Tree.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /**
  2. * @class SimpleTasks.view.lists.Tree
  3. * @extends Ext.tree.Panel
  4. * The task list view. A tree that displays all of the task lists.
  5. */
  6. Ext.define('SimpleTasks.view.lists.Tree', {
  7. extend: 'Ext.tree.Panel',
  8. xtype: 'listTree',
  9. requires: [
  10. 'Ext.grid.plugin.CellEditing',
  11. 'Ext.tree.plugin.TreeViewDragDrop',
  12. 'Ext.grid.column.Action'
  13. ],
  14. title: 'Lists',
  15. store: 'Lists',
  16. hideHeaders: true,
  17. dockedItems: [
  18. {
  19. xtype: 'toolbar',
  20. dock: 'bottom',
  21. items: [
  22. {
  23. iconCls: 'tasks-new-list',
  24. tooltip: 'New List'
  25. },
  26. {
  27. iconCls: 'tasks-delete-list',
  28. id: 'delete-list-btn',
  29. tooltip: 'Delete List'
  30. },
  31. {
  32. iconCls: 'tasks-new-folder',
  33. tooltip: 'New Folder'
  34. },
  35. {
  36. iconCls: 'tasks-delete-folder',
  37. id: 'delete-folder-btn',
  38. tooltip: 'Delete Folder'
  39. }
  40. ]
  41. }
  42. ],
  43. viewConfig: {
  44. plugins: {
  45. ptype: 'tasksdragdrop',
  46. dragText: 'Drag to reorder',
  47. ddGroup: 'task'
  48. }
  49. },
  50. initComponent: function() {
  51. var me = this;
  52. /**
  53. * This Tree Panel's cell editing plugin
  54. * @property cellEditingPlugin
  55. * @type Ext.grid.plugin.CellEditing
  56. */
  57. me.plugins = [me.cellEditingPlugin = Ext.create('Ext.grid.plugin.CellEditing')];
  58. me.columns = [
  59. {
  60. xtype: 'treecolumn',
  61. dataIndex: 'name',
  62. flex: 1,
  63. editor: {
  64. xtype: 'textfield',
  65. selectOnFocus: true,
  66. validator: function(value){
  67. value = Ext.String.trim(value);
  68. return value.length < 1 ? this.blankText : true;
  69. }
  70. },
  71. renderer: Ext.bind(me.renderName, me)
  72. },
  73. {
  74. xtype: 'actioncolumn',
  75. width: 24,
  76. icon: 'resources/images/delete.png',
  77. iconCls: 'x-hidden',
  78. tooltip: 'Delete',
  79. handler: Ext.bind(me.handleDeleteClick, me)
  80. }
  81. ];
  82. me.callParent(arguments);
  83. me.addEvents(
  84. /**
  85. * @event deleteclick
  86. * Fires when the delete icon is clicked
  87. * @param {Ext.grid.View} gridView
  88. * @param {Number} rowIndex
  89. * @param {Number} colIndex
  90. * @param {Ext.grid.column.Action} column
  91. * @param {EventObject} e
  92. */
  93. 'deleteclick',
  94. /**
  95. * @event taskdrop
  96. * Fires when a task record is dropped on this grid
  97. * @param {SimpleTasks.model.Task} task The task record
  98. * @param {SimpleTasks.model.List} list The list that the task was dropped on
  99. */
  100. 'taskdrop',
  101. /**
  102. * @event listdrop
  103. * Fires when a list record is dropped on this grid
  104. * @param {SimpleTasks.model.List} list The list that was dropped
  105. * @param {SimpleTasks.model.List} overList The list that the list was dropped on
  106. * @param {String} position `"before"` or `"after"` depending on whether the mouse is above or below the midline of the node.
  107. */
  108. 'listdrop'
  109. );
  110. me.on('beforeedit', me.handleBeforeEdit, me);
  111. me.relayEvents(me.getView(), ['taskdrop', 'listdrop'])
  112. },
  113. /**
  114. * Handles a click on a delete icon
  115. * @private
  116. * @param {Ext.tree.View} treeView
  117. * @param {Number} rowIndex
  118. * @param {Number} colIndex
  119. * @param {Ext.grid.column.Action} column
  120. * @param {EventObject} e
  121. */
  122. handleDeleteClick: function(gridView, rowIndex, colIndex, column, e) {
  123. // Fire a "deleteclick" event with all the same args as this handler
  124. this.fireEvent('deleteclick', gridView, rowIndex, colIndex, column, e);
  125. },
  126. /**
  127. * Handles this grid's "beforeedit" event (relayed from the CellEditing plugin).
  128. * Prevents editing of "All Lists" root by returning false if the record has an id of -1
  129. * @private
  130. * @param {Ext.grid.plugin.CellEditing} editingPlugin The cell editing plugin
  131. * @param {Object} e an edit event object
  132. */
  133. handleBeforeEdit: function(editingPlugin, e) {
  134. return e.record.get('id') !== -1;
  135. },
  136. /**
  137. * Renderer for the name field.
  138. * Adds the task count after the list name.
  139. * @private
  140. * @param {String} value
  141. * @param {Object} metaData
  142. * @param {SimpleTasks.model.List} list
  143. * @param {Number} rowIndex
  144. * @param {Number} colIndex
  145. * @param {SimpleTasks.store.Lists} store
  146. * @param {Ext.grid.View} view
  147. */
  148. renderName: function(value, metaData, list, rowIndex, colIndex, store, view) {
  149. var tasksStore = Ext.StoreMgr.lookup('Tasks'),
  150. count = 0;
  151. (function countTasks(list) {
  152. count += tasksStore.queryBy(function(task, id) {
  153. // only show count for tasks that are not done
  154. return task.get('list_id') === list.get('id') && task.get('done') === false;
  155. }).getCount();
  156. list.eachChild(function(child) {
  157. countTasks(child);
  158. });
  159. })(list);
  160. return value + ' (' + count + ')';
  161. },
  162. /**
  163. * Triggers the list tree to refresh its view. This is necessary in two scenarios:
  164. * 1) Since the lists and tasks are loaded asyncrounously, The Lists store may have finished
  165. * loading before the tasks store. In this case, the tasks data would not be available so all
  166. * of the task counts would be rendered as (0).
  167. * 2) When a task is dragged and dropped onto a list, or when a list is deleted the task count won't automatially be updated
  168. * because none of the data in the lists store actually changed (the renderer gets the count
  169. * from the tasks store).
  170. *
  171. * In both situations refreshing the lists view we ensure that the task counts are accurate.
  172. */
  173. refreshView: function() {
  174. // refresh the data in the view. This will trigger the column renderers to run, making sure the task counts are up to date.
  175. this.getView().refresh();
  176. }
  177. });