Created
          July 1, 2016 03:26 
        
      - 
      
- 
        Save elquimista/677af350749de3dd631596494ba8a01d to your computer and use it in GitHub Desktop. 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | SVGAnimatedTransformList.prototype.translate = function (x, y) { | |
| var xForms = this.baseVal, | |
| xFormTranslate = undefined, | |
| transform = undefined; | |
| for (var i = 0, n = xForms.numberOfItems; i < n; i ++) { | |
| transform = xForms.getItem(i); | |
| if (transform.type === SVGTransform.SVG_TRANSFORM_TRANSLATE) { | |
| xFormTranslate = transform; | |
| break; | |
| } | |
| if (transform.type === SVGTransform.SVG_TRANSFORM_MATRIX) { | |
| xFormTranslate = transform; | |
| break; | |
| } | |
| } | |
| if (xFormTranslate) { | |
| if (x) { | |
| xFormTranslate.matrix.e = x; | |
| } | |
| if (y) { | |
| xFormTranslate.matrix.f = y; | |
| } | |
| } | |
| }; | |
| var RAPPID = function() { | |
| var $ = window.jQuery, | |
| graph, paper, paperScroller, snaplines, stencil, nav, inspector, halo, gOptions, | |
| shapeSize = [50, 50], | |
| shapeMargin = [20, 10], | |
| shapeTextMarginTop = 5, | |
| iconSize = [32, 32], | |
| shapeBigSize = [150, 150], | |
| zoomMax = 1, | |
| zoomMin = 0.4, | |
| zoomStep = 0.2, | |
| defaultPaperSize = [$('#paper').width() || 1500, $('#paper').height() || 900], | |
| wfAutoSaveInterval = 1000, // in milliseconds | |
| chartPieRadius = 60, | |
| chartSerieFillColor = ['#8bce5d', '#53abdd', '#c377b1', '#ffe891', '#888888', '#53abdd', '#c377b1', '#ffe891', '#888888'], | |
| logTimerId, | |
| chart = new joint.shapes.chart.Pie({ | |
| attrs: { | |
| '.slice-inner-label': { fill: '#000' } | |
| }, | |
| position: { x: 0, y: 0 }, | |
| size: { width: chartPieRadius * 2, height: chartPieRadius * 2 }, | |
| serieDefaults: { | |
| degree: 360, | |
| startAngle: 0, | |
| showLegend: false | |
| }, | |
| sliceDefaults: { | |
| innerLabel: '{label}' | |
| }, | |
| series: [] | |
| }), | |
| $statusBarEl = $('#status_bar'), | |
| configErrors = {}, | |
| linkDownFlag = false, | |
| graphHasChanged = false, | |
| agentDownFlag = false, | |
| $goalMarkerEl = V('<path d="M 0.000 10.000 L 11.756 16.180 L 9.511 3.090 L 19.021 -6.180 L 5.878 -8.090 L 0.000 -20.000 L -5.878 -8.090 L -19.021 -6.180 L -9.511 3.090 L -11.756 16.180 L 0.000 10.000" fill="#f8b600" stroke="#f8b600" transform="translate(75 145)"></path>').node, | |
| // Used for showing sticky config option icons for agents that are not configured yet. | |
| halo2 = {}, | |
| configIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QA/wD/AP+gvaeTAAAAB3RJTUUH3wwECAsV5RQSlAAABn1JREFUWMOtl12MZUURx3//6j73zr0zu7ODIrssJLODDBDN7vIAGDWyxtEEUF/A+GDCI348GEWfwIAG0PiAJMSgr5po4osakjVEwK9EDPjAh9Gwuw4fsrgoCO7szNyPc06VD/fe2Zk7d1ggdtLpU3266l9dXdXVpaWlIwaIYTNgFeJQyBbBuqI8EopusHcarhN8AjgcsB+YHvKuCU4BzwQ8vA5HL0MnfynXOhQnwf+k8N0gZ0sLLS0dSSMFhuBcFbK9EB8PlatwRQu+IrjJI84DQpIMkAZ6RwQ+GAOQSSvAgx24993oqV/J8ylIjyvqNhCbFEgLC/MGyIA14NpQeiRR3lhTzEj3NODHEXGVpFY7Z99TFDFXFJprFNpTFMwO+0xKMZWSS6KMmPKIgw3plj7sm4Xff6mT118sojghothkgrSwMG8GWgWWQuluV+99wcJ50kPATUDMFoVf0GxqriisnbMVkpKEJGzYCzO1crZdOWsm55BU99wBrm6hG18o4g/Xh/3zDVE8K6I5tER678K8dUBHQukut95j4nAT/cYjLm2alfumptJco5GSJB8yjTrSoI/NZ0kzOVs7JfXc69L9/Cx97jXx2CdDz70qiuMiGoBVwKGQ3V2m3h8VlxRw1CP2TudcXdxuFa2UVA/PeNQ2PLaqoCoh4uwc4EAdwZSZLm618q6iqD1id4YH/yauvLO23tWh1AdsP/CUwn+W6mYDfuIRF07nXF04NZWF8M2Aw+9wR4DNzmJ75pAZUdfb1o2U3tdspqESsxl++qj53L25LhcD5cOh9H23/jHFNwOuaZiVe5vNYmRWbRo3t/Ztt1EcOkS4Uy8vs3bnnURVIWnjKEa8AHubzVS5V133y3ej76z1iy/cb57tVrf+XxSXA7cCXNBs5jwUogmCwh212+TLLkOtFpqeJi8uot27oa43fGLSBt7TbGYNyM8/rbjmq259e0FBA77oEa1dOVftnFTvAP52msZkODCVErNF4R5Bhi+/LrCTcD5wk0nsKYoUsVXIOLjMiPV1qmPHiG4X1tepTpwgVlYgpS0OGWOjRzBbZEsDK93wPHFJbsKSR1zYzsmnzMzHmMaVGQlf+/Y9qNUeEN0OUftAuZ0UH841ZGqn5GeqaraQbjDBxwDaKcfoatUE5slGnqxtjK3arJAE7ZxH/5YycCUSTTPF0P4xAWY8EqZvv53i0CFwp1peZu2OO7ZEwTjvhnIBTTMN1x20gIuMwe210x63CBhFweIimpqCdpt86aXbomAS74hOw2QG7DNglwCTFOcA37KNqhr8cyeqajD3Jrybd2cDPICGvdnp7iRgcw44S7+5H+zUDDgTgEeE3oGAiQY6x2Z8gAfQN8FJB6o4a8O3fBQT7XZuS9YRMQz3UwY8SQQ9921h+NbBt6/aiVeCntcRgwvrGQt4FGC9riaG4Tu9hne0ZMB6VY/+P2I9eMSkl7u1W9c9bBPD/8sPRrSAfnis17WZdLqEo3YRvAr83CP4b1nWmoC0bSpiS9gN6J3BR/wmcbqsvB7wHj2Alm0+RA8eMKlzpqryWlVHYvvNt0WoBDkPn9KGct4almPgwSDcunXN6bI0k6jg/vMC7D7zxkH0LPA9gH/3elVF7JiOt2TDTodYW9uWDcfBR+O/er0qBuQPD6LH7zNv6OalI+mY4GuVinnpdx5xzehJxgQlRk8yzLCZGZCI1dVBHkhp6zrOJqNTvV59piyTSc+uEB9catSnbynN0rsW5u1wKH29Tr0XLH6bpc/03Wd77tVMTmZoQigNX8KdDtHtANpIxZvbyKFf6XXrM2WVTFop4VPXhj2/Gmr8Vbhl4GmFfyPXzQ+Flku4zqRX1qoqv7TeKTt1HUli8529AZQz5GJghTHgJNF1j5c6nWoEXsGnrwie/JZ58wlFXQDpwMK8NUDHRbwoipvdXn5O/KKQPlLD/pWq8tLdCzMVkkzaMOvI1OJsghHQd4/Xy7J+tdejisgmHe/DdYvBEw9YNH89LNGcYWUUoCZwTMSyKO7K8Z8POz+aQQ3BB7p1XZypKnXcvYrwAMUAixgK6rvHalX562XJa/2+derahkf1gzeIz360l/7x3cKbjyrq1maf2qk43Q+xFCpX4PIW3Cq48e0Wp124d0566iE8nwJ7XOHjxakmledrwPsDLSI7gMqFIN6AC9pwvZ2jPHd4uANH23Dy7xY6FRQvgv9ZEbuA8fL8f40EPnOmwLnoAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTEyLTA0VDA4OjExOjIxLTA1OjAwhYihSgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNS0xMi0wNFQwODoxMToyMS0wNTowMPTVGfYAAAAASUVORK5CYII=', | |
| configIconGreen = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAAEEfUpiAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAjJSURBVHjaAEQAu/8BRERAAh0SBP+8Phz9VbzkCAD/QUMAL6Zy//3//v8vpnL/AhxRG/YAAAAA/QD/AAAAAAACb7PjEAAAAADsAPgAAAAAAAAAAP//YnZzcWD+WWi/jNdTX8T8t+AFRq2Fuf+YmZkZmZmZGd68efOfiZWVlZEBCoSFhRmZPnz48JuJiYnh////DG/evGEAAAAA//9idHNxYL7qJ6fLx8d3jo2NDa7648ePfy6sus/KKDM5fo6wsHAyTIKVlZXh9+/fDAwMDAyMjIwMTAwMDHthkv/+/WM4FtIG4zL8//+fgZExw5r53w2Ov7LBMn9ERESY//+HeOjt27cMaRsecQAAAAD//2J0cXFgVv3PyLjeR0qEhYXlFgMDw4vT65+oBTL9ZeJhYGBkrHZ2ZJ/vJ/NDVFQUbjQjIyPD69evPylteiTMtDBA7j1McnVkLQMPDw/D////GURERPju+ckZM6rNzfzDycnJjOxQJiYmBgYGBobXr18zMLGzs8Mll0ZWM/Dx8cGtYmZmZmD68uXLP5jL0cHfv38ZmH7//t3OyMjI8P//f4bN/+8yfP36Fa7g1sZnjMw/xLkPMQty+bKxsUlcu3aN8f///wzfv3//8+HDB8P9tz+8BbBN9SoNg1H0nO+LNkmloTV1UVwEF8HBjkUoWHVzEEQ61ElEH8KXcBIXFxGdCoq+gPQJFEEEl1YRO5QaCMGQ+7k01VrXezncc88Pq9WKVgBLhvpkzaftOAFJy3XdJOWXJImJoshEUaQAHL9evB8sZ2PLBsB6taJvViYtJ5uNfN8f4WnbNsIwHHwOAEEQJHEcP7euXxY4fbRTVEp9FAqFEfDu5jZqmUWsXh5CRIY8NsaYbrf7qUg+eJ43IpOIYD0zjzwycF0XJIf2SimS9BSAtoj8q/MXZNCG9HIahYGpd41WqdfrqXT42zPpg0WkH80fFmEYJgDOyb2ylicnmd2aebMsq5jL5ay/Zmuth5h1Oh0AWKpdtR/J/bIGwLHIYCOZYLM0NUeyCSBPkmn/RARa67PbRqt+Chm/pxED4JuPqueJKgqiZ+69cEWLx1NJjLJqxNhZGgolENzExPiBSKGFRgsSbQwVv8CvyhhMjLHzD0As1JioQQsRLGykIUqMLCGEXdlkF967zzd3bHib3RWY5jYzc8+cOXMon+/TALAOyPHdLeZGiZOhi503lVKjAI6JyDqAt2majgx8XVlsW/6rZ0lkYydC+XyfiQCsKeKVc7mHAEattd5aS8YYAoA4jjmKIg3AO+fC22+W3RQJCyDUk+8zn1inBy/nlpRSe8IwbNlM/CICZpZyuUwAeodfLkx/JkmVAMgNdn4xxuxtb2+vFXvvYa2tMU9E0FrThlo/Pj27b+dhAan587mjItIdBIFplvDU4D28u3IXzNyw/zAMYa39M+Z1apRS74MgEBFpkFocx1iFw2s/33AH2aEDwJGB/V10YOy6dHR0oHnubITMBJsjiiIfRdErlZnBZlc4PfQAk1fv10aoD2utEpEzWzao/QT+7xbq+Gg1zRrfLurzmFkA/FZZg+1QbMGBAHikiOhJpVJJm1HUG8hm8OM4VjMThTE1O1G445wzWUL2JkmCVTh8SH9BKdUAv1wup0T07AX5Vuq+1t9aONGZA/Cj2RO99yCihuJqtcrOubWF8ULQr1mrmV3On55cLDBzV6lUQrVaTetsq4G0YrHISZL8/Da+EJzSbDQAolsnDQD0VHaox0uSXLiUe+69H66H7b0XIqowc++hueJ3PRejbYOaf5RWTWhcVRT+zrnvP4lhTEDND2pclKi0IohgFEwNWgptJUZsVrooNbta6aZ0IQW3WVgL6qqrCiJto1Ywlvq3ERGxVAQVahfO1NZqyCTzyJt33z3HRWamMZ0k413eyz333POd831fkw8IABhADcBjSrzQ7+mhm87u2TswysyvMfOUiNwJQAG0iKZZVBGBiGiDbJcAfGytnf3i/I1Lp7rhSSrmO1KXNAJgbQIMUA3AhJI5LlQffH5whIg+JKJHAbgwDDWOY2OMoc1apnnWEDKXZRmpqiGi31T1xUvnKpffYQnnSV0XAAGUdk48bR5UMm9bkw9NDTzAzN845wbCMCzW83M76VHV27rklj+hlhBmWWaYuaqq4+WzlR+PGAl/IC1o9pnx4IBw/tDk0JsAjhGRLZVK/mbTJSI4ODWN6XA7HBTncRUnPzgF59ymU7m4uFgUReER0Xu/ni3PnGAJeFIpf/iF4bdU9VgYhkVfX9+Wj0dR1BLdfkTYhxEkSdJq+40GsFQqeUmSOBF5ddvk0OmXlXMaPvnKtHPu/SAIpLe3lzuhgabL8n0fAFAUxapX4o6uY3l5WbIsY2PMIQ/AEWZGFEX/i4tmJvdjf7gdOQQXiquYPdMegnZkGccx1et1qOrrLCKjDQfc8e+DIMBYOII7EKCEEDu9+xDHcVsI2sFpjKFGte5lAMsN46DrMdtoMTMYWz+0Uaw1+zkz8ycAYK2VTjHcajXsY9ukiAh5nkujWvPsnDtKRJU0TU2e59qpuG0lfBvFcc5pmqYMoOqcO8yVuWs3RWSCiFaq1So1k9gKigCr1TIgxDAtFlwva+uN5sLCQvPsud/nrl2h4QPjppbWQTsG/KSr6ysReTyKoqKnp8fbrBGJCHEcN8X1tglYX4FareZWVlYMM/9SFMUT1+f/qB60zEQzY4ZzoZeWEnP6H9SHJ4d2APhMRO72PM92d3d7QRDQ2h9thO/afSKCtVbTNHV5nnvMvKSqe386V/76BGt4kdTFgLbsNQD4mWJfGpuL9ZWcnxwK4yQ5DuCwiPhEBN/3xfd99TyPjTG0VoBERIuikDzPyVrLDY0QVX3XWnv0+pm/lt6IXPglqYtuKaISzYxxM4Hm8uqCUYnpfvL529Fe+/n837przz13eZ63G8CzAB4BMAigq3E3JaI/AVxW1Qsi8uncR5Xy7l39NFxe9p/6OZPvSbVnVQH/U7R/BwC/DDNb2ALc6QAAAABJRU5ErkJggg==', | |
| // Customized Halo - Halo2 | |
| Halo2 = function(options) { | |
| // possible options: { cellView } | |
| this.options = options; | |
| this.$el = undefined; | |
| } | |
| ; | |
| Halo2.prototype = { | |
| _options: { | |
| tinyThreshold: 40, | |
| smallThreshold: 80 | |
| }, | |
| render: function() { | |
| var cellView = this.options.cellView, | |
| $cell = cellView.$el, | |
| cellPos = $cell.offset(), | |
| paperPos = $('#paper .paper').offset(), | |
| $haloEl = $('<div class="halo surrounding halo2"></div>'), | |
| cellSize = cellView.model.attributes.size, | |
| width = cellSize.width * paperScroller._sx, | |
| height = cellSize.height * paperScroller._sy, | |
| _options = this._options, | |
| $handleEl = $('<div class="handle config"></div>'); | |
| $haloEl.css('width', width + 'px') | |
| .css('height', height + 'px') | |
| .css('left', (cellPos.left - paperPos.left) + 'px') | |
| .css('top', (cellPos.top - paperPos.top) + 'px') | |
| .attr('data-model-id', cellView.model.id) | |
| .toggleClass('tiny', width < _options.tinyThreshold && height < _options.tinyThreshold) | |
| .toggleClass('small', !$haloEl.hasClass('tiny') && width < _options.smallThreshold && height < _options.smallThreshold); | |
| $handleEl.css('background-image', 'url("' + configIcon + '")') | |
| .appendTo($haloEl); | |
| $haloEl.appendTo(cellView.paper.$el); | |
| this.$el = $haloEl; | |
| }, | |
| remove: function() { | |
| if (this.$el) { | |
| this.$el.remove(); | |
| this.$el = undefined; | |
| } | |
| }, | |
| update: function() { | |
| try { | |
| var cellView = this.options.cellView, | |
| $cell = cellView.$el, | |
| cellPos = $cell.offset(), | |
| paperPos = $('#paper .paper').offset(), | |
| cellSize = cellView.model.attributes.size, | |
| width = cellSize.width * paperScroller._sx, | |
| height = cellSize.height * paperScroller._sy, | |
| _options = this._options, | |
| $el = this.$el; | |
| $el.css('width', width + 'px') | |
| .css('height', height + 'px') | |
| .css('left', (cellPos.left - paperPos.left) + 'px') | |
| .css('top', (cellPos.top - paperPos.top) + 'px') | |
| .toggleClass('tiny', width < _options.tinyThreshold && height < _options.tinyThreshold) | |
| .toggleClass('small', !$el.hasClass('tiny') && width < _options.smallThreshold && height < _options.smallThreshold); | |
| } catch (error) { | |
| console.log(error); | |
| } | |
| } | |
| }; | |
| /** | |
| * getWordWrapText() | |
| * | |
| * @param String text | |
| * @param Object options | |
| */ | |
| function getWordWrapText(text, options) { | |
| var lines = joint.util.breakText(text, options).split("\n"), | |
| textContent = ''; | |
| for (var i = 0, n = lines.length; i < n; i ++) { | |
| textContent += '<tspan dy="' + (i > 0 ? 1 : 0) + 'em" x="0" class="v-line">' + lines[i] + '</tspan>'; | |
| } | |
| return textContent; | |
| } | |
| /** | |
| * wrapText(): Wrap texts in SVG using joint.util.breakText | |
| * | |
| * @param Array size | |
| * @param Bool isOnPaper | |
| */ | |
| function wrapText(size, isOnPaper) { | |
| var xForms, xFormTranslate; | |
| if (isOnPaper) { | |
| // Yes, it's on the paper | |
| $('.wrap').each(function () { | |
| var $this = $(this), | |
| klass = $this.attr('class'), | |
| model = graph.getCell( $this.parents('[model-id]').attr('model-id') ), | |
| modelText = model && model.attributes.textRaw; | |
| if (!model) return; | |
| model.attributes.attrs.text.text = modelText; | |
| $this.html(getWordWrapText(modelText, { width: size[0] })) | |
| .attr('fill', '#000') | |
| .attr('font-size', '14'); | |
| this.transform.translate(null, size[1] / 2); | |
| $this.attr('class', klass.replace(/\bwrap\b/, '')); | |
| }); | |
| } else { | |
| // No, it's not on the paper. Then it must be on the STENCIL. No doubt!! | |
| $('.wrap').each(function () { | |
| var $this = $(this), | |
| klass = $this.attr('class'); | |
| this.transform.translate(null, size[1] + shapeTextMarginTop); | |
| $this.attr('class', klass.replace(/\bwrap\b/, '')); | |
| }); | |
| } | |
| } | |
| /** | |
| * logStatus() | |
| * | |
| * @param Any data | |
| * @param Number duration milliseconds | |
| */ | |
| function logStatus(data, duration) { | |
| clearTimeout(logTimerId); | |
| $statusBarEl.html(data); | |
| if (duration) { | |
| logTimerId = setTimeout(function () { $statusBarEl.html(''); }, duration); | |
| } | |
| } | |
| /** | |
| * saveGraphAsync() | |
| * | |
| */ | |
| function saveGraphAsync() { | |
| var workflow_draft = graph.toJSON(); | |
| workflow_draft.options = { | |
| paperWidth: defaultPaperSize[0], | |
| paperHeight: defaultPaperSize[1], | |
| paperOrigin: {x: 0, y: 0} | |
| }; | |
| if (paper && paperScroller) { | |
| workflow_draft.options = { | |
| paperWidth: paper.options.width / paperScroller._sx, | |
| paperHeight: paper.options.height / paperScroller._sy, | |
| paperOrigin: { | |
| x: paper.options.origin.x / paperScroller._sx, | |
| y: paper.options.origin.y / paperScroller._sy | |
| } | |
| } | |
| } | |
| return $.ajax({ | |
| url: gOptions.save_to, | |
| type: 'post', | |
| dataType: 'json', | |
| data: { | |
| id: gOptions.workflow_id, | |
| workflow_draft: JSON.stringify(workflow_draft) | |
| } | |
| }); | |
| } | |
| /** | |
| * saveWorkflow() | |
| * | |
| * @param Function doneCallback | |
| */ | |
| function saveWorkflow(doneCallback) { | |
| logStatus('<div class="alert alert-info">Saving...</div>'); | |
| saveGraphAsync().then(function(data) { | |
| configErrors = data.errors; | |
| if (data.isValid) { | |
| logStatus('<div class="alert alert-success">The workflow has been saved!</div>', 5000); | |
| } else { | |
| logStatus('<div class="alert alert-warning">The workflow has been saved, BUT we have invalid config.</div>'); | |
| } | |
| if (doneCallback) { | |
| doneCallback(data); | |
| } | |
| }, function(jqXHR, textStatus, errorThrown) { | |
| logStatus('<div class="alert alert-danger">Uh oh, seems we lost connection. The workflow could not be saved.</div>'); | |
| }); | |
| } | |
| /** | |
| * cronSaveWorkflow() | |
| */ | |
| function cronSaveWorkflow() { | |
| if (graphHasChanged) { | |
| saveWorkflow(); | |
| graphHasChanged = false; | |
| } | |
| } | |
| /** | |
| * isAgent() | |
| * | |
| * @param joint.dia.ElementView|joint.dia.Element cell | |
| * @return Bool | |
| */ | |
| function isAgent(cell) { | |
| if (cell.model) { | |
| return (cell.model.attributes.config != undefined); | |
| } else { | |
| return (cell.attributes.config != undefined); | |
| } | |
| } | |
| /** | |
| * validateConnection() | |
| * | |
| * @param joint.dia.ElementView cellViewS, | |
| * @param magnetS | |
| * @param joint.dia.ElementView cellViewT, | |
| * @param magnetT | |
| * @param String end | |
| * @param joint.dia.LinkView linkView | |
| */ | |
| function validateConnection(cellViewS, magnetS, cellViewT, magnetT, end, linkView) { | |
| if (isAgent(cellViewT) && cellViewS.model.id != cellViewT.model.id && | |
| cellViewT.model.attributes.cannot_receive_events === false) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| /** | |
| * initializePaper(): Create a graph, paper and wrap the paper in a PaperScroller. | |
| */ | |
| function initializePaper() { | |
| var workflow_draft = gOptions.workflow_draft, | |
| wfdOptions = workflow_draft.options, | |
| $paperContainer = $('#paper'); | |
| graph = new joint.dia.Graph; | |
| paper = new joint.dia.Paper({ | |
| width: defaultPaperSize[0], | |
| height: defaultPaperSize[1], | |
| gridSize: 10, | |
| model: graph, | |
| async: { batchSize: 1 }, | |
| defaultLink: new joint.dia.Link({ | |
| attrs: { | |
| '.connection': { stroke: '#8d8d94', 'stroke-width': 3 }, | |
| '.marker-target': { stroke: '#8d8d94', fill: '#272634', d: 'M5.5,15.499,15.8,21.447,15.8,9.552z' }, | |
| '.marker-source': { stroke: '#8d8d94', fill: '#272634' } | |
| } | |
| }), | |
| linkConnectionPoint: joint.util.shapePerimeterConnectionPoint, | |
| validateConnection: validateConnection | |
| }); | |
| paperScroller = new joint.ui.PaperScroller({ | |
| paper: paper, | |
| autoResizePaper: true, | |
| padding: 50, | |
| baseWidth: 200, | |
| baseHeight: 200 | |
| }); | |
| $paperContainer.append(paperScroller.$el); | |
| paper.on('render:done', function() { | |
| var cells = graph.getElements(), | |
| cellView, attributes, | |
| agentsConfigByType = gOptions.agentsConfigByType, | |
| updatedAttrs; | |
| if (wfdOptions) { | |
| if (wfdOptions.paperOrigin) { | |
| paper.setOrigin(workflow_draft.options.paperOrigin.x, workflow_draft.options.paperOrigin.y); | |
| nav.updatePaper(paper.options.width, paper.options.height); | |
| } | |
| if (wfdOptions.paperWidth && wfdOptions.paperHeight) { | |
| paper.setDimensions(wfdOptions.paperWidth, wfdOptions.paperHeight); | |
| } | |
| } | |
| wrapText(shapeBigSize, true); | |
| for (var i = 0, n = cells.length; i < n; i ++) { | |
| if (!isAgent(cells[i])) continue; | |
| attributes = cells[i].attributes; | |
| cellView = paper.findViewByModel(cells[i]); | |
| checkAgentIfConfiguredAndDoIt(cellView); | |
| initAgentSubtitle(cellView); | |
| if (attributes.is_goal) { | |
| showGoalMarker(cellView); | |
| } | |
| updatedAttrs = agentsConfigByType[attributes.config.type] && agentsConfigByType[attributes.config.type].attrs; | |
| if (updatedAttrs) { | |
| attributes.config = agentsConfigByType[attributes.config.type].config; | |
| if (updatedAttrs.rect) { | |
| cells[i].attr('rect/fill', updatedAttrs.rect.fill); | |
| cells[i].attr('rect/stroke', updatedAttrs.rect.stroke); | |
| } else if (updatedAttrs.circle) { | |
| cells[i].attr('circle/fill', updatedAttrs.circle.fill); | |
| cells[i].attr('circle/stroke', updatedAttrs.circle.stroke); | |
| } else if (updatedAttrs.path) { | |
| cells[i].attr('path/fill', updatedAttrs.path.fill); | |
| cells[i].attr('path/stroke', updatedAttrs.path.stroke); | |
| } | |
| cells[i].attr('image/xlink:href', updatedAttrs.image['xlink:href']); | |
| } | |
| } | |
| if (!gOptions.wf_valid) { | |
| logStatus('<div class="alert alert-warning">Some agents have invalid configuration.</div>'); | |
| } | |
| configErrors = gOptions.wf_errors; | |
| paperScroller.zoomToFit({ | |
| padding: 100, | |
| maxScaleX: 1, | |
| maxScaleY: 1 | |
| }); | |
| setInterval(cronSaveWorkflow, wfAutoSaveInterval); | |
| }); | |
| paper.on('cell:pointerdown', function(cellView) { | |
| if (isAgent(cellView)) { | |
| agentDownFlag = true; | |
| } | |
| }); | |
| paper.on('cell:pointerup', function() { | |
| agentDownFlag = false; | |
| }); | |
| paper.on('blank:pointerdown', paperScroller.startPanning); | |
| $paperContainer.on('contextmenu', function(e) { e.preventDefault(); }); | |
| snaplines = new joint.ui.Snaplines({ paper: paper }); | |
| snaplines.startListening(); | |
| graph.on('add', function(cell) { | |
| if (isAgent(cell)) { | |
| var $image = $('image', '[model-id=' + cell.id + ']'), | |
| image = cell.attr('image'), | |
| newX = (shapeBigSize[0] - iconSize[0]) / 2, | |
| newY = shapeBigSize[1] / 2 - iconSize[1] - 10; | |
| cell.set('size', { width: shapeBigSize[0], height: shapeBigSize[1] }); | |
| $image.attr('x', newX).attr('y', newY); | |
| image.x = newX; | |
| image.y = newY; | |
| wrapText(shapeBigSize, true); | |
| initializeDefaultConfigValues(cell); | |
| } | |
| }); | |
| if (workflow_draft.cells && workflow_draft.cells.length > 0) { | |
| graph.fromJSON(workflow_draft); | |
| } else { | |
| setInterval(cronSaveWorkflow, wfAutoSaveInterval); | |
| } | |
| graph.on('change', function(cell) { | |
| if (cell.id != chart.id && linkDownFlag == false) { | |
| graphHasChanged = true; | |
| } | |
| }); | |
| graph.on('remove', function(cell) { | |
| if (cell instanceof joint.dia.Link && cell.get('target').id) { | |
| var link = cell, | |
| source = graph.getCell(link.get('source').id), | |
| sourceAttr = source.attributes, | |
| groupKey = link.attributes.groupKey; | |
| if (groupKey) { | |
| sourceAttr.targetIds[groupKey] = _.without(sourceAttr.targetIds[groupKey], link.get('target').id); | |
| } else { | |
| sourceAttr.targetIds = _.without(sourceAttr.targetIds, link.get('target').id); | |
| } | |
| } | |
| if (cell.id != chart.id && linkDownFlag == false) { | |
| graphHasChanged = true; | |
| } | |
| }); | |
| paper.on('scale resize', function() { | |
| for (var modelId in halo2) { | |
| halo2[modelId].update(); | |
| } | |
| }); | |
| } | |
| /** | |
| * createCustomShapes(): Create custom elements. | |
| */ | |
| function createCustomShapes() { | |
| joint.shapes.custom = {}; | |
| joint.shapes.custom.CircleEx = joint.shapes.basic.Circle.extend({ | |
| markup: '<g class="scalable"><circle/></g><image/><text/>', | |
| defaults: joint.util.deepSupplement({ | |
| type: 'custom.CircleEx' | |
| }, joint.shapes.basic.Circle.prototype.defaults) | |
| }); | |
| joint.shapes.custom.RectEx = joint.shapes.basic.Rect.extend({ | |
| markup: '<g class="scalable"><rect/></g><image/><text/>', | |
| defaults: joint.util.deepSupplement({ | |
| type: 'custom.RectEx' | |
| }, joint.shapes.basic.Rect.prototype.defaults) | |
| }); | |
| joint.shapes.custom.PathEx = joint.shapes.basic.Path.extend({ | |
| markup: '<g class="scalable"><path/></g><image/><text/>', | |
| defaults: joint.util.deepSupplement({ | |
| type: 'custom.PathEx' | |
| }, joint.shapes.basic.Path.prototype.defaults) | |
| }); | |
| } | |
| /** | |
| * initializeStencil(): Create and populate stencil. | |
| * | |
| * @param Object stencilData | |
| */ | |
| function initializeStencil(stencilData) { | |
| stencil = new joint.ui.Stencil({ | |
| paper: paperScroller, | |
| width: (shapeSize[0] + shapeMargin[0]) * 3, | |
| groups: stencilData.groups, | |
| dropAnimation: { duration: 200, easing: 'swing' } | |
| }); | |
| $('#stencil').append(stencil.render().el) | |
| .find('.content').mCustomScrollbar({ theme: 'minimal-dark' }); | |
| stencil.$el.on('contextmenu', function(e) { e.preventDefault(); }); | |
| $('.stencil-paper-drag').on('contextmenu', function(e) { e.preventDefault(); }); | |
| var layoutOptions = { | |
| columns: 3, | |
| columnWidth: shapeSize[0] + shapeMargin[0], | |
| rowHeight: shapeSize[1] * 2 + shapeTextMarginTop | |
| }, | |
| shapes = stencilData.shapes; | |
| _.each(stencilData.groups, function(group, name) { | |
| stencil.load(shapes[name], name); | |
| joint.layout.GridLayout.layout(stencil.getGraph(name), layoutOptions); | |
| stencil.getPaper(name).fitToContent(1, 1, 30); | |
| }); | |
| wrapText(shapeSize); | |
| } | |
| /** | |
| * initializeHaloAndInspector() | |
| */ | |
| function initializeHaloAndInspector() { | |
| paper.on('cell:mouseover', function(cellView) { | |
| if (linkDownFlag || agentDownFlag) return; | |
| // We don't want a Halo for links. | |
| if (cellView.model instanceof joint.dia.Link || !isAgent(cellView)) return; | |
| var model = cellView.model, | |
| modelId = model.id, | |
| attributes = model.attributes, | |
| configHandleOptions; | |
| showAgentSubtitle(cellView, false); | |
| if (halo && halo.options.cellView === cellView) return; | |
| // Removes the sticky halo | |
| if (halo2[modelId]) { | |
| halo2[modelId].remove(); | |
| delete halo2[modelId]; | |
| } | |
| halo = new joint.ui.Halo({ cellView: cellView }); | |
| halo.removeHandle('clone'); | |
| halo.removeHandle('resize'); | |
| halo.removeHandle('rotate'); | |
| halo.removeHandle('fork'); | |
| if (attributes.cannot_create_events) { | |
| halo.removeHandle('link'); | |
| } | |
| configHandleOptions = { | |
| name: 'config', | |
| position: 'n' | |
| }; | |
| if (isAgentConfigured(cellView)) { | |
| configHandleOptions.icon = configIconGreen; | |
| } else { | |
| configHandleOptions.icon = configIcon; | |
| configHandleOptions.attrs = { | |
| '.config': { | |
| 'data-toggle': 'tooltip', | |
| 'data-placement': 'top', | |
| 'title': configErrors[modelId] ? configErrors[modelId].join('\n') : 'Invalid config' | |
| } | |
| }; | |
| } | |
| halo.addHandle(configHandleOptions); | |
| halo.render(); | |
| $('.handle.config[data-toggle="tooltip"]').tooltip(); | |
| halo.on('action:link:add', function(link) { | |
| var sourceId = link.get('source').id, | |
| targetId = link.get('target').id, | |
| source = graph.getCell(sourceId), | |
| sourceAttr = source.attributes, | |
| sourceType = sourceAttr.config.type, | |
| activeSliceIndex = chart.prop('active-slice'); | |
| linkDownFlag = false; | |
| chart.remove(); | |
| if ( !sourceId || !targetId || | |
| (sourceType == 'Split' && activeSliceIndex === undefined) || | |
| (sourceType == 'Balance' && activeSliceIndex === undefined) || | |
| (sourceType == 'Send Email' && activeSliceIndex === undefined) || | |
| (sourceType == 'Twitter Status' && activeSliceIndex === undefined)) { | |
| link.remove(); | |
| } else { | |
| if (sourceType == 'Split' || sourceType == 'Balance' || sourceType == 'Send Email' || | |
| sourceType == 'Twitter Status' || sourceType == 'Twitter Message') { | |
| var chartData = chart.get('series')[0].data[activeSliceIndex], | |
| groupKey = chartData.groupKey; | |
| link.label(0, { position: 0.5, attrs: { text: { text: chartData.label } } }); | |
| link.attributes.groupKey = groupKey; | |
| if (!sourceAttr.targetIds) { | |
| sourceAttr.targetIds = {}; | |
| } | |
| if (!sourceAttr.targetIds[groupKey]) { | |
| sourceAttr.targetIds[groupKey] = []; | |
| } | |
| sourceAttr.targetIds[groupKey].push(targetId); | |
| } | |
| else { | |
| if (!sourceAttr.targetIds) { | |
| sourceAttr.targetIds = []; | |
| } | |
| sourceAttr.targetIds.push(targetId); | |
| } | |
| graph.trigger('change', link); | |
| } | |
| chart.prop('active-slice', undefined); | |
| if (halo2[sourceId] === undefined) { | |
| halo && (halo.remove(), halo = undefined); | |
| checkAgentIfConfiguredAndDoIt(paper.findViewByModel(source)); | |
| } | |
| if (targetId) { | |
| paper.trigger('cell:mouseover', paper.findViewByModel(graph.getCell(targetId))); | |
| } | |
| }); | |
| halo.on('action:config:pointerdown', function(e) { | |
| e.stopPropagation(); | |
| if (model instanceof joint.dia.Link) return; | |
| createInspector(cellView); | |
| }); | |
| halo.on('action:link:pointerdown', function(e) { | |
| var bbox = model.getBBox(), | |
| pieValue, chartView, $chartViewDataEl; | |
| linkDownFlag = true; | |
| // Display pie chart for Split and Balance agents. | |
| if (attributes.config.type === 'Split') { | |
| var criteria = attributes.criteriaUI, | |
| serieData = []; | |
| if (criteria && criteria.length > 0) { | |
| chart.prop('position', { x: bbox.x + bbox.width - chartPieRadius, y: bbox.y + bbox.height / 2 - chartPieRadius }); | |
| for (var i = 0, n = criteria.length, v = parseFloat((100 / n).toFixed(2)); i < n; i ++) { | |
| serieData.push({ | |
| value: v, | |
| label: criteria[i].weight_label + ' (' + criteria[i].weight + ')', | |
| fill: chartSerieFillColor[i], | |
| groupKey: criteria[i].weight_label.toString() | |
| }); | |
| } | |
| chart.prop('series', [{ data: serieData }]); | |
| chart.prop('active-slice', undefined); | |
| graph.addCell(chart); | |
| chart.toFront(); | |
| chartView = paper.findViewByModel(chart); | |
| $chartViewDataEl = chartView.$('.data'); | |
| chartView.$('.slice-inner-label').each(function () { | |
| var $textEl = $(this); | |
| $textEl.attr('data-slice', $textEl.parents('.slice').attr('data-slice')); | |
| $textEl.appendTo($chartViewDataEl); | |
| }); | |
| chartView.on('mouseover', function(slice, e) { | |
| var $slice = $('.slice[data-serie="' + slice.serieIndex + '"][data-slice="' + slice.sliceIndex + '"]', $chartViewDataEl), | |
| elSlice = V($slice[0]); | |
| // _.each(this.$('.slice'), function(slice) { V(slice).scale(1); $('.slice-inner-label', $(slice)).css('display', 'none'); }); | |
| _.each($('.slice', $chartViewDataEl), function(slice) { V(slice).scale(1); }); | |
| $('.slice-inner-label', $chartViewDataEl).css('display', 'none'); | |
| elSlice.scale(1.2); | |
| chart.prop('active-slice', slice.sliceIndex); | |
| // $('.slice-inner-label', $slice).css('display', 'block'); | |
| $('.slice-inner-label[data-slice="' + slice.sliceIndex + '"]', $chartViewDataEl).css('display', 'block'); | |
| }); | |
| } | |
| } | |
| else if (attributes.config.type === 'Balance') { | |
| chart.prop('position', { x: bbox.x + bbox.width - chartPieRadius, y: bbox.y + bbox.height / 2 - chartPieRadius }); | |
| chart.prop('series', [{ data: [ | |
| { value: 50, label: '50', fill: chartSerieFillColor[0], groupKey: '50' }, | |
| { value: 50, label: '50', fill: chartSerieFillColor[1], groupKey: '50' } | |
| ] }]); | |
| chart.prop('active-slice', undefined); | |
| graph.addCell(chart); | |
| chart.toFront(); | |
| chartView = paper.findViewByModel(chart); | |
| $chartViewDataEl = chartView.$('.data'); | |
| chartView.$('.slice-inner-label').each(function () { | |
| var $textEl = $(this); | |
| $textEl.attr('data-slice', $textEl.parents('.slice').attr('data-slice')); | |
| $textEl.appendTo($chartViewDataEl); | |
| }); | |
| chartView.on('mouseover', function(slice, e) { | |
| var $slice = $('.slice[data-serie="' + slice.serieIndex + '"][data-slice="' + slice.sliceIndex + '"]', $chartViewDataEl), | |
| elSlice = V($slice[0]); | |
| // _.each(this.$('.slice'), function(slice) { V(slice).scale(1); $('.slice-inner-label', $(slice)).css('display', 'none'); }); | |
| _.each($('.slice', $chartViewDataEl), function(slice) { V(slice).scale(1); }); | |
| $('.slice-inner-label', $chartViewDataEl).css('display', 'none'); | |
| elSlice.scale(1.2); | |
| chart.prop('active-slice', slice.sliceIndex); | |
| // $('.slice-inner-label', $slice).css('display', 'block'); | |
| $('.slice-inner-label[data-slice="' + slice.sliceIndex + '"]', $chartViewDataEl).css('display', 'block'); | |
| }); | |
| } | |
| else if (attributes.config.type === 'Send Email') { | |
| chart.prop('position', { x: bbox.x + bbox.width - chartPieRadius, y: bbox.y + bbox.height / 2 - chartPieRadius }); | |
| pieValue = 100 / 7; | |
| chart.prop('series', [{ data: [ | |
| { value: pieValue, label: 'On Bounce', fill: chartSerieFillColor[0], groupKey: 'on_bounce' }, | |
| { value: pieValue, label: 'On Click', fill: chartSerieFillColor[1], groupKey: 'on_click' }, | |
| { value: pieValue, label: 'On Open', fill: chartSerieFillColor[2], groupKey: 'on_open' }, | |
| { value: pieValue, label: 'On Unsubscribe', fill: chartSerieFillColor[3], groupKey: 'on_unsubscribe' }, | |
| { value: pieValue, label: 'On Reply', fill: chartSerieFillColor[4], groupKey: 'on_reply' }, | |
| { value: pieValue, label: 'On Send', fill: chartSerieFillColor[5], groupKey: 'on_send' }, | |
| { value: pieValue, label: 'On No Response', fill: chartSerieFillColor[6], groupKey: 'on_no_response' } | |
| ] }]); | |
| chart.prop('active-slice', undefined); | |
| graph.addCell(chart); | |
| chart.toFront(); | |
| chartView = paper.findViewByModel(chart); | |
| $chartViewDataEl = chartView.$('.data'); | |
| chartView.$('.slice-inner-label').each(function () { | |
| var $textEl = $(this); | |
| $textEl.attr('data-slice', $textEl.parents('.slice').attr('data-slice')); | |
| $textEl.appendTo($chartViewDataEl); | |
| }); | |
| chartView.on('mouseover', function(slice, e) { | |
| var $slice = $('.slice[data-serie="' + slice.serieIndex + '"][data-slice="' + slice.sliceIndex + '"]', $chartViewDataEl), | |
| elSlice = V($slice[0]); | |
| // _.each(this.$('.slice'), function(slice) { V(slice).scale(1); $('.slice-inner-label', $(slice)).css('display', 'none'); }); | |
| _.each($('.slice', $chartViewDataEl), function(slice) { V(slice).scale(1); }); | |
| $('.slice-inner-label', $chartViewDataEl).css('display', 'none'); | |
| elSlice.scale(1.2); | |
| chart.prop('active-slice', slice.sliceIndex); | |
| // $('.slice-inner-label', $slice).css('display', 'block'); | |
| $('.slice-inner-label[data-slice="' + slice.sliceIndex + '"]', $chartViewDataEl).css('display', 'block'); | |
| }); | |
| } | |
| else if (attributes.config.type === 'Twitter Status') { | |
| chart.prop('position', { x: bbox.x + bbox.width - chartPieRadius, y: bbox.y + bbox.height / 2 - chartPieRadius }); | |
| pieValue = 100 / 4; | |
| chart.prop('series', [{ data: [ | |
| { value: pieValue, label: 'Following Us', fill: chartSerieFillColor[0], groupKey: 'following_us' }, | |
| { value: pieValue, label: 'Not Following Us', fill: chartSerieFillColor[1], groupKey: 'not_following_us' }, | |
| { value: pieValue, label: 'Blocking Us', fill: chartSerieFillColor[2], groupKey: 'blocking_us' }, | |
| { value: pieValue, label: 'Muted By Us', fill: chartSerieFillColor[3], groupKey: 'muted_by_us' } | |
| ] }]); | |
| chart.prop('active-slice', undefined); | |
| graph.addCell(chart); | |
| chart.toFront(); | |
| chartView = paper.findViewByModel(chart); | |
| $chartViewDataEl = chartView.$('.data'); | |
| chartView.$('.slice-inner-label').each(function () { | |
| var $textEl = $(this); | |
| $textEl.attr('data-slice', $textEl.parents('.slice').attr('data-slice')); | |
| $textEl.appendTo($chartViewDataEl); | |
| }); | |
| chartView.on('mouseover', function(slice, e) { | |
| var $slice = $('.slice[data-serie="' + slice.serieIndex + '"][data-slice="' + slice.sliceIndex + '"]', $chartViewDataEl), | |
| elSlice = V($slice[0]); | |
| // _.each(this.$('.slice'), function(slice) { V(slice).scale(1); $('.slice-inner-label', $(slice)).css('display', 'none'); }); | |
| _.each($('.slice', $chartViewDataEl), function(slice) { V(slice).scale(1); }); | |
| $('.slice-inner-label', $chartViewDataEl).css('display', 'none'); | |
| elSlice.scale(1.2); | |
| chart.prop('active-slice', slice.sliceIndex); | |
| // $('.slice-inner-label', $slice).css('display', 'block'); | |
| $('.slice-inner-label[data-slice="' + slice.sliceIndex + '"]', $chartViewDataEl).css('display', 'block'); | |
| }); | |
| } | |
| else if (attributes.config.type === 'Twitter Message') { | |
| chart.prop('position', { x: bbox.x + bbox.width - chartPieRadius, y: bbox.y + bbox.height / 2 - chartPieRadius }); | |
| pieValue = 100 / 5; | |
| chart.prop('series', [{ data: [ | |
| { value: pieValue, label: '@Mentions Us', fill: chartSerieFillColor[0], groupKey: 'mentions_us' }, | |
| { value: pieValue, label: 'DMs Us', fill: chartSerieFillColor[1], groupKey: 'dms_us' }, | |
| { value: pieValue, label: 'Blocking Us', fill: chartSerieFillColor[2], groupKey: 'blocking_us' }, | |
| { value: pieValue, label: 'On Send', fill: chartSerieFillColor[3], groupKey: 'on_send' }, | |
| { value: pieValue, label: 'On No Response', fill: chartSerieFillColor[4], groupKey: 'on_no_response' } | |
| ] }]); | |
| chart.prop('active-slice', undefined); | |
| graph.addCell(chart); | |
| chart.toFront(); | |
| chartView = paper.findViewByModel(chart); | |
| $chartViewDataEl = chartView.$('.data'); | |
| chartView.$('.slice-inner-label').each(function () { | |
| var $textEl = $(this); | |
| $textEl.attr('data-slice', $textEl.parents('.slice').attr('data-slice')); | |
| $textEl.appendTo($chartViewDataEl); | |
| }); | |
| chartView.on('mouseover', function(slice, e) { | |
| var $slice = $('.slice[data-serie="' + slice.serieIndex + '"][data-slice="' + slice.sliceIndex + '"]', $chartViewDataEl), | |
| elSlice = V($slice[0]); | |
| // _.each(this.$('.slice'), function(slice) { V(slice).scale(1); $('.slice-inner-label', $(slice)).css('display', 'none'); }); | |
| _.each($('.slice', $chartViewDataEl), function(slice) { V(slice).scale(1); }); | |
| $('.slice-inner-label', $chartViewDataEl).css('display', 'none'); | |
| elSlice.scale(1.2); | |
| chart.prop('active-slice', slice.sliceIndex); | |
| // $('.slice-inner-label', $slice).css('display', 'block'); | |
| $('.slice-inner-label[data-slice="' + slice.sliceIndex + '"]', $chartViewDataEl).css('display', 'block'); | |
| }); | |
| } | |
| }); | |
| }); | |
| paper.on('cell:mouseout', function(cellView, e) { | |
| if (linkDownFlag || agentDownFlag || !isAgent(cellView)) return; | |
| var $te = $(e.relatedTarget); | |
| if (($te.hasClass('handle') && ($te.parents('.halo2').length == 0)) || | |
| $te.parents('[model-id=' + cellView.model.id + ']').length > 0) return; | |
| if (halo) { | |
| halo.remove(); | |
| halo = undefined; | |
| checkAgentIfConfiguredAndDoIt(cellView); | |
| } | |
| showAgentSubtitle(cellView); | |
| }); | |
| paper.$el.on('mouseenter', '.halo2 .handle.config', function() { | |
| var modelId = $(this).parents('.halo2').attr('data-model-id'); | |
| paper.trigger('cell:mouseover', paper.findViewByModel(paper.getModelById(modelId))); | |
| }); | |
| paper.$el.on('mouseleave', '.halo .handle', function(e) { | |
| if (!halo || linkDownFlag || agentDownFlag) return; | |
| var $te = $(e.relatedTarget), | |
| cellView = halo.options.cellView; | |
| if ($te.parents('[model-id=' + cellView.model.id + ']').length > 0 || | |
| ($te.hasClass('handle') && ($te.parents('.halo2').length == 0))) return; | |
| checkAgentIfConfiguredAndDoIt(cellView); | |
| halo.remove(); | |
| halo = undefined; | |
| showAgentSubtitle(cellView); | |
| }); | |
| } | |
| /** | |
| * createInspector() | |
| * | |
| * @param joint.dia.ElementView cellView | |
| */ | |
| function createInspector(cellView) { | |
| // No need to re-render inspector if the cellView didn't change. | |
| // ------------------------------------------------------------- | |
| if (!inspector || inspector.options.cellView !== cellView) { | |
| if (inspector) { | |
| // Set unsaved changes to the model and clean up the old inspector if there was one. | |
| inspector.updateCell(); | |
| inspector.remove(); | |
| } | |
| var $dlgEl = $('#inspector_dialog'), | |
| attributes = cellView.model.attributes, | |
| config = attributes.config, | |
| agentType = config.type, | |
| addServiceURL = '', | |
| fields = config.fields, | |
| inputs = { | |
| is_goal: { type: 'toggle', label: 'Set this as goal' } | |
| }, | |
| $isGoalDivEl; | |
| for (var i = 0, n = fields.length; i < n; i ++) { | |
| inputs[fields[i]] = {}; | |
| } | |
| initializeInspectorInputs(inputs, attributes); | |
| inspector = new joint.ui.Inspector({ | |
| cellView: cellView, | |
| inputs: inputs, | |
| live: false | |
| }); | |
| $('[data-field="schedule"]', '#inspector_dialog_header').remove(); | |
| $dlgEl.find('.inspector-container').html(inspector.render().el); | |
| $dlgEl.find('.modal-title') | |
| .html(attributes.attrs.text.text) | |
| .after($('[data-field="schedule"]', '.inspector').addClass('pull-right')); | |
| $dlgEl.find('.description').html( config.description || '' ); | |
| $dlgEl.find('.btn-list-add').addClass('btn btn-xs'); | |
| $dlgEl.find('.btn-list-del').addClass('btn btn-xs pull-right').html('×'); | |
| if (agentHasField(cellView, 'segment_id')) { | |
| $dlgEl.find('[data-field="segment_id"]').append('<a href="' + gOptions.add_segment_url + '" class="btn btn-xs btn-primary">Add New Segment</a>'); | |
| } | |
| if (agentHasField(cellView, 'service_id')) { | |
| switch (agentType) { | |
| case 'Facebook Update': | |
| case 'Twitter Action': | |
| case 'Twitter Message': | |
| case 'Twitter Status': | |
| addServiceURL = gOptions.add_twitter_service_url; break; | |
| case 'Send Email': | |
| addServiceURL = gOptions.add_email_service_url; break; | |
| } | |
| $dlgEl.find('[data-field="service_id"]').append('<a href="' + addServiceURL + '" class="btn btn-xs btn-primary">Add New Service</a>'); | |
| } | |
| if (agentHasField(cellView, 'message_template_id')) { | |
| $dlgEl.find('[data-field="message_template_id"]').append('<a href="' + gOptions.add_message_template_url + '" class="btn btn-xs btn-primary">Add New Message Template</a>'); | |
| } | |
| if (agentHasField(cellView, 'campaign_list_id')) { | |
| $dlgEl.find('[data-field="campaign_list_id"]').append('<a href="' + gOptions.add_campaign_list_url + '" class="btn btn-xs btn-primary">Add New Campaign List</a>'); | |
| } | |
| if (agentType == 'Twitter Action') { | |
| var actionValue = $dlgEl.find('[data-attribute="criteria/action"]').val(); | |
| $dlgEl.find('[data-field="criteria/list_name"]').toggle(actionValue == 'list' || actionValue == 'unlist'); | |
| } | |
| $dlgEl.find('select > option[value=""]').prop('disabled', true); | |
| $dlgEl.find('.modal-footer').find('[data-field="is_goal"]').remove(); | |
| var dataFieldId, $dataFieldDivEl, $inputEl; | |
| $dlgEl.find('[data-type="toggle"]').each(function () { | |
| $inputEl = $(this); | |
| $dataFieldDivEl = $inputEl.parents('[data-field]'); | |
| dataFieldId = $dataFieldDivEl.attr('data-field'); | |
| if (dataFieldId === 'is_goal') { | |
| $dataFieldDivEl.prependTo($dlgEl.find('.modal-footer')); | |
| } | |
| $dataFieldDivEl | |
| .addClass('checkbox') | |
| .css('float', 'left') | |
| .css('margin-top', '5px'); | |
| $inputEl.attr('id', dataFieldId).insertBefore($('label', $dataFieldDivEl)); | |
| $('label', $dataFieldDivEl).attr('for', dataFieldId); | |
| $('div.toggle', $dataFieldDivEl).remove(); | |
| }); | |
| // $('.toggle', $isGoalDivEl).remove(); | |
| $dlgEl.modal('show'); | |
| } | |
| } | |
| /** | |
| * readableScheduleText() | |
| * | |
| * @param String text | |
| * @return String | |
| */ | |
| function readableScheduleText(text) { | |
| text = text.toString(); | |
| if (!text || text.trim().length === 0) return ''; | |
| var matches, | |
| timeUnitsSingular = { 'm': 'minute', 'h': 'hour', 'd': 'day' }, | |
| timeUnitsPlural = { 'm': 'minutes', 'h': 'hours', 'd': 'days' }; | |
| if (matches = text.match(/^every_(\d+)(.+)/)) { | |
| text = 'Every ' + ( parseInt(matches[1], 10) > 1 ? matches[1] + ' ' + timeUnitsPlural[matches[2]] : timeUnitsSingular[matches[2]] ); | |
| } | |
| else if (matches = text.match(/^(\d+)(.+)/)) { | |
| text = matches[1] + ' ' + matches[2].toUpperCase(); | |
| } | |
| else { | |
| text = text.charAt(0).toUpperCase() + text.slice(1); | |
| } | |
| return text; | |
| } | |
| /** | |
| * initializeDefaultConfigValues() | |
| * | |
| * @param joint.dia.Cell cell | |
| */ | |
| function initializeDefaultConfigValues(cell) { | |
| var attributes = cell.attributes, | |
| agentType = attributes.config.type; | |
| if (agentHasField(cell, 'workflow_id')) { | |
| attributes.workflow_id = gOptions.workflow_id; | |
| } | |
| if (agentType === 'Has Facebook' || | |
| agentType === 'Has Email' || | |
| agentType === 'Has Twitter') { | |
| if (agentHasField(cell, 'criteria')) { | |
| attributes.criteria = attributes.config.criteria; | |
| } | |
| } | |
| attributes.schedule = attributes.default_schedule; | |
| } | |
| /** | |
| * initializeInspectorInputs() | |
| * | |
| * @param Object inputs | |
| * @param Object attributes | |
| */ | |
| function initializeInspectorInputs(inputs, attributes) { | |
| var config = attributes.config, | |
| criteria = config.criteria, | |
| tmp, options, | |
| type = config.type; | |
| if (type.match(/Segment$/)) { | |
| type = type.match(/(.*) Segment$/)[1].toLowerCase(); | |
| } | |
| for (var field in inputs) { | |
| switch (field) { | |
| case 'segment_id': | |
| tmp = config.dropdowns.segments; | |
| options = [{ value: '', content: 'Choose segment..' }]; | |
| for (var i = 0, n = tmp.length; i < n; i ++) { | |
| options.push({ value: tmp[i].value, content: tmp[i].name }); | |
| } | |
| inputs[field] = { | |
| type: 'select', label: 'Segments', options: options, index: 1 | |
| }; | |
| // Assume these agents are triggers and let's add another trigger-specific field | |
| inputs.only_new = { | |
| type: 'toggle', label: ['Only new ', type, ' that matches this segment'].join('') | |
| }; | |
| break; | |
| case 'schedule': | |
| tmp = config.dropdowns.schedule; | |
| options = []; | |
| for (var i = 0, n = tmp.length; i < n; i ++) { | |
| options.push({ value: tmp[i], content: readableScheduleText(tmp[i]) }); | |
| } | |
| inputs[field] = { | |
| type: 'select', label: 'Schedule', options: options | |
| }; | |
| break; | |
| case 'service_id': | |
| tmp = config.dropdowns.services; | |
| if (config.type === 'Twitter Action' || config.type === 'Twitter Status' || config.type === 'Twitter Message') { | |
| tmp = config.dropdowns.twitter_services; | |
| } | |
| else if (config.type === 'Facebook Update') { | |
| tmp = config.dropdowns.facebook_services; | |
| } | |
| else if (config.type === 'Send Email') { | |
| tmp = config.dropdowns.email_services; | |
| } | |
| options = [{ value: '', content: 'Choose service..' }]; | |
| for (var i = 0, n = tmp.length; i < n; i ++) { | |
| options.push({ value: tmp[i].value, content: tmp[i].name }); | |
| } | |
| inputs[field] = { | |
| type: 'select', label: 'Services', options: options, index: 1 | |
| }; | |
| break; | |
| case 'campaign_list_id': | |
| tmp = config.dropdowns.campaigns_list; | |
| options = [{ value: '', content: 'Choose campaign..' }]; | |
| for (var i in tmp) { | |
| options.push({ value: tmp[i].id, content: tmp[i].name }); | |
| } | |
| inputs[field] = { | |
| type: 'select', label: 'Campaigns', options: options, index: 1 | |
| }; | |
| options = [{ value: '', content: 'Choose stage..' }]; | |
| if (attributes.campaign_list_id) { | |
| tmp = config.dropdowns.campaigns_list[attributes.campaign_list_id].stages; | |
| for (var i in tmp) { | |
| options.push({ value: tmp[i].id, content: tmp[i].name }); | |
| } | |
| } | |
| inputs['stage_id'] = { | |
| type: 'select', label: 'Stages', options: options, index: 2 | |
| }; | |
| // Assume this is a campaign list agent and let's add another campaign-specific field | |
| inputs.only_new = { | |
| type: 'toggle', label: 'Only new list that matches this segment' | |
| }; | |
| break; | |
| case 'message_template_id': | |
| tmp = config.dropdowns.message_templates; | |
| options = [{ value: '', content: 'Choose message template..' }]; | |
| for (var i = 0, n = tmp.length; i < n; i ++) { | |
| options.push({ value: tmp[i].message_template.id, content: tmp[i].message_template.name }); | |
| } | |
| inputs[field] = { | |
| type: 'select', label: 'Message Template', options: options | |
| }; | |
| break; | |
| case 'user_ids': | |
| tmp = config.dropdowns.users; | |
| options = [{ value: '', content: 'Choose a user..' }]; | |
| for (var i = 0, n = tmp.length; i < n; i ++) { | |
| options.push({ value: tmp[i].user.id, content: tmp[i].user.name + ' (' + tmp[i].user.login + ')' }); | |
| } | |
| inputs[field] = { | |
| type: 'select', label: 'User', options: options | |
| }; | |
| break; | |
| case 'criteria': | |
| if (config.type == "Add Field" || config.type == "Modify Field") { | |
| inputs.criteria = { | |
| type: 'list', | |
| item: { | |
| type: 'object', | |
| properties: { | |
| field_name: { type: 'text', label: 'Field Name' }, | |
| field_value: { type: 'text', label: 'Field Value' } | |
| } | |
| }, | |
| label: 'Click the {+} button to add a field and value.', | |
| attrs: { | |
| label: { class: 'custom-label' } | |
| }, | |
| index: 99 | |
| }; | |
| } | |
| else if (config.type == 'Filter') { | |
| inputs.criteria = { type: 'text', label: 'Criteria', index: 99 }; | |
| } | |
| else if (config.type == 'Twitter Action') { | |
| inputs.criteria = { | |
| action: { | |
| type: 'select', | |
| label: 'Action', | |
| options: [ | |
| { value: '', content: 'Choose action..' }, | |
| { value: 'follow', content: 'Follow' }, | |
| { value: 'unfollow', content: 'Unfollow' }, | |
| { value: 'list', content: 'List' }, | |
| { value: 'unlist', content: 'Unlist' } | |
| ], | |
| index: 98 | |
| }, | |
| list_name: { type: 'text', label: 'List Name', index: 99 } | |
| }; | |
| } | |
| else if (config.type == "Split") { | |
| inputs.criteriaUI = { | |
| type: 'list', | |
| item: { | |
| type: 'object', | |
| properties: { | |
| weight_label: { type: 'text', label: 'Label' }, | |
| weight: { type: 'text', label: 'Weight' } | |
| } | |
| }, | |
| label: 'Click the {+} button to add a weight.', | |
| attrs: { | |
| label: { class: 'custom-label' } | |
| }, | |
| index: 99 | |
| }; | |
| } | |
| else if (config.type == 'Delay') { | |
| inputs.criteria = { | |
| length: { type: 'text', label: 'Length', attrs: { type: 'number' }, index: 98 }, | |
| unit: { | |
| type: 'select', | |
| label: 'Type', | |
| options: [ | |
| { value: '', content: 'Choose..' }, | |
| { value: 'minutes', content: 'Minutes' }, | |
| { value: 'hours', content: 'Hours' }, | |
| { value: 'days', content: 'Days' }, | |
| { value: 'weeks', content: 'Weeks' }, | |
| { value: 'months', content: 'Months' } | |
| ], | |
| index: 99 | |
| } | |
| }; | |
| } | |
| else if (config.type == 'Twitter Message') { | |
| tmp = config.dropdowns.message_type; | |
| options = [{ value: '', content: 'Choose message type..' }]; | |
| for (var i = 0, n = tmp.length; i < n; i ++) { | |
| options.push({ value: tmp[i], content: tmp[i].replace(/\w/, function(match, capture) { return match.toUpperCase(); }) }); | |
| } | |
| inputs.criteria = { | |
| type: 'select', label: 'Message Type', options: options, index: 99 | |
| }; | |
| } | |
| else if (config.type == 'Limit') { | |
| inputs.criteria = { type: 'text', label: 'Limit', index: 99 }; | |
| } | |
| else if (config.type == "Update Field") { | |
| inputs.criteria = { | |
| type: 'list', | |
| item: { | |
| type: 'object', | |
| properties: { | |
| field_name: { type: 'text', label: 'Field Name' }, | |
| field_value: { type: 'text', label: 'Field Value' } | |
| } | |
| }, | |
| label: 'Click the {+} button to add a field and value.', | |
| attrs: { | |
| label: { class: 'custom-label' } | |
| }, | |
| index: 99 | |
| }; | |
| } | |
| else if (config.type == 'Has Profile') { | |
| tmp = config.dropdowns.services; | |
| options = [{ value: '', content: 'Choose..' }]; | |
| for (var i = 0, n = tmp.length; i < n; i ++) { | |
| options.push({ value: tmp[i], content: tmp[i].replace(/\w/, function(match, capture) { return match.toUpperCase(); }) }); | |
| } | |
| inputs.criteria = { type: 'select', label: 'Has Profile', options: options, index: 99 }; | |
| } | |
| else if (config.type == 'Modify Campaign List') { | |
| inputs.criteria = { | |
| type: 'select', | |
| label: 'Action', | |
| options: [ | |
| { value: '', content: 'Choose action..' }, | |
| { value: 'add', content: 'Add' }, | |
| { value: 'remove', content: 'Remove' } | |
| ], | |
| index: 99 | |
| }; | |
| } | |
| else { | |
| delete inputs.criteria; | |
| } | |
| break; | |
| default: | |
| } | |
| } | |
| } | |
| /** | |
| * agentHasField() | |
| * | |
| * @param joint.dia.ElementView|joint.dia.Cell cell | |
| * @param String fieldName | |
| * @return Bool | |
| */ | |
| function agentHasField(cell, fieldName) { | |
| var model = cell.model || cell, | |
| fields = model.attributes.config.fields; | |
| return (fields.indexOf(fieldName) >= 0); | |
| } | |
| /** | |
| * isAgentConfigured() | |
| * | |
| * @param joint.dia.ElementView cellView | |
| * @return Bool | |
| */ | |
| function isAgentConfigured(cellView) { | |
| if (!cellView || !cellView.model) return false; | |
| var attributes = cellView.model.attributes, | |
| agentType = attributes.config.type, | |
| data, k; | |
| if (agentHasField(cellView, 'criteria')) { | |
| data = attributes.criteria; | |
| if (!data) return false; | |
| if (data instanceof Array && data.length === 0) return false; | |
| if (agentType == 'Add Field' || agentType == 'Update Field') { | |
| for (var i = 0, n = data.length; i < n; i ++) { | |
| if (data[i].field_name.toString().match(/^\s*$/) || data[i].field_value.toString().match(/^\s*$/)) { | |
| return false; | |
| } | |
| } | |
| } else if (agentType == 'Filter') { | |
| if (data.toString().match(/^\s*$/)) return false; | |
| } else if (agentType == 'Twitter Action') { | |
| if (!data.action || data.action.toString().match(/^\s*$/)) return false; | |
| if (data.action.toString().match(/^(list|unlist)$/) && data.list_name.toString().match(/^\s*$/)) return false; | |
| } else if (agentType == 'Split') { | |
| data = attributes.criteriaUI; | |
| for (var i = 0, n = data.length; i < n; i ++) { | |
| if (data[i].weight_label.toString().match(/^\s*$/) || data[i].weight.toString().match(/^\s*$/)) { | |
| return false; | |
| } | |
| } | |
| } else if (agentType == 'Twitter Message') { | |
| if (data.toString().match(/^\s*$/)) return false; | |
| } else if (agentType == 'Delay') { | |
| if (data.length.toString().match(/^\s*$/) || !data.unit || data.unit.toString().match(/^\s*$/)) return false; | |
| } else if (agentType == 'Limit') { | |
| if (data.toString().match(/^\s*$/)) return false; | |
| } else if (agentType == 'Has Profile') { | |
| if (data.toString().match(/^\s*$/)) return false; | |
| } else { | |
| for (k in data) { | |
| if (data[k].toString().match(/^\s*$/)) { | |
| return false; | |
| } | |
| } | |
| } | |
| } | |
| if (agentHasField(cellView, 'segment_id')) { | |
| data = attributes.segment_id; | |
| if (!data) return false; | |
| } | |
| if (agentHasField(cellView, 'service_id')) { | |
| data = attributes.service_id; | |
| if (!data) return false; | |
| } | |
| if (agentHasField(cellView, 'message_template_id')) { | |
| data = attributes.message_template_id; | |
| if (!data) return false; | |
| } | |
| if (agentHasField(cellView, 'campaign_list_id')) { | |
| data = attributes.campaign_list_id; | |
| if (!data || !attributes.stage_id) return false; | |
| } | |
| if (agentHasField(cellView, 'user_ids')) { | |
| data = attributes.user_ids; | |
| if (!data) return false; | |
| } | |
| return true; | |
| } | |
| /** | |
| * checkAgentIfConfiguredAndDoIt() | |
| * | |
| * @param joint.dia.ElementView cellView | |
| */ | |
| function checkAgentIfConfiguredAndDoIt(cellView) { | |
| var modelId = cellView.model.id; | |
| if (isAgentConfigured(cellView)) | |
| { | |
| // In case agent is configured, remove config link. | |
| halo2[modelId] && halo2[modelId].remove(); | |
| delete halo2[modelId]; | |
| } | |
| else | |
| { | |
| // This case implies agent is not configured. | |
| if (halo2[modelId] === undefined) { | |
| var h = new Halo2({ cellView: cellView }); | |
| h.render(); | |
| halo2[modelId] = h; | |
| } | |
| } | |
| } | |
| /** | |
| * initializeNavigator() | |
| */ | |
| function initializeNavigator() { | |
| nav = new joint.ui.Navigator({ | |
| paperScroller: paperScroller, | |
| width: 200, | |
| height: 100, | |
| padding: 10, | |
| zoomOptions: { max: zoomMax, min: zoomMin } | |
| }); | |
| nav.$el.appendTo('#navigator'); | |
| nav.render(); | |
| $('#zoom-in').on('click', function() { | |
| paperScroller.zoom(zoomStep, { max: zoomMax }); | |
| }); | |
| $('#zoom-out').on('click', function() { | |
| paperScroller.zoom(-zoomStep, { min: zoomMin }); | |
| }); | |
| $('#toggle-panning').on('click', function() { | |
| }); | |
| } | |
| /** | |
| * clearGraph() | |
| */ | |
| function clearGraph() { | |
| for (var k in halo2) { | |
| halo2[k].remove(); | |
| delete halo2[k]; | |
| } | |
| graph.clear(); | |
| } | |
| /** | |
| * initAgentSubtitle() | |
| * | |
| * @param joint.dia.ElementView cellView | |
| */ | |
| function initAgentSubtitle(cellView) { | |
| var subtitle = cellView.model.attributes.subtitle, | |
| subtitleAlt = cellView.model.attributes.subtitleAlt, | |
| $cellEl = cellView.$el, | |
| subtitleTextNode = $cellEl.find('.agent-subtitle'); | |
| if (subtitle || subtitleAlt) { | |
| if (subtitleTextNode.length == 0) { | |
| subtitleTextNode = V('<text class="agent-subtitle" display="null" xml:space="preserve" font-size="14" text-anchor="middle" fill="#fff" y="0.8em" transform="matrix(1 0 0 1 0 0)"></text>').node; | |
| cellView.el.appendChild(subtitleTextNode); | |
| subtitleTextNode = $(subtitleTextNode); | |
| } | |
| subtitleTextNode.attr('data-normal-text', subtitle).attr('data-hover-text', subtitleAlt); | |
| if (subtitle) { | |
| showAgentSubtitle(cellView); | |
| } | |
| } | |
| else { | |
| if (subtitleTextNode.length > 0) { | |
| subtitleTextNode.remove(); | |
| } | |
| } | |
| } | |
| function showAgentSubtitle(cellView, showNormalText) { | |
| var $cellEl = cellView.$el, | |
| subtitleTextNode = $cellEl.find('.agent-subtitle'), | |
| subtitleNormalText = subtitleTextNode.attr('data-normal-text'), | |
| subtitleHoverText = subtitleTextNode.attr('data-hover-text'), | |
| $textTitleEl = $cellEl.find('text.title'), | |
| x, y; | |
| if (subtitleTextNode.length == 0) return; | |
| if (showNormalText === undefined) { | |
| showNormalText = true; | |
| } | |
| if (showNormalText) { | |
| $textTitleEl.show(); | |
| subtitleNormalText = subtitleNormalText || ""; | |
| x = shapeBigSize[0] / 2; | |
| y = shapeBigSize[1] / 2 + $textTitleEl[0].getBBox().height + 5; | |
| subtitleTextNode.html(getWordWrapText(subtitleNormalText, { width: shapeBigSize[0] }))[0].transform.translate(x, y); | |
| } | |
| else if (!showNormalText && subtitleHoverText !== undefined) { | |
| $textTitleEl.hide(); | |
| x = shapeBigSize[0] / 2; | |
| y = shapeBigSize[1] / 2; | |
| subtitleTextNode.html(getWordWrapText(subtitleHoverText, { width: shapeBigSize[0] }))[0].transform.translate(x, y); | |
| } | |
| } | |
| /** | |
| * showGoalMarker() | |
| * | |
| * @param joint.dia.ElementView cellView | |
| */ | |
| function showGoalMarker(cellView) { | |
| cellView.el.appendChild($goalMarkerEl); | |
| } | |
| /** | |
| * initializeMisc() | |
| */ | |
| function initializeMisc() { | |
| $('#btn_clear').on('click', function() { | |
| clearGraph(); | |
| }); | |
| $('#btn_save').on('click', function() { | |
| saveWorkflow(); | |
| }); | |
| $('#btn_save_close').on('click', function() { | |
| saveWorkflow(function (data) { | |
| window.location.replace(gOptions.workflows_path); | |
| }); | |
| }); | |
| $('#btn_open_png').on('click', function() { | |
| paper.toPNG(function (dataURL) { | |
| window.open(dataURL); | |
| }); | |
| }); | |
| $('#inspector_dialog').on('hide.bs.modal', function() { | |
| if (inspector) { | |
| inspector.remove(); | |
| inspector = null; | |
| } | |
| }); | |
| $('#inspector_btn_save').on('click', function() { | |
| if (inspector) { | |
| inspector.updateCell(); | |
| var cellView = inspector.options.cellView, | |
| attributes = cellView.model.attributes, | |
| agentType = attributes.config.type, | |
| tmp; | |
| // Special process for Split agent | |
| if (agentType === 'Split') { | |
| attributes.criteria = {}; | |
| for (var i = 0, criteriaUI = attributes.criteriaUI, n = criteriaUI.length; i < n; i ++) { | |
| attributes.criteria[criteriaUI[i].weight_label] = criteriaUI[i].weight; | |
| } | |
| } | |
| checkAgentIfConfiguredAndDoIt(cellView); | |
| if (isAgentConfigured(cellView)) { | |
| if (agentHasField(cellView, 'segment_id')) { | |
| attributes.subtitle = $('select[data-attribute="segment_id"] option:selected', '#inspector_dialog').html(); | |
| } | |
| else { | |
| switch (agentType) { | |
| case 'Facebook Update': | |
| case 'Twitter Message': | |
| case 'Twitter Status': | |
| attributes.subtitle = $('select[data-attribute="service_id"] option:selected', '#inspector_dialog').html(); | |
| break; | |
| case 'Send Email': | |
| attributes.subtitle = $('select[data-attribute="message_template_id"] option:selected', '#inspector_dialog').html(); | |
| break; | |
| case 'Twitter Action': | |
| attributes.subtitle = $('select[data-attribute="criteria/action"] option:selected', '#inspector_dialog').html(); | |
| break; | |
| case 'Delay': | |
| attributes.subtitle = [attributes.criteria.length, $('select[data-attribute="criteria/unit"] option:selected', '#inspector_dialog').html()].join(' '); | |
| break; | |
| case 'Limit': | |
| attributes.subtitle = attributes.criteria.toString(); | |
| break; | |
| case 'Has Profile': | |
| attributes.subtitle = $('select[data-attribute="criteria"] option:selected', '#inspector_dialog').html(); | |
| break; | |
| case 'Split': | |
| attributes.subtitle = $('[data-attribute="criteriaUI"] .list-item', '#inspector_dialog').length.toString(); | |
| break; | |
| case 'Campaign List': | |
| attributes.subtitleAlt = [$('[data-attribute="campaign_list_id"] option:selected', '#inspector_dialog').html(), $('[data-attribute="stage_id"] option:selected', '#inspector_dialog').html()].join(': '); | |
| break; | |
| case 'Modify Campaign List': | |
| attributes.subtitle = $('select[data-attribute="criteria"] option:selected', '#inspector_dialog').html(); | |
| attributes.subtitleAlt = [$('[data-attribute="campaign_list_id"] option:selected', '#inspector_dialog').html(), $('[data-attribute="stage_id"] option:selected', '#inspector_dialog').html()].join(': '); | |
| break; | |
| default: | |
| } | |
| } | |
| } | |
| else { | |
| delete attributes.subtitle; | |
| } | |
| initAgentSubtitle(cellView); | |
| if (attributes.is_goal) { | |
| for (var i = 0, cells = graph.getCells(), n = cells.length; i < n; i ++) { | |
| if (cells[i] === cellView.model) continue; | |
| delete cells[i].attributes.is_goal; | |
| } | |
| showGoalMarker(cellView); | |
| } | |
| $('#inspector_dialog').modal('hide'); | |
| } | |
| }); | |
| $('#inspector_dialog').on('click', '.btn-list-add', function () { | |
| $('.btn-list-del', '#inspector_dialog').addClass('btn btn-xs pull-right').html('×'); | |
| if (inspector.options.cellView.model.attributes.config.type == 'Split' && $('.list-item', '#inspector_dialog').length >= 5) { | |
| $(this).prop('disabled', true); | |
| } | |
| }) | |
| .on('click', '[data-attribute="criteria/action"]', function() { | |
| var value = $(this).val(); | |
| $('[data-field="criteria/list_name"]', '#inspector_dialog').toggle(value == 'list' || value == 'unlist'); | |
| }) | |
| .on('change', '[data-attribute="campaign_list_id"]', function () { | |
| var options = '<option value="" selected disabled>Choose stage..</option>', | |
| campaign_list_id = $(this).val(); | |
| $('[data-field="stage_id"]', '#inspector_dialog').toggle(campaign_list_id != ''); | |
| if (campaign_list_id) { | |
| for (var i = 0, | |
| stages = inspector.options.cellView.model.attributes.config.dropdowns.campaigns_list[campaign_list_id].stages, | |
| n = stages.length; | |
| i < n; i ++) { | |
| options += '<option value="' + stages[i].id + '">' + stages[i].name + '</option>'; | |
| } | |
| } | |
| $('[data-attribute="stage_id"]', '#inspector_dialog').html(options); | |
| }); | |
| $(document).on('click.btnListDel', '.btn-list-del', function () { | |
| if (inspector.options.cellView.model.attributes.config.type == 'Split') { | |
| $('.btn-list-add', '#inspector_dialog').prop('disabled', false); | |
| } | |
| }); | |
| } | |
| return { | |
| shapeSize: shapeSize, | |
| iconSize: iconSize, | |
| init: function(stencilData, options) { | |
| gOptions = options; | |
| initializePaper(); | |
| initializeStencil(stencilData); | |
| initializeHaloAndInspector(); | |
| initializeNavigator(); | |
| initializeMisc(); | |
| }, | |
| createCustomShapes: function() { | |
| createCustomShapes(); | |
| }, | |
| /* for debugging */ | |
| exposed: function() { | |
| return { | |
| paper: paper, | |
| graph: graph, | |
| paperScroller: paperScroller, | |
| nav: nav, | |
| stencil: stencil, | |
| snaplines: snaplines, | |
| halo: halo, | |
| inspector: inspector, | |
| chart: chart, | |
| gOptions: gOptions | |
| }; | |
| } | |
| }; | |
| }(); | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment