]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | /**\r |
2 | * @class SimpleTasks.controller.Lists\r | |
3 | * @extends Ext.app.Controller\r | |
4 | */\r | |
5 | Ext.define('SimpleTasks.controller.Lists', {\r | |
6 | extend: 'Ext.app.Controller',\r | |
7 | \r | |
8 | models: ['List'],\r | |
9 | stores: ['Lists', 'Tasks'],\r | |
10 | \r | |
11 | views: [\r | |
12 | 'lists.Tree',\r | |
13 | 'lists.ContextMenu',\r | |
14 | 'Toolbar'\r | |
15 | ],\r | |
16 | \r | |
17 | refs: [\r | |
18 | {\r | |
19 | ref: 'listTree',\r | |
20 | selector: 'listTree'\r | |
21 | },\r | |
22 | {\r | |
23 | ref: 'taskGrid',\r | |
24 | selector: 'taskGrid'\r | |
25 | },\r | |
26 | {\r | |
27 | ref: 'taskForm',\r | |
28 | selector: 'taskForm'\r | |
29 | },\r | |
30 | {\r | |
31 | ref: 'contextMenu',\r | |
32 | selector: 'listsContextMenu',\r | |
33 | xtype: 'listsContextMenu',\r | |
34 | autoCreate: true\r | |
35 | }\r | |
36 | ],\r | |
37 | \r | |
38 | init: function() {\r | |
39 | var me = this,\r | |
40 | listsStore = me.getListsStore();\r | |
41 | \r | |
42 | me.control({\r | |
43 | '[iconCls=tasks-new-list]': {\r | |
44 | click: me.handleNewListClick\r | |
45 | },\r | |
46 | '[iconCls=tasks-new-folder]': {\r | |
47 | click: me.handleNewFolderClick\r | |
48 | },\r | |
49 | '[iconCls=tasks-delete-list]': {\r | |
50 | click: me.handleDeleteClick\r | |
51 | },\r | |
52 | '[iconCls=tasks-delete-folder]': {\r | |
53 | click: me.handleDeleteClick\r | |
54 | },\r | |
55 | 'listTree': {\r | |
56 | afterrender: me.handleAfterListTreeRender,\r | |
57 | edit: me.updateList,\r | |
58 | completeedit: me.handleCompleteEdit,\r | |
59 | canceledit: me.handleCancelEdit,\r | |
60 | deleteclick: me.handleDeleteIconClick,\r | |
61 | selectionchange: me.filterTaskGrid,\r | |
62 | taskdrop: me.updateTaskList,\r | |
63 | listdrop: me.reorderList,\r | |
64 | itemmouseenter: me.showActions,\r | |
65 | itemmouseleave: me.hideActions,\r | |
66 | itemcontextmenu: me.showContextMenu\r | |
67 | }\r | |
68 | });\r | |
69 | \r | |
70 | if(listsStore.isLoading()) {\r | |
71 | listsStore.on('load', me.handleListsLoad, me);\r | |
72 | } else {\r | |
73 | me.handleListsLoad(listsStore);\r | |
74 | }\r | |
75 | listsStore.on('write', me.syncListsStores, me, {\r | |
76 | buffer: 1\r | |
77 | });\r | |
78 | },\r | |
79 | \r | |
80 | /**\r | |
81 | * Handles a click on the "New List" button or context menu item.\r | |
82 | * @param {Ext.Component} component\r | |
83 | * @param {Ext.EventObject} e\r | |
84 | */\r | |
85 | handleNewListClick: function(component, e) {\r | |
86 | this.addList(true);\r | |
87 | },\r | |
88 | \r | |
89 | /**\r | |
90 | * Handles a click on the "New Folder" button or context menu item.\r | |
91 | * @param {Ext.Component} component\r | |
92 | * @param {Ext.EventObject} e\r | |
93 | */\r | |
94 | handleNewFolderClick: function(component, e) {\r | |
95 | this.addList();\r | |
96 | },\r | |
97 | \r | |
98 | /**\r | |
99 | * Adds an empty list to the lists store and starts editing the new list\r | |
100 | * @param {Boolean} leaf True if the new node should be a leaf node.\r | |
101 | */\r | |
102 | addList: function(leaf) {\r | |
103 | var me = this,\r | |
104 | listTree = me.getListTree(),\r | |
105 | cellEditingPlugin = listTree.cellEditingPlugin,\r | |
106 | selectionModel = listTree.getSelectionModel(),\r | |
107 | selectedList = selectionModel.getSelection()[0],\r | |
108 | parentList = selectedList.isLeaf() ? selectedList.parentNode : selectedList,\r | |
109 | newList = Ext.create('SimpleTasks.model.List', {\r | |
110 | name: 'New ' + (leaf ? 'List' : 'Folder'),\r | |
111 | leaf: leaf,\r | |
112 | loaded: true // set loaded to true, so the tree won't try to dynamically load children for this node when expanded\r | |
113 | }),\r | |
114 | expandAndEdit = function() {\r | |
115 | if(parentList.isExpanded()) {\r | |
116 | selectionModel.select(newList);\r | |
117 | me.addedNode = newList;\r | |
118 | cellEditingPlugin.startEdit(newList, 0);\r | |
119 | } else {\r | |
120 | listTree.on('afteritemexpand', function startEdit(list) {\r | |
121 | if(list === parentList) {\r | |
122 | selectionModel.select(newList);\r | |
123 | me.addedNode = newList;\r | |
124 | cellEditingPlugin.startEdit(newList, 0);\r | |
125 | // remove the afterexpand event listener\r | |
126 | listTree.un('afteritemexpand', startEdit);\r | |
127 | }\r | |
128 | });\r | |
129 | parentList.expand();\r | |
130 | }\r | |
131 | };\r | |
132 | \r | |
133 | parentList.appendChild(newList);\r | |
134 | listTree.getStore().sync();\r | |
135 | if(listTree.getView().isVisible(true)) {\r | |
136 | expandAndEdit();\r | |
137 | } else {\r | |
138 | listTree.on('expand', function onExpand() {\r | |
139 | expandAndEdit();\r | |
140 | listTree.un('expand', onExpand);\r | |
141 | });\r | |
142 | listTree.expand();\r | |
143 | }\r | |
144 | },\r | |
145 | \r | |
146 | /**\r | |
147 | * Handles the list list's "edit" event.\r | |
148 | * Updates the list on the server whenever a list record is updated using the tree editor.\r | |
149 | * @param {Ext.grid.plugin.CellEditing} editor\r | |
150 | * @param {Object} e an edit event object\r | |
151 | */\r | |
152 | updateList: function(editor, e) {\r | |
153 | var me = this,\r | |
154 | list = e.record;\r | |
155 | \r | |
156 | list.save({\r | |
157 | success: function(list, operation) {\r | |
158 | // filter the task list by the currently selected list. This is necessary for newly added lists\r | |
159 | // since this is the first point at which we have a primary key "id" from the server.\r | |
160 | // If we don't filter here then any new tasks that are added will not appear until the filter is triggered by a selection change.\r | |
161 | me.filterTaskGrid(me.getListTree().getSelectionModel(), [list]);\r | |
162 | },\r | |
163 | failure: function(list, operation) {\r | |
164 | var error = operation.getError(),\r | |
165 | msg = Ext.isObject(error) ? error.status + ' ' + error.statusText : error;\r | |
166 | \r | |
167 | Ext.MessageBox.show({\r | |
168 | title: 'Update List Failed',\r | |
169 | msg: msg,\r | |
170 | icon: Ext.Msg.ERROR,\r | |
171 | buttons: Ext.Msg.OK\r | |
172 | });\r | |
173 | }\r | |
174 | });\r | |
175 | },\r | |
176 | \r | |
177 | /**\r | |
178 | * Handles the list tree's complete edit event\r | |
179 | * @param {Ext.grid.plugin.CellEditing} editor\r | |
180 | * @param {Object} e an edit event object\r | |
181 | */\r | |
182 | handleCompleteEdit: function(editor, e){\r | |
183 | delete this.addedNode;\r | |
184 | },\r | |
185 | \r | |
186 | /**\r | |
187 | * Handles the list tree's cancel edit event\r | |
188 | * removes a newly added node if editing is cancelled before the node has been saved to the server\r | |
189 | * @param {Ext.grid.plugin.CellEditing} editor\r | |
190 | * @param {Object} e an edit event object\r | |
191 | */\r | |
192 | handleCancelEdit: function(editor, e) {\r | |
193 | var list = e.record,\r | |
194 | parent = list.parentNode,\r | |
195 | added = this.addedNode;\r | |
196 | \r | |
197 | delete this.addedNode;\r | |
198 | if (added === list) {\r | |
199 | // Only remove it if it's been newly added\r | |
200 | parent.removeChild(list);\r | |
201 | this.getListTree().getStore().sync();\r | |
202 | this.getListTree().getSelectionModel().select([parent]);\r | |
203 | }\r | |
204 | },\r | |
205 | \r | |
206 | /**\r | |
207 | * Handles a click on a delete icon in the list tree.\r | |
208 | * @param {Ext.tree.View} view\r | |
209 | * @param {Number} rowIndex\r | |
210 | * @param {Number} colIndex\r | |
211 | * @param {Ext.grid.column.Action} column\r | |
212 | * @param {EventObject} e\r | |
213 | */\r | |
214 | handleDeleteIconClick: function(view, rowIndex, colIndex, column, e) {\r | |
215 | this.deleteList(view.getRecord(view.findTargetByEvent(e)));\r | |
216 | },\r | |
217 | \r | |
218 | /**\r | |
219 | * Handles a click on the "Delete List" or "Delete Folder" button or menu item\r | |
220 | * @param {Ext.Component} component\r | |
221 | * @param {Ext.EventObject} e\r | |
222 | */\r | |
223 | handleDeleteClick: function(component, e) {\r | |
224 | this.deleteList(this.getListTree().getSelectionModel().getSelection()[0]);\r | |
225 | },\r | |
226 | \r | |
227 | /**\r | |
228 | * Deletes a list from the server and updates the view.\r | |
229 | * @param {SimpleTasks.model.List} list\r | |
230 | */\r | |
231 | deleteList: function(list) {\r | |
232 | var me = this,\r | |
233 | listTree = me.getListTree(),\r | |
234 | listName = list.get('name'),\r | |
235 | selModel = listTree.getSelectionModel(),\r | |
236 | tasksStore = me.getTasksStore(),\r | |
237 | listsStore = me.getListsStore(),\r | |
238 | isLocal = SimpleTasks.Settings.useLocalStorage,\r | |
239 | tasks;\r | |
240 | \r | |
241 | Ext.Msg.show({\r | |
242 | title: 'Delete List?',\r | |
243 | msg: 'Are you sure you want to permanently delete the "' + listName + '" list and all its tasks?',\r | |
244 | buttons: Ext.Msg.YESNO,\r | |
245 | fn: function(response) {\r | |
246 | if(response === 'yes') {\r | |
247 | // recursively remove any tasks from the store that are associated with the list being deleted or any of its children.\r | |
248 | (function deleteTasks(list) {\r | |
249 | tasks = tasksStore.queryBy(function(task, id) {\r | |
250 | return task.get('list_id') === list.get('id');\r | |
251 | });\r | |
252 | tasksStore.remove(tasks.getRange(0, tasks.getCount()), !isLocal);\r | |
253 | \r | |
254 | list.eachChild(function(child) {\r | |
255 | deleteTasks(child);\r | |
256 | });\r | |
257 | })(list);\r | |
258 | \r | |
259 | // destroy the tree node on the server\r | |
260 | list.parentNode.removeChild(list);\r | |
261 | listsStore.sync({\r | |
262 | failure: function(batch, options) {\r | |
263 | var error = batch.exceptions[0].getError(),\r | |
264 | msg = Ext.isObject(error) ? error.status + ' ' + error.statusText : error;\r | |
265 | \r | |
266 | Ext.MessageBox.show({\r | |
267 | title: 'Delete List Failed',\r | |
268 | msg: msg,\r | |
269 | icon: Ext.Msg.ERROR,\r | |
270 | buttons: Ext.Msg.OK\r | |
271 | });\r | |
272 | }\r | |
273 | });\r | |
274 | \r | |
275 | if(isLocal) {\r | |
276 | // only need to sync the tasks store when using local storage.\r | |
277 | // when using an ajax proxy we will allow the server to handle deleting any tasks associated with the deleted list(s)\r | |
278 | tasksStore.sync();\r | |
279 | }\r | |
280 | \r | |
281 | // If there is no selection, or the selection no longer exists in the store (it was part of the deleted node(s))\r | |
282 | // then select the "All Lists" root\r | |
283 | if (!selModel.hasSelection() || !listsStore.getNodeById(selModel.getSelection()[0].getId())) {\r | |
284 | selModel.select(0);\r | |
285 | }\r | |
286 | \r | |
287 | // refresh the list view so the task counts will be accurate\r | |
288 | listTree.refreshView();\r | |
289 | }\r | |
290 | }\r | |
291 | });\r | |
292 | \r | |
293 | },\r | |
294 | \r | |
295 | /**\r | |
296 | * Handles the list tree's "selectionchange" event.\r | |
297 | * Filters the task store based on the selected list.\r | |
298 | * @param {Ext.selection.RowModel} selModel\r | |
299 | * @param {SimpleTasks.model.List[]} lists\r | |
300 | */\r | |
301 | filterTaskGrid: function(selModel, lists) {\r | |
302 | if (lists.length === 0) {\r | |
303 | return;\r | |
304 | }\r | |
305 | \r | |
306 | var list = lists[0],\r | |
307 | tasksStore = this.getTasksStore(),\r | |
308 | listIds = [],\r | |
309 | deleteListBtn = Ext.getCmp('delete-list-btn'),\r | |
310 | deleteFolderBtn = Ext.getCmp('delete-folder-btn'),\r | |
311 | i = 0;\r | |
312 | \r | |
313 | // build an array of all the list_id's in the hierarchy of the selected list\r | |
314 | list.cascadeBy(function(list) {\r | |
315 | listIds.push(list.get('id'));\r | |
316 | });\r | |
317 | \r | |
318 | tasksStore.addFilter({\r | |
319 | property: "list_id",\r | |
320 | value: new RegExp('^' + listIds.join('$|^') + '$')\r | |
321 | });\r | |
322 | \r | |
323 | // set the center panel's title to the name of the currently selected list\r | |
324 | this.getTaskGrid().setTitle(list.get('name'));\r | |
325 | \r | |
326 | // enable or disable the "delete list" and "delete folder" buttons depending on what type of node is selected\r | |
327 | if(list.get('id') === -1) {\r | |
328 | deleteListBtn.disable();\r | |
329 | deleteFolderBtn.disable();\r | |
330 | } else if(list.isLeaf()) {\r | |
331 | deleteListBtn.enable();\r | |
332 | deleteFolderBtn.disable();\r | |
333 | } else {\r | |
334 | deleteListBtn.disable();\r | |
335 | deleteFolderBtn.enable();\r | |
336 | }\r | |
337 | \r | |
338 | // make the currently selected list the default value for the list field on the new task form\r | |
339 | this.getTaskForm().query('[name=list_id]')[0].setValue(list.get('id'));\r | |
340 | },\r | |
341 | \r | |
342 | /**\r | |
343 | * Handles the list view's "taskdrop" event. Runs when a task is dragged and dropped on a list.\r | |
344 | * Updates the task to belong to the list it was dropped on.\r | |
345 | * @param {SimpleTasks.model.Task} task The Task record that was dropped\r | |
346 | * @param {SimpleTasks.model.List} list The List record that the mouse was over when the drop happened\r | |
347 | */\r | |
348 | updateTaskList: function(task, list) {\r | |
349 | var me = this,\r | |
350 | listId = list.get('id');\r | |
351 | \r | |
352 | // set the tasks list_id field to the id of the list it was dropped on\r | |
353 | task.set('list_id', listId);\r | |
354 | // save the task to the server\r | |
355 | task.save({\r | |
356 | success: function(task, operation) {\r | |
357 | // refresh the lists view so the task counts will be updated.\r | |
358 | me.getListTree().refreshView();\r | |
359 | },\r | |
360 | failure: function(task, operation) {\r | |
361 | var error = operation.getError(),\r | |
362 | msg = Ext.isObject(error) ? error.status + ' ' + error.statusText : error;\r | |
363 | \r | |
364 | Ext.MessageBox.show({\r | |
365 | title: 'Move Task Failed',\r | |
366 | msg: msg,\r | |
367 | icon: Ext.Msg.ERROR,\r | |
368 | buttons: Ext.Msg.OK\r | |
369 | });\r | |
370 | }\r | |
371 | });\r | |
372 | },\r | |
373 | \r | |
374 | /**\r | |
375 | * Handles the list view's "listdrop" event. Runs after a list is reordered by dragging and dropping.\r | |
376 | * Commits the lists new position in the tree to the server.\r | |
377 | * @param {SimpleTasks.model.List} list The List that was dropped\r | |
378 | * @param {SimpleTasks.model.List} overList The List that the List was dropped on\r | |
379 | * @param {String} position `"before"` or `"after"` depending on whether the mouse is above or below the midline of the node.\r | |
380 | */\r | |
381 | reorderList: function(list, overList, position) {\r | |
382 | var listsStore = this.getListsStore();\r | |
383 | \r | |
384 | if(SimpleTasks.Settings.useLocalStorage) {\r | |
385 | listsStore.sync();\r | |
386 | } else {\r | |
387 | Ext.Ajax.request({\r | |
388 | url: 'php/list/move.php',\r | |
389 | jsonData: {\r | |
390 | id: list.get('id'),\r | |
391 | relatedId: overList.get('id'),\r | |
392 | position: position\r | |
393 | },\r | |
394 | success: function(response, options) {\r | |
395 | var responseData = Ext.decode(response.responseText);\r | |
396 | \r | |
397 | if(!responseData.success) {\r | |
398 | Ext.MessageBox.show({\r | |
399 | title: 'Move Task Failed',\r | |
400 | msg: responseData.message,\r | |
401 | icon: Ext.Msg.ERROR,\r | |
402 | buttons: Ext.Msg.OK\r | |
403 | });\r | |
404 | }\r | |
405 | },\r | |
406 | failure: function(response, options) {\r | |
407 | Ext.MessageBox.show({\r | |
408 | title: 'Move Task Failed',\r | |
409 | msg: response.status + ' ' + response.statusText,\r | |
410 | icon: Ext.Msg.ERROR,\r | |
411 | buttons: Ext.Msg.OK\r | |
412 | });\r | |
413 | }\r | |
414 | });\r | |
415 | }\r | |
416 | \r | |
417 | // refresh the lists view so the task counts will be updated.\r | |
418 | this.getListTree().refreshView();\r | |
419 | },\r | |
420 | \r | |
421 | /**\r | |
422 | * Handles the initial tasks store "load" event,\r | |
423 | * refreshes the List tree view then removes itself as a handler.\r | |
424 | * @param {SimpleTasks.store.Tasks} tasksStore\r | |
425 | * @param {SimpleTasks.model.Task[]} tasks\r | |
426 | * @param {Boolean} success\r | |
427 | * @param {Ext.data.Operation} operation\r | |
428 | */\r | |
429 | handleTasksLoad: function(tasksStore, tasks, success, operation) {\r | |
430 | var me = this,\r | |
431 | listTree = me.getListTree(),\r | |
432 | selectionModel = listTree.getSelectionModel();\r | |
433 | \r | |
434 | // refresh the lists view so the task counts will be updated.\r | |
435 | listTree.refreshView();\r | |
436 | // filter the task grid by the selected list\r | |
437 | me.filterTaskGrid(selectionModel, selectionModel.getSelection());\r | |
438 | // remove the event listener after the first run\r | |
439 | tasksStore.un('load', this.handleTasksLoad, this);\r | |
440 | },\r | |
441 | \r | |
442 | /**\r | |
443 | * Handles the initial lists store "load" event,\r | |
444 | * selects the list tree's root node if the list tree exists, loads the tasks store, then removes itself as a handler.\r | |
445 | * @param {SimpleTasks.store.Lists} listsStore\r | |
446 | * @param {SimpleTasks.model.List[]} lists\r | |
447 | * @param {Boolean} success\r | |
448 | * @param {Ext.data.Operation} operation\r | |
449 | */\r | |
450 | handleListsLoad: function(listsStore, lists, success, operation) {\r | |
451 | var me = this,\r | |
452 | listTree = me.getListTree(),\r | |
453 | tasksStore = me.getTasksStore();\r | |
454 | \r | |
455 | if(listTree) {\r | |
456 | // if the list tree exists when the lists store is first loaded, select the root node.\r | |
457 | // when using a server proxy, the list tree will always exist at this point since asyncronous loading of data allows time for the list tree to be created and rendered.\r | |
458 | // when using a local storage proxy, the list tree will not yet exist at this point, so we'll have to select the root node on render instead (see handleAfterListTreeRender)\r | |
459 | listTree.getSelectionModel().select(0);\r | |
460 | }\r | |
461 | // wait until lists are done loading to load tasks since the task grid's "list" column renderer depends on lists store being loaded\r | |
462 | me.getTasksStore().load();\r | |
463 | // if the tasks store is asynchronous (server proxy) attach load handler for refreshing the list counts after loading is complete\r | |
464 | // if local storage is being used, isLoading will be false here since load() will run syncronously, so there is no need\r | |
465 | // to refresh the lists view because load will have happened before the list tree is even rendered\r | |
466 | if(tasksStore.isLoading()) {\r | |
467 | tasksStore.on('load', me.handleTasksLoad, me);\r | |
468 | }\r | |
469 | // remove the event listener after the first run\r | |
470 | listsStore.un('load', me.handleListsLoad, me);\r | |
471 | },\r | |
472 | \r | |
473 | /**\r | |
474 | * Handles the list tree's "afterrender" event\r | |
475 | * Selects the lists tree's root node, if the list tree exists\r | |
476 | * @param {SimpleTasks.view.lists.Tree} listTree\r | |
477 | */\r | |
478 | handleAfterListTreeRender: function(listTree) {\r | |
479 | listTree.getSelectionModel().select(0);\r | |
480 | },\r | |
481 | \r | |
482 | /**\r | |
483 | * Handles the lists store's write event.\r | |
484 | * Syncronizes the other read only list stores with the newly saved data\r | |
485 | * @param {SimpleTasks.store.Lists} listsStore\r | |
486 | * @param {Ext.data.Operation} operation\r | |
487 | */\r | |
488 | syncListsStores: function(listsStore, operation) {\r | |
489 | var me = this,\r | |
490 | stores = [\r | |
491 | Ext.getStore('Lists-TaskGrid'),\r | |
492 | Ext.getStore('Lists-TaskEditWindow'),\r | |
493 | Ext.getStore('Lists-TaskForm')\r | |
494 | ],\r | |
495 | storesLen = stores.length,\r | |
496 | records = operation.getRecords(),\r | |
497 | recordsLen = records.length, \r | |
498 | i, j, listToSync, node, list, store;\r | |
499 | \r | |
500 | for (i = 0; i < recordsLen; ++i) {\r | |
501 | list = records[i];\r | |
502 | for (j = 0; j < storesLen; ++j) {\r | |
503 | store = stores[j];\r | |
504 | if (store) {\r | |
505 | listToSync = store.getNodeById(list.getId());\r | |
506 | switch(operation.action) {\r | |
507 | case 'create':\r | |
508 | node = store.getNodeById(list.parentNode.getId()) || store.getRoot();\r | |
509 | node.appendChild(list.copy(list.getId()));\r | |
510 | break;\r | |
511 | case 'update':\r | |
512 | if(listToSync) {\r | |
513 | listToSync.set(list.data);\r | |
514 | listToSync.commit();\r | |
515 | }\r | |
516 | break;\r | |
517 | case 'destroy':\r | |
518 | if(listToSync) {\r | |
519 | listToSync.remove(false);\r | |
520 | }\r | |
521 | }\r | |
522 | }\r | |
523 | }\r | |
524 | }\r | |
525 | },\r | |
526 | \r | |
527 | /**\r | |
528 | * Handles a mouseenter event on a list tree node.\r | |
529 | * Shows the node's action icons.\r | |
530 | * @param {Ext.tree.View} view\r | |
531 | * @param {SimpleTasks.model.List} list\r | |
532 | * @param {HTMLElement} node\r | |
533 | * @param {Number} rowIndex\r | |
534 | * @param {Ext.EventObject} e\r | |
535 | */\r | |
536 | showActions: function(view, list, node, rowIndex, e) {\r | |
537 | var icons = Ext.fly(node).query('.x-action-col-icon');\r | |
538 | if(view.getRecord(node).get('id') > 0) {\r | |
539 | Ext.each(icons, function(icon){\r | |
540 | Ext.get(icon).removeCls('x-hidden');\r | |
541 | });\r | |
542 | }\r | |
543 | },\r | |
544 | \r | |
545 | /**\r | |
546 | * Handles a mouseleave event on a list tree node.\r | |
547 | * Hides the node's action icons.\r | |
548 | * @param {Ext.tree.View} view\r | |
549 | * @param {SimpleTasks.model.List} list\r | |
550 | * @param {HTMLElement} node\r | |
551 | * @param {Number} rowIndex\r | |
552 | * @param {Ext.EventObject} e\r | |
553 | */\r | |
554 | hideActions: function(view, list, node, rowIndex, e) {\r | |
555 | var icons = Ext.fly(node).query('.x-action-col-icon');\r | |
556 | Ext.each(icons, function(icon){\r | |
557 | Ext.get(icon).addCls('x-hidden');\r | |
558 | });\r | |
559 | },\r | |
560 | \r | |
561 | /**\r | |
562 | * Handles the list tree's itemcontextmenu event\r | |
563 | * Shows the list context menu.\r | |
564 | * @param {Ext.grid.View} view\r | |
565 | * @param {SimpleTasks.model.List} list\r | |
566 | * @param {HTMLElement} node\r | |
567 | * @param {Number} rowIndex\r | |
568 | * @param {Ext.EventObject} e\r | |
569 | */\r | |
570 | showContextMenu: function(view, list, node, rowIndex, e) {\r | |
571 | var contextMenu = this.getContextMenu(),\r | |
572 | newListItem = Ext.getCmp('new-list-item'),\r | |
573 | newFolderItem = Ext.getCmp('new-folder-item'),\r | |
574 | deleteFolderItem = Ext.getCmp('delete-folder-item'),\r | |
575 | deleteListItem = Ext.getCmp('delete-list-item');\r | |
576 | \r | |
577 | if(list.isLeaf()) {\r | |
578 | newListItem.hide();\r | |
579 | newFolderItem.hide();\r | |
580 | deleteFolderItem.hide();\r | |
581 | deleteListItem.show();\r | |
582 | } else {\r | |
583 | newListItem.show();\r | |
584 | newFolderItem.show();\r | |
585 | if(list.isRoot()) {\r | |
586 | deleteFolderItem.hide();\r | |
587 | } else {\r | |
588 | deleteFolderItem.show();\r | |
589 | }\r | |
590 | deleteListItem.hide();\r | |
591 | }\r | |
592 | contextMenu.setList(list);\r | |
593 | contextMenu.showAt(e.getX(), e.getY());\r | |
594 | e.preventDefault();\r | |
595 | }\r | |
596 | \r | |
597 | });\r |