1 /** 2 * @class A manager for workflow. Handles transitions between steps in the flow. 3 * Contains the initial workbench screen. 4 * @extends Monk.component.Component 5 * @author Andrew 6 * 7 * @property {Ext.util.MixedCollection} steps A list containing all the steps in the workflow. 8 * @property {String} currentStep The ID of the step currently being viewed. 9 * @property {Ext.Panel} panel This is the container for all the steps in the flow, the toolbar for the steps, and the universal continue button. 10 * An {@link Ext.ux.AnimatedCardLayout} is used to switch between steps. 11 */ 12 Monk.component.FlowManager = function(args) { 13 14 this.steps = new Ext.util.MixedCollection(); 15 this.currentStep = ''; 16 17 var home = new Monk.component.ProjectSelector(); 18 19 this.panel = new Ext.Panel({ 20 id: 'main-panel', 21 collapsible: false, 22 layout: 'animatedcard', 23 activeItem: 0, 24 border: false, 25 tbar: [{ 26 xtype:'tbcustomfill', 27 width: '110px' 28 }], 29 bbar: [{ 30 id: 'universal-previous-button', 31 text: '« previous', 32 scope: this 33 },{ 34 xtype: 'tbfill' 35 },{ 36 id: 'universal-continue-button', 37 text: 'continue »', 38 scope: this 39 }], 40 items: home.panel 41 }); 42 43 this.panel.on('render', function(panel){ 44 panel.getBottomToolbar().setHeight(40); 45 46 /** 47 * Removes an item from the toolbar 48 * @param {String|Integer} key The ID/index of the item. 49 */ 50 panel.getTopToolbar().remove = function(item) { 51 if(this.rendered && item){ 52 if(item.destroy)item.destroy(); 53 if(item.removeListeners)item.removeListeners(); 54 55 //all items are contained by a <TD> tag, so might need: 56 if(item.dom && item.dom.parentNode){ 57 var td = item.dom.parentNode; 58 td.removeChild(item.dom); 59 td.parentNode.removeChild(td); 60 } 61 62 this.items.remove(item); 63 } 64 }; 65 66 // add the panel to the list of steps 67 this.addStep(home); 68 }, this); 69 70 Monk.component.FlowManager.superclass.constructor.call(this, args); 71 } 72 73 Workbench.extend(Monk.component.FlowManager, Monk.component.Component, { 74 /** @lends Monk.component.FlowManager.prototype */ 75 76 id: 'flow-manager', 77 label : "Flow Manager", 78 79 /** 80 * For moving between steps in the workflow. 81 * @param {String|Integer} key The key or index of the step. 82 * @param {Boolean} [noFade] True to cancel default fade in animation (defaults to false). 83 */ 84 goToStep : function(key, noFade) { 85 var step = this.steps.get(key); 86 87 this.toolbarButtonToggle(step.id); 88 89 // show the panel for the item 90 this.panel.layout.setActiveItem(this.steps.indexOfKey(step.id), noFade); 91 92 var oldStep = this.steps.get(this.currentStep); 93 if (oldStep != null) { 94 // call any function that needs to get called before we leave the old step 95 if (oldStep.beforeExit) oldStep.beforeExit.call(oldStep); 96 // set the previous button to get back to the old step 97 Ext.getCmp('universal-previous-button').setHandler( 98 function() { 99 this.goToStep(oldStep.id); 100 }, 101 this 102 ); 103 } 104 105 this.currentStep = step.id; 106 this.notify(new Monk.event.flowmanager.StepSelected({ 107 label: 'StepSelected: "'+this.currentStep+'"', 108 "component" : this 109 }), this.currentStep); 110 }, 111 112 /** 113 * Set a specific button to appear pressed. 114 * @param {String} buttonId The button ID to use (corresponds to step ID). 115 */ 116 toolbarButtonToggle : function(buttonId) { 117 // set all toolbar items to not pressed 118 var tbar = this.panel.getTopToolbar(); 119 tbar.items.each(function(item, index, length){ 120 if (item.pressed) item.toggle(false); 121 return true; 122 }); 123 124 // press the item that we're moving to 125 var button = tbar.items.get(buttonId); 126 if (button) button.toggle(true); 127 }, 128 129 /** 130 * Check if the user's currently running a toolset, and confirm that they want to exit it. 131 * @param {String|Integer} key The key or index of the step to move to 132 */ 133 withinToolsetCheck : function(key) { 134 if (this.currentStep != key) { 135 if (this.currentStep == 'tool-flow-manager') { 136 if (Monk.component.dataManager.isWorksetUnsaved()) { 137 Monk.component.messenger.confirm( 138 'Monk Workbench', 139 'Navigating away from your toolset will cause you to lose unsaved data. Do you wish to continue?', 140 function(buttonId) { 141 if (buttonId == 'yes') { 142 this.goToStep(key) 143 // hide the search box 144 feature.searchComponent.hide(); 145 } else { 146 // turn off the button that was pressed 147 this.panel.getTopToolbar().items.get(key).toggle(false); 148 }; 149 }, this); 150 } else { 151 this.goToStep(key) 152 // hide the search box 153 feature.searchComponent.hide(); 154 } 155 } else { 156 this.goToStep(key); 157 } 158 } 159 }, 160 161 /** 162 * Adds a step to the flow 163 * @param {Object} nextStep 164 * @param {String} nextStep.id The ID of the step 165 * @param {String} nextStep.label The label for the step 166 * @param {Ext.Panel} nextStep.panel The panel to render 167 * @param {Boolean} [addTBarButton] Whether to add a toolbar button (defaults to true) 168 */ 169 addStep : function(nextStep, addTBarButton) { 170 if (!this.steps.containsKey(nextStep.id)) { 171 // call any function that needs to get called after the panel is rendered 172 nextStep.panel.on('show', function() { 173 if (nextStep.afterRenderFirstTime) { 174 if (nextStep.afterRenderFirstTimeCalled == false) { 175 nextStep.afterRenderFirstTime.call(nextStep); 176 nextStep.afterRenderFirstTimeCalled = true; 177 } 178 } 179 if (nextStep.afterRenderEveryTime) nextStep.afterRenderEveryTime.call(nextStep); 180 }); 181 182 this.steps.add(nextStep.id, nextStep); 183 184 this.panel.add(nextStep.panel); 185 186 if (addTBarButton !== false) { 187 var tbar = this.panel.getTopToolbar(); 188 if (this.steps.getCount() > 1) tbar.addSeparator(); 189 tbar.addButton({ 190 id: nextStep.id, 191 text: nextStep.label, 192 handler: this.withinToolsetCheck.createDelegate(this, [nextStep.id]), 193 enableToggle: true, 194 pressed: false 195 }); 196 } 197 } 198 }, 199 200 /** 201 * Removes a step from the flow 202 * @param {String} stepId The ID of the step 203 */ 204 removeStep : function(stepId) { 205 // remove from toolbar 206 var tbar = this.panel.getTopToolbar(); 207 var step = tbar.items.get(stepId); 208 var separator = tbar.items.get(tbar.items.indexOfKey(stepId)-1); 209 if (step) tbar.remove(step); 210 if (separator) tbar.remove(separator); 211 // remove from steps 212 this.steps.removeKey(stepId); 213 }, 214 215 /** 216 * Removes the specified step, and all steps after it 217 * @param {String} stepId The ID of the step 218 */ 219 trimSteps : function(stepId) { 220 var steps = this.steps.getRange(this.steps.indexOfKey(stepId)); 221 for (var i = 0, len = steps.length; i < len; i++) { 222 this.removeStep(steps[i].id); 223 } 224 }, 225 226 /** 227 * Gets a particular step in the flow. Returns the step, or null if none is found. 228 * @param {String} key The ID of the step to get. 229 * @returns {Object} The step (or null) 230 */ 231 getStep : function(key) { 232 return this.steps.get(key); 233 }, 234 235 /** 236 * Sets the button label for a particular step. 237 * @param {String} stepId The ID of the step 238 * @param {String} label The label to use for the step 239 */ 240 setButtonLabel : function(stepId, label) { 241 var tbar = this.panel.getTopToolbar(); 242 var button = tbar.items.get(stepId); 243 button.setText(label); 244 } 245 }); 246