1 /** 2 * An object for editing toolsets. 3 * @extends Monk.component.Component 4 * @author Andrew 5 */ 6 7 Monk.component.ToolsetEditor = function(args) { 8 9 this.projectToolsets = args.projectToolsets; 10 11 // the tools 12 this.tools = feature.components; 13 14 var toolsHTML = '<div id="toolsParent" style="float: left; width: 100%; height: 100%;">'; 15 16 var toolsTemplate = new Ext.Template( 17 '<div id="{id}" class="draggable-tool">', 18 '<img src="{icon}" title="{summary}" onerror="this.src=\'resources/images/tools/default_icon.gif\'"/>', 19 '<span style="float: left; clear: left;">{label}</span>', 20 '</div>' 21 ); 22 23 this.tools.each( 24 function(tool) { 25 if (!tool.clone) { // don't add clones to the tool panel 26 toolsHTML += toolsTemplate.apply({id: tool.id, icon: tool.icon, label: tool.label, summary: tool.label + (tool.description ? ": " + tool.description : "")}); 27 } 28 }, 29 this); 30 31 toolsHTML += '</div>'; 32 33 this.toolsPanel = new Ext.Panel({ 34 id: 'tools-panel', 35 collapsible: true, 36 titleCollapse: true, 37 autoScroll: true, 38 region: 'south', 39 title: 'tools', 40 height: 130, 41 html: toolsHTML 42 }); 43 44 this.initialToolset = null; 45 46 // keeps track of the tools for each "step" in the workflow 47 this.toolsteps = new Ext.util.MixedCollection(); 48 // has an existing toolset been modified? 49 this.modifiedToolset = false; 50 51 this.toolsetEditorPanel = new Ext.Panel({ 52 id: 'toolsetEditorPanel', 53 border: false, 54 region: 'center', 55 margins: '0 10 0 0', 56 html: 57 //'<span id="toolsetLabel"></span>'+ 58 '<div id="toolsetEditor" style="width: 100%; height: 97%; overflow: auto; float: left; clear: both;"></div>' 59 }); 60 61 this.panel = new Ext.Panel({ 62 id: 'editorParentPanel', 63 layout: 'border', 64 defaults: { 65 border: false 66 }, 67 items: [ 68 { 69 title: '', 70 height: 70, 71 region: 'north', 72 html: '<h2 id="toolsetLabel"></h2>'+ 73 '<div id="toolsetMenuBar">'+ 74 '</div>'+ 75 '<div style="clear: both;"></div>' 76 }, 77 this.toolsetEditorPanel, 78 this.toolsPanel 79 ] 80 }); 81 82 this.saveDialog = null; 83 84 this.toolsetSelected = function(action) { 85 var actionName = action || 'perform an action on'; 86 if (this.projectToolsets.selectedToolset == null) { 87 Monk.component.messenger.alert('Monk Workbench', 'You must select a toolset before you can '+actionName+' it.'); 88 return false; 89 } else { 90 return true; 91 } 92 } 93 94 this.toolsetCreated = function(action) { 95 var actionName = action || 'perform an action on'; 96 if (this.toolsteps.getCount() == 0) { 97 Monk.component.messenger.alert('Monk Workbench', 'You must create a toolset before you can '+actionName+' it.'); 98 return false; 99 } else { 100 return true; 101 } 102 } 103 104 this.fadeInToolstep = function(toolstepIndex) { 105 // TODO fix in Opera 106 var toolstep = this.toolsteps.get(toolstepIndex); 107 if (toolstep) { 108 var toolstepEl = Ext.get(toolstep.id); 109 110 toolstepEl.shift({ 111 opacity: 1, 112 duration: 0.3, 113 callback: function(){ 114 toolstepEl.removeClass('invisible'); 115 } 116 }); 117 118 toolstepIndex++; 119 120 this.fadeInToolstep.defer(150, this, [toolstepIndex]); 121 } 122 } 123 124 this.afterRenderFirstTime = function() { 125 var buttonParent = Ext.get('toolsetMenuBar'); 126 127 var newButton = new Ext.Button({ 128 id: 'newToolsetButton', 129 text: 'new', 130 renderTo: buttonParent, 131 handler: function(){ 132 Monk.component.messenger.confirm('Monk Workbench', 'This will create a new, empty, toolset. Do you wish to continue?', function(btn){ 133 if (btn == 'yes') this.reset(); 134 }, this, this.window); 135 }, 136 scope: this 137 }); 138 139 var saveButton = new Ext.Button({ 140 id: 'saveToolsetButton', 141 text: 'save', 142 renderTo: buttonParent, 143 handler: function(){ 144 if (this.toolsetCreated('save')) { 145 if (this.projectToolsets.selectedToolset == null) { 146 if (this.saveDialog == null) { 147 this.initializeSaveDialog(); 148 } else { 149 this.saveDialog.show(); 150 } 151 } else { 152 if (this.projectToolsets.isToolsetDefault(this.projectToolsets.selectedToolset)) { 153 if (this.saveDialog == null) { 154 this.initializeSaveDialog(); 155 } else { 156 this.saveDialog.show(); 157 } 158 } else { 159 this.saveToolset({toolsetId: this.projectToolsets.selectedToolset}); 160 } 161 } 162 } 163 }, 164 scope: this 165 }); 166 167 var saveAsButton = new Ext.Button({ 168 id: 'saveAsToolsetButton', 169 text: 'save as', 170 renderTo: buttonParent, 171 handler: function(){ 172 if (this.toolsetSelected('save a copy of')) { 173 if (this.saveDialog == null) { 174 this.initializeSaveDialog(); 175 } else { 176 this.saveDialog.show(); 177 } 178 } 179 }, 180 scope: this 181 }); 182 183 var deleteButton = new Ext.Button({ 184 id: 'deleteToolsetButton', 185 text: 'delete', 186 renderTo: buttonParent, 187 handler: function(){ 188 if (this.toolsetSelected('delete')) { 189 if (feature.toolsets.get(this.projectToolsets.selectedToolset) != null) { 190 Monk.component.messenger.alert('Monk Workbench', 'You cannot delete a default toolset.'); 191 } else { 192 Monk.component.messenger.confirm('Monk Workbench', 'Are you sure you want to delete this toolset?', function(btn){ 193 if (btn == 'yes') { 194 Monk.data.toolset.deleteToolset(this.projectToolsets.selectedToolset); 195 } 196 }, this, this.window); 197 } 198 } 199 }, 200 scope: this 201 }); 202 203 var exportButton = new Ext.Button({ 204 id: 'exportToolsetButton', 205 text: 'export', 206 renderTo: buttonParent, 207 disabled: true, 208 handler: function(){ 209 if (this.toolsetSelected('export')) { 210 Monk.component.messenger.alert('Monk Workbench', 'Not yet implemented.'); 211 } 212 }, 213 scope: this 214 }); 215 216 var moveButton = new Ext.Button({ 217 id: 'moveToolsetButton', 218 text: 'move', 219 renderTo: buttonParent, 220 disabled: true, 221 handler: function(){ 222 if (this.toolsetSelected('move')) { 223 Monk.component.messenger.alert('Monk Workbench', 'Not yet implemented.'); 224 } 225 }, 226 scope: this 227 }); 228 229 // set the toolset label 230 // var labelField = new Ext.form.InlineTextField({ 231 // id: 'toolsetLabelField', 232 // saveOnlyOnChange: true, 233 // value: this.label, 234 // grow: true, 235 // cls: 'header' 236 // }); 237 // 238 // labelField.saveMethod = function(toolsetEditor) { 239 // var label = this.getValue(); 240 // toolsetEditor.label = label; 241 // }.createDelegate(labelField, [this]); 242 // 243 // // update the toolbar button when the toolset name changes 244 // labelField.on('change', function(field, newVal, oldVal){ 245 // //feature.flowManager.setButtonLabel(this.id, newVal); 246 // }, this); 247 // 248 // labelField.render(Ext.get('toolsetLabel')); 249 250 this.initializeDragDrop(); 251 } 252 253 this.initializeToolsteps = function() { 254 if (this.initialToolset.tools.length > 0) { 255 for (var i = 0; i < this.initialToolset.tools.length; i++) { 256 var initialToolstep = this.initialToolset.tools[i]; 257 var components = initialToolstep.components; 258 259 var newToolstep = null; 260 if (i == 0) { 261 newToolstep = this.createToolstep(null, initialToolstep, true); 262 } else { 263 var siblingEl = Ext.get(this.toolsteps.itemAt(i - 1).id) 264 newToolstep = this.createToolstep(siblingEl, initialToolstep, true); 265 } 266 267 for (var j = 0; j < components.length; j++) { 268 var component = components[j]; 269 // remove the clone append if it exists 270 component = component.split('-clone')[0]; 271 var componentEl = Ext.get(component); 272 if (componentEl == null) { 273 Monk.component.messenger.alert( 274 'Monk Workbench', 275 'This toolset contains an unknown tool ('+component+') which cannot be loaded.' 276 ); 277 } else { 278 this.handleToolTransfer(newToolstep, componentEl); 279 } 280 } 281 } 282 283 this.updateToolstepNumbers(); 284 285 this.fadeInToolstep(0); 286 } 287 } 288 289 this.afterRenderEveryTime = function() { 290 var continueButton = Ext.getCmp('universal-continue-button'); 291 continueButton.setHandler( 292 this.loadToolset, 293 this 294 ); 295 296 this.saveDialog = null; 297 298 if (this.toolsteps.getCount() == 0) { 299 this.setToolsetLabel('new toolset'); 300 301 var toolset = this.projectToolsets.getToolset(this.projectToolsets.selectedToolset); 302 if (toolset != null) { 303 this.initialToolset = toolset; 304 this.setToolsetLabel(toolset.label); 305 this.initializeToolsteps(); 306 } 307 } 308 } 309 310 Monk.component.ToolsetEditor.superclass.constructor.call(this, args); 311 } 312 313 Workbench.extend(Monk.component.ToolsetEditor, Monk.component.Component, { 314 315 id: 'toolset-editor', 316 label: 'Toolset Editor', 317 "window": this.window, 318 319 handle : function(monkEvent, data) { 320 if (monkEvent.instanceOf(Monk.event.toolset.ToolsetSelected)) { 321 if (this.isVisible()) { 322 this.reset(); 323 324 if (data.selected) { 325 this.initialToolset = data.toolset; 326 this.setToolsetLabel(data.toolset.label); 327 this.initializeToolsteps(); 328 329 Ext.getCmp('saveAsToolsetButton').enable(); 330 } else { 331 Ext.getCmp('saveAsToolsetButton').disable(); 332 } 333 } 334 } else if (monkEvent.instanceOf(Monk.event.toolset.ToolsetDeleted)) { 335 this.reset(); 336 } else if (monkEvent.instanceOf(Monk.event.toolset.ToolsetCreated)) { 337 if (this.isVisible()) { 338 var toolset = data.toolsetJson; 339 340 toolset.id = data.toolsetId; 341 toolset.label = toolset.toolSetLabel; 342 343 delete toolset.toolSetLabel; 344 delete toolset.toolSetConfig; 345 346 Monk.component.dataManager.getProjectData().toolsets.add(toolset.id, toolset); 347 348 this.setToolsetLabel(toolset.label); 349 } 350 } else if (monkEvent.instanceOf(Monk.event.toolset.ToolsetSaved)) { 351 if (this.isVisible()) { 352 var toolset = data.toolsetJson; 353 354 toolset.label = toolset.toolSetLabel; 355 356 delete toolset.toolSetLabel; 357 delete toolset.toolSetConfig; 358 359 Monk.component.dataManager.getProjectData().toolsets.replace(data.toolsetId, toolset); 360 361 this.setToolsetLabel(toolset.label); 362 } 363 } else if (monkEvent.instanceOf(Monk.event.toolset.LoadToolset)) { 364 this.loadToolset(); 365 } 366 }, 367 368 // setProjectLabel : function(label) { 369 // this.label = label; 370 // feature.flowManager.setButtonLabel(this.id, label); 371 // }, 372 373 /** 374 * Save/create a toolset 375 * @param {Object} config An object containing toolset properties 376 * @config {String} label The toolset label 377 * @config {String} worksetId A number representing the workset ID 378 * @config {String} toolsetId A number representing the toolset ID 379 * @config {Boolean} shareable Where to share this toolset with other users 380 * @config {String} description A description of the toolset 381 * If this is present, the toolset will be updated. Otherwise, a new toolset will be created. 382 */ 383 saveToolset : function(config) { 384 var toolsetConfig = {}; 385 386 if (config.toolsetId != null) { 387 toolsetConfig = this.projectToolsets.getToolset(config.toolsetId); 388 toolsetConfig.toolSetLabel = this.label; 389 } else { 390 toolsetConfig.worksetId = config.worksetId; 391 toolsetConfig.toolSetLabel = config.label; 392 toolsetConfig.shareable = config.shareable != null ? config.shareable : true; 393 toolsetConfig.pathToIcon = config.pathToIcon || 'resources/images/toolsets/Toolset-default.gif'; 394 toolsetConfig.description = config.description; 395 } 396 397 var tempTools = this.createToolsetConfig(); 398 var tools = []; 399 tempTools.tools.each(function(item, index, length){ 400 tools.push(item); 401 }); 402 toolsetConfig.tools = tools; 403 404 if (config.toolsetId != null) { 405 Monk.data.toolset.saveToolset(config.toolsetId, toolsetConfig); 406 } else { 407 Monk.data.toolset.createToolset(toolsetConfig); 408 } 409 }, 410 411 initializeSaveDialog : function() { 412 var projectId = Monk.component.dataManager.getProjectId(); 413 414 415 var xmlReader = new Ext.data.XmlReader({ 416 record: 'workset', 417 id: '@id' 418 }, [ 419 {name: 'id', mapping: '@id'}, 420 'label' 421 ] 422 ); 423 424 var worksetsStore = new Ext.data.Store({ 425 reader: xmlReader, 426 autoLoad: true, 427 proxy: new Ext.data.HttpProxy({ 428 url: Monk.data.PROXY_URL + 'get/ProjectManager.getWorksets', 429 method: 'GET' 430 }), 431 baseParams: {projectId: projectId} 432 }); 433 434 var worksetsCombo = new Ext.form.ComboBox({ 435 fieldLabel: 'Workset', 436 name: 'workset', 437 width: 175, 438 store: worksetsStore, 439 triggerAction: 'all', 440 mode: 'local', 441 allowBlank: false, 442 editable: false, 443 forceSelection: true, 444 displayField: 'label', 445 hiddenName: 'worksetId', 446 valueField: 'id' 447 }); 448 449 var labelField = new Ext.form.TextField({ 450 fieldLabel: 'Label', 451 name: 'label', 452 width: 175, 453 value: this.label, 454 allowBlank: false 455 }); 456 457 var sharedRadioGroup = new Ext.ux.RadioGroup({ 458 fieldLabel: 'Privacy', 459 name: 'shareable', 460 horizontal: true, 461 width: 175, 462 radios: [{ 463 value: 1, 464 boxLabel: 'Public', 465 checked: true 466 },{ 467 value: 0, 468 boxLabel: 'Private' 469 } 470 ] 471 }); 472 473 var imageUrl = new Ext.form.TextField({ 474 fieldLabel: 'Icon (URL)', 475 name: 'pathToIcon', 476 width: 175, 477 disabled: true, 478 // regex for image match 479 regex: /(http:\/\/)([a-zA-Z0-9\-_\.]+(\.(com|edu|gov|net|org|biz|info|name|museum|co\.uk)))(\/(?!\/))(([a-zA-Z0-9\-_\/]*)?)([a-zA-Z0-9])+\.((jpg|jpeg|gif|png)(?!(\w|\W)))/, 480 regexText: "This doesn't look like a valid image URL. Make sure it starts with 'http://'." 481 }); 482 // ANDREW: I commented the value -causes exception when creating 483 // new toolset 484 var description = new Ext.form.TextArea({ 485 fieldLabel: 'Toolset Description', 486 name: 'description', 487 width: 175, 488 height: 80, 489 maxLength: 500 490 // value: this.initialToolset.description 491 }); 492 493 var saveForm = new Ext.form.FormPanel({ 494 labelAlign: 'right', 495 labelWidth: 70, 496 border: false 497 }); 498 499 saveForm.add({ 500 xtype: 'panel', 501 border: false, 502 html: '<div style="padding: 5px;">Select a workset to associate your toolset with.</div>' 503 }); 504 saveForm.add(worksetsCombo); 505 saveForm.add(labelField); 506 saveForm.add(sharedRadioGroup); 507 saveForm.add(description); 508 //saveForm.add(imageUrl); 509 510 this.saveDialog = new Ext.Window({ 511 title: 'Save Toolset', 512 height: 250, 513 width: 300, 514 modal: true, 515 shadow: true, 516 plain: true, 517 border: false, 518 collapsible: false, 519 items: saveForm, 520 buttons: [ 521 { 522 text: 'Save', 523 handler: function(){ 524 if (saveForm.getForm().isValid()) { 525 var values = saveForm.getForm().getValues(); 526 // convert to boolean 527 values.shareable = values.shareable == '1' ? true : false; 528 this.saveToolset(values); 529 530 saveForm.getForm().reset(); 531 this.saveDialog.hide(); 532 } 533 }, 534 scope: this 535 }, 536 { 537 text: 'Cancel', 538 handler: function(){ 539 this.saveDialog.hide(); 540 }, 541 scope: this 542 } 543 ] 544 }); 545 546 this.saveDialog.show(); 547 }, 548 549 /** 550 * Create a config for Monk.component.Toolset based on a toolset object 551 * @param {String} [toolsetId] If included, create a config for a saved toolset, otherwise, create a config for a new toolset 552 */ 553 createToolsetConfig : function(toolsetId) { 554 var config = {}; 555 if (toolsetId != null) { 556 config = Monk.component.dataManager.createToolsetConfig(toolsetId); 557 } else { 558 config.tools = new Ext.util.MixedCollection(); 559 this.toolsteps.each( 560 function(tool) { 561 var tools = tool.tools; 562 var toolNames = []; 563 for (var toolId in tools) { 564 // get rid of the appended underscore & number 565 toolId = toolId.split('_')[0]; 566 // check for clones 567 if (toolNames.indexOf(toolId) != -1) { 568 toolId = toolId + '-clone'; 569 } 570 toolNames.push(toolId); 571 } 572 var processedTool = { 573 id: tool.id, 574 label: tool.label, 575 components: toolNames, 576 helpUrl: tool.helpUrl 577 }; 578 config.tools.add(tool.id, processedTool); 579 }, 580 this); 581 config.label = this.label; 582 } 583 584 return config; 585 }, 586 587 setToolsetLabel : function(label) { 588 this.label = label; 589 Ext.getDom('toolsetLabel').innerHTML = label; 590 //feature.flowManager.setButtonLabel(this.id, label); 591 }, 592 593 /** 594 * Creates a new toolstep. 595 * @param {Ext.Element} siblingToolstep The sibling of this toolstep 596 * @param {Object} config A config object containing label and help url 597 * @param {String} config.label The label for this toolstep 598 * @param {String} config.helpUrl The help url for this toolstep 599 * @param {Boolean} invisible Whether the toolstep should be invisible initially 600 */ 601 createToolstep : function(siblingToolstep, config, invisible) { 602 var thisConfig = config == null ? {label: 'Tool Label', helpUrl: null} : config; 603 this.modifiedToolset = true; 604 605 // give the toolset a default name if it's new 606 if (this.label == '') {// && !Ext.getCmp('toolsetLabelField').isDirty()) { 607 this.setToolsetLabel('new toolset'); 608 } 609 610 var toolstep = null; 611 var index = null; 612 var toolLabel = thisConfig.label; 613 var helpUrl = thisConfig.helpUrl; 614 615 var toolstepClass = 'toolstep-row'; 616 if (invisible) toolstepClass = 'toolstep-row invisible'; 617 618 if (!siblingToolstep) { 619 // then it's the first toolstep 620 index = 0; 621 var parent = Ext.get('toolsetEditor'); 622 toolstep = parent.createChild({cls:toolstepClass}); 623 } else { 624 var siblingId = siblingToolstep.id; 625 index = this.toolsteps.indexOfKey(siblingId) + 1; 626 toolstep = siblingToolstep.next().insertSibling({cls:toolstepClass}, 'after'); 627 } 628 629 // remove the ext generated id and create a more useable one 630 toolstep.dom.removeAttribute('id'); 631 toolstep.id = Ext.id(toolstep, 'toolstep-'); 632 //Ext.DomHelper.insertHtml('afterBegin', toolstep.dom, '<span>'+toolstep.id+'</span>'); 633 634 var fieldParent = toolstep.createChild({style:'float: left; width: 100px;'}); 635 636 var labelField = new Ext.form.InlineTextArea({ 637 saveOnlyOnChange: true, 638 value: toolLabel, 639 width: 95, 640 height: 'auto', 641 preventScrollbars: true, 642 style: "margin:5px;padding:0;float:left;", 643 grow: true, 644 growMin: 0, 645 growAppend: '' 646 }); 647 648 labelField.saveMethod = function(toolsetEditor) { 649 // assign the label to the appropriate toolstep entry 650 var label = this.getValue(); 651 var toolstepId = this.getEl().findParent('div.toolstep-row', 3, true).id; 652 toolsetEditor.toolsteps.get(toolstepId).label = label; 653 }.createDelegate(labelField, [this]); 654 655 labelField.render(fieldParent); 656 labelField.autoSize(); 657 658 var helpUrlField = new Ext.form.InlineTextField({ 659 saveOnlyOnChange: true, 660 value: helpUrl, 661 emptyText: 'URL for step help', 662 regex: /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$/, 663 regexText: "This doesn't look like a valid URL. Make sure it starts with 'http://'.", 664 width: 95, 665 height: 'auto', 666 preventScrollbars: true, 667 style: "margin:5px;padding:0;float:left;clear:left;", 668 grow: false, 669 growMin: 0, 670 growAppend: '' 671 }); 672 673 helpUrlField.saveMethod = function(toolsetEditor) { 674 // assign the url to the appropriate toolstep entry 675 if (this.isValid()) { 676 var url = this.getValue(); 677 var toolstepId = this.getEl().findParent('div.toolstep-row', 3, true).id; 678 toolsetEditor.toolsteps.get(toolstepId).helpUrl = url; 679 } 680 }.createDelegate(helpUrlField, [this]); 681 682 helpUrlField.render(fieldParent); 683 helpUrlField.autoSize(); 684 685 var closeButton = toolstep.createChild({cls: 'x-tool x-tool-close', title: 'Remove Toolstep'}); 686 closeButton.on('click', function(){ 687 this.deleteToolstep(toolstep); 688 }, this); 689 690 var number = toolstep.createChild({id:toolstep.id+'-number', cls:'toolstep-number'}); 691 692 var gap = toolstep.insertSibling({cls:'toolstep-gap'}, 'after'); 693 gap.dom.removeAttribute('id'); 694 gap.id = Ext.id(gap, 'gap-'); 695 696 var columnDropzone = new Ext.dd.DropZone(toolstep.id, {ddGroup:'toolsDD'}); 697 var gapDropzone = new Ext.dd.DropZone(gap.id, {ddGroup:'toolsDD'}); 698 699 this.toolsteps.insert(index, toolstep.id, {id: toolstep.id, tools:{}, label: toolLabel, helpUrl: helpUrl}); 700 701 this.updateToolstepNumbers(); 702 703 return toolstep; 704 }, 705 706 deleteToolstep : function(toolstep) { 707 this.modifiedToolset = true; 708 709 try { 710 this.toolsteps.removeKey(toolstep.id); 711 712 var toolstepEl = Ext.get(toolstep.id); 713 var gapEl = toolstepEl.next(); 714 toolstepEl.remove(); 715 gapEl.remove(); 716 717 this.updateToolstepNumbers(); 718 } catch (e) { 719 720 } 721 }, 722 723 /** 724 * Handle transfer of tools between toolsteps and tool parent, etc. 725 * @param {Object} target The receiving target Element 726 * @param {Ext.Element} toolEl The tool to transfer 727 */ 728 handleToolTransfer : function(target, toolEl) { 729 // TODO: check if previous toolstep is empty 730 this.modifiedToolset = true; 731 732 var flagForDeletion = false; // set if we need to delete the toolstep at the end of this method 733 var newToolEl = toolEl; 734 735 var oldLocation = toolEl.parent(); 736 var oldLocationId = oldLocation.id; 737 if (oldLocationId.split('-')[0] == 'toolstep') { 738 // delete tool from toolstep 739 delete this.toolsteps.get(oldLocationId).tools[toolEl.id]; 740 741 // check to see if any tools remain in this toolstep, if not, then delete it 742 var toolsCounter = 0; 743 for (var key in this.toolsteps.get(oldLocationId).tools) { 744 toolsCounter++; 745 break; 746 } 747 if (toolsCounter == 0) { 748 // delete the toolstep after we've moved the tool 749 flagForDeletion = true; 750 } 751 } else if (oldLocationId == 'toolsParent' && target.id != 'toolsParent') { 752 // copy the tool 753 newToolEl = toolEl.dom.cloneNode(true); 754 // generate a unique ID for the clone 755 var oldId = toolEl.id; 756 newToolEl.removeAttribute('id'); 757 var cloneId = Ext.id(newToolEl, oldId+'_'); 758 newToolEl.setAttribute('id', cloneId); 759 } else { 760 // we're moving the tool, don't make any changes 761 } 762 763 if (target.id != 'toolsParent') { 764 target.setStyle({height: 'auto'}); 765 target.appendChild(newToolEl); 766 this.toolsteps.get(target.id).tools[newToolEl.id] = true; 767 768 // make it drag n droppable 769 newToolEl = Ext.get(newToolEl); 770 newToolEl.dd = new Ext.ux.EditorDDProxy(cloneId, 'toolsDD', {isTarget: false}); 771 newToolEl.dd.constrain(newToolEl); 772 newToolEl.applyStyles({position:'', width:''}); 773 774 // add delete context menu 775 newToolEl.on('contextmenu', function(event, el){ 776 event.preventDefault(); 777 var menu = new Ext.menu.Menu([{ 778 text: 'Remove Tool', 779 iconCls: 'delete-tool', 780 handler : function(){ 781 var toolsParent = Ext.get('toolsParent'); 782 this.handleToolTransfer(toolsParent, newToolEl); 783 }, 784 scope: this 785 }]); 786 menu.showAt(event.getPoint()); 787 }, this); 788 } else if (oldLocationId != 'toolsParent') { 789 // if no toolstepIndex, then we're moving the tool back to the tool list 790 newToolEl.remove(); 791 } 792 793 if (flagForDeletion) { 794 this.deleteToolstep(oldLocation); 795 } 796 }, 797 798 /** 799 * Set the number for each step, based on their index 800 */ 801 updateToolstepNumbers : function() { 802 this.toolsteps.each(function(item, index, length) { 803 var toolstep = Ext.get(item.id); 804 Ext.get(toolstep.id+'-number').update(index + 1); 805 }, this); 806 }, 807 808 // called after tools have been rendered 809 initializeDragDrop : function() { 810 var editorDropzone = new Ext.dd.DropZone('toolsetEditor', {ddGroup:'toolsDD'}); 811 var toolDropzone = new Ext.dd.DropZone('toolsParent', {ddGroup:'toolsDD'}); 812 813 // custom drag n drop proxy 814 Ext.ux.EditorDDProxy = Ext.extend(Ext.dd.DDProxy, { 815 parent : this, 816 817 // custom methods 818 showPreview: function(target) { 819 if (!this.previewEl) { 820 this.previewEl = target.createChild({cls:'dd-preview'}); 821 } 822 if (target.dom.className == 'toolstep-gap') { 823 // increase the width of the gap (fix for opera) 824 target.setStyle({width:'50%'}); 825 } 826 target.setStyle({'background-color':'#eeeeee'}); 827 }, 828 829 hidePreview: function() { 830 if (this.previewEl) { 831 this.previewEl.parent().setStyle({'background-color':'#fff'}); 832 this.previewEl.remove(); 833 delete this.previewEl; 834 } 835 }, 836 837 // constrain dragging to the barriers of the screen 838 constrain: function(element) { 839 var windowWidth = Ext.lib.Dom.getViewWidth(); 840 var windowHeight = Ext.lib.Dom.getViewHeight(); 841 var leftConstraint = element.getX(); 842 var rightConstraint = windowWidth - leftConstraint - element.getWidth(); 843 var topConstraint = element.getY(); 844 var bottomConstraint = windowHeight - topConstraint - element.getHeight(); 845 this.setXConstraint(leftConstraint, rightConstraint); 846 this.setYConstraint(topConstraint, bottomConstraint); 847 }, 848 849 // overrides of DDProxy methods 850 startDrag: function(x, y) { 851 var dragEl = Ext.get(this.getDragEl()); 852 var el = Ext.get(this.getEl()); 853 854 dragEl.applyStyles({border:'','z-index':2000}); 855 dragEl.update(el.dom.innerHTML); 856 dragEl.addClass(el.dom.className + ' dd-proxy'); 857 }, 858 859 onDragOver: function(e, targetId) { 860 if (this.id != targetId) { 861 if ('toolsetEditor' === targetId){ 862 var index = this.parent.toolsteps.getCount() - 1; 863 if (index == -1) { 864 // no toolsteps yet, use toolsetEditor as target 865 var target = Ext.get(targetId); 866 this.lastTarget = target; 867 this.showPreview(target); 868 } else { 869 // otherwise use the last toolstep gap as target 870 targetId = this.parent.toolsteps.get(index).id 871 var target = Ext.get(targetId).next(); 872 target.setStyle({height:'auto'}); 873 this.lastTarget = target; 874 this.hidePreview(); 875 this.showPreview(target); 876 } 877 } else if (targetId.split('-')[0] == 'gap') { 878 var target = Ext.get(targetId); 879 if (target != this.lastTarget) { 880 target.setStyle({height:'auto'}); 881 this.lastTarget = target; 882 this.hidePreview(); 883 this.showPreview(target); 884 } 885 } else { 886 // we're in a toolstep or the tool list (toolParent) 887 var target = Ext.get(targetId); 888 // test if we're in the tool's current toolstep 889 if (target.contains(this.getEl())) { 890 this.lastTarget = target; 891 this.hidePreview(); 892 } else { 893 if (target != this.lastTarget) { 894 this.lastTarget = target; 895 this.hidePreview(); 896 this.showPreview(target); 897 } 898 } 899 } 900 } 901 }, 902 onDragOut: function(e, targetId) { 903 if (this.lastTarget) { 904 if (this.lastTarget.id.split('-')[0] == 'gap') { 905 this.lastTarget.setStyle({width:'50%'}); 906 this.lastTarget.setHeight(20); 907 } 908 } 909 if('toolsetEditor' === targetId || 'toolsParent' === targetId) { 910 var target = Ext.get(targetId); 911 this.lastTarget = null; 912 this.hidePreview(); 913 } else { 914 var target = Ext.get(targetId); 915 this.lastTarget = null; 916 this.hidePreview(); 917 } 918 }, 919 920 endDrag: function() { 921 this.hidePreview(); 922 923 var dragEl = Ext.get(this.getDragEl()); 924 var el = Ext.get(this.getEl()); 925 926 if (this.lastTarget) { 927 // tool dropped on the editor 928 if (this.lastTarget.id == 'toolsetEditor'){ 929 var index = this.parent.toolsteps.getCount() - 1; 930 var newToolstep = this.parent.createToolstep(); 931 this.parent.handleToolTransfer(newToolstep, el); 932 933 // tool dropped on a gap in between toolsteps 934 } else if (this.lastTarget.id.split('-')[0] == 'gap') { 935 var gap = Ext.get(this.lastTarget); 936 var target = gap.prev(); // get toolstep before this gap 937 var newToolstep = this.parent.createToolstep(target); 938 var newGap = newToolstep.prev(); 939 newGap.setHeight(20); 940 this.parent.handleToolTransfer(newToolstep, el); 941 942 // tool dropped on the tool list 943 } else if (this.lastTarget.id == 'toolsParent') { 944 var toolsParent = Ext.get(this.lastTarget); 945 this.parent.handleToolTransfer(toolsParent, el); 946 947 // tool dropped in an existing toolstep 948 } else { 949 var toolstep = Ext.get(this.lastTarget); 950 // test if the toolstep contained the tool initially 951 if (!toolstep.contains(el.dom)) { 952 this.parent.handleToolTransfer(toolstep, el); 953 } 954 } 955 } else { 956 // no lastTarget 957 } 958 } 959 }); 960 961 this.tools.each( 962 function(tool) { 963 if (!tool.clone) { 964 var toolDD = Ext.get(tool.id); 965 toolDD.dd = new Ext.ux.EditorDDProxy(tool.id, 'toolsDD', {isTarget: false}); 966 toolDD.dd.constrain(toolDD); 967 } 968 }, this); 969 970 }, 971 972 /** 973 * Load a toolset. 974 * @param {Boolean} savedToolset Is the toolset one of the previously saved ones? Or is it a new (unsaved) toolset. 975 */ 976 loadToolset : function() { 977 var config = null; 978 if (this.projectToolsets.selectedToolset != null && !this.modifiedToolset) { 979 config = this.createToolsetConfig(this.projectToolsets.selectedToolset); 980 Ext.get('toolset-'+this.projectToolsets.selectedToolset).removeClass('selected'); 981 } else { 982 // see if there's anything in the toolset editor 983 config = this.createToolsetConfig(); 984 } 985 if (config.tools.getCount() == 0) { 986 Monk.component.messenger.alert('Monk Workbench', 'You must select or create a toolset before you can continue.'); 987 } else { 988 var toolsetObject = new Monk.component.Toolset(config); 989 Monk.component.dataManager.setToolsetId(toolsetObject.id); 990 feature.toolFlowManager.setToolset(toolsetObject); 991 feature.flowManager.addStep(feature.toolFlowManager, false); 992 feature.flowManager.goToStep(feature.toolFlowManager.id); 993 } 994 }, 995 996 /** 997 * Resets everything back to the factory state. 998 */ 999 reset : function() { 1000 this.setToolsetLabel('new toolset'); 1001 1002 this.initialToolset = null; 1003 1004 this.toolsteps.each(function(toolstep) { 1005 this.deleteToolstep(toolstep); 1006 }, this); 1007 1008 this.toolsteps.clear(); 1009 1010 this.modifiedToolset = false; 1011 1012 //Ext.getCmp('toolsetLabelField').destroy(); 1013 1014 //this.afterRenderFirstTimeCalled = false; 1015 } 1016 1017 });