Upgrade to ExtJS 3.0.0 - Released 07/06/2009
[extjs.git] / docs / source / tasks.html
1 <html>\r
2 <head>\r
3   <title>The source code</title>\r
4     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />\r
5     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>\r
6 </head>\r
7 <body  onload="prettyPrint();">\r
8     <pre class="prettyprint lang-js">Ext.onReady(function(){\r
9     Ext.QuickTips.init();\r
10 \r
11     var xg = Ext.grid;\r
12     // turn off default shadows which look funky in air\r
13     xg.GridEditor.prototype.shadow = false;\r
14     \r
15     var conn = Ext.data.SqlDB.getInstance();\r
16         conn.open('tasks.db');\r
17     \r
18     // the main grid store\r
19     var taskStore = new TaskStore(conn);\r
20     \r
21     // Category store shared by category combos\r
22     var catStore = new CategoryStore();\r
23     \r
24         taskStore.load({\r
25                 callback: function(){\r
26                         // first time?\r
27                         if(taskStore.getCount() < 1){\r
28                                 Ext.Msg.confirm('Create Tasks?', 'Your database is currently empty. Would you like to insert some demo data?', \r
29                                         function(btn){\r
30                                                 if(btn == 'yes'){\r
31                                                         loadDemoTasks(taskStore);       \r
32                                                 }\r
33                                                 catStore.init(taskStore);\r
34                                         });\r
35                         }else{\r
36                                 catStore.init(taskStore);\r
37                         }\r
38                 }\r
39         });\r
40 \r
41     // custom event to notify when a new category is available\r
42     taskStore.on('newcategory', catStore.addCategory, catStore);\r
43 \r
44     // set of event handlers shared by combos to allow them to share\r
45     // the same local store\r
46     var comboEvents = {\r
47         focus: function(){\r
48             this.bindStore(catStore);\r
49         },\r
50         blur: function(c){\r
51             catStore.purgeListeners();\r
52         }\r
53     }\r
54 \r
55     var completeColumn = new CompleteColumn();\r
56 \r
57     // custom template for the grid header\r
58     var headerTpl = new Ext.Template(\r
59         '<table border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',\r
60         '<thead><tr class="x-grid3-hd-row">{cells}</tr></thead>',\r
61         '<tbody><tr class="new-task-row">',\r
62             '<td><div id="new-task-icon"></div></td>',\r
63             '<td><div class="x-small-editor" id="new-task-title"></div></td>',\r
64             '<td><div class="x-small-editor" id="new-task-cat"></div></td>',\r
65             '<td><div class="x-small-editor" id="new-task-due"></div></td>',\r
66         '</tr></tbody>',\r
67         "</table>"\r
68     );\r
69 \r
70     var selections = new Ext.grid.RowSelectionModel();\r
71 \r
72     // The main grid in all its configuration option glory\r
73     var grid = new xg.EditorGridPanel({\r
74         id:'tasks-grid',\r
75         store: taskStore,\r
76         sm: selections,\r
77         clicksToEdit: 'auto',\r
78         enableColumnHide:false,\r
79         enableColumnMove:false,\r
80                 border:false,\r
81                 title:'All Tasks',\r
82                 iconCls:'icon-show-all',\r
83                 region:'center',\r
84                 \r
85         plugins: completeColumn,\r
86 \r
87         columns: [\r
88             completeColumn,\r
89             {\r
90                 header: "Task",\r
91                 width:400,\r
92                 sortable: true,\r
93                 dataIndex: 'title',\r
94                 id:'task-title',\r
95                 editor: new Ext.form.TextField({\r
96                     allowBlank: false\r
97                 })\r
98             },\r
99             {\r
100                 header: "Category",\r
101                 width:150,\r
102                 sortable: true,\r
103                 dataIndex: 'category',\r
104                 editor: new Ext.form.ComboBox({\r
105                     displayField: 'text',\r
106                     triggerAction: 'all',\r
107                     mode:'local',\r
108                     selectOnFocus:true,\r
109                     listClass:'x-combo-list-small',\r
110                     listeners: comboEvents\r
111                 })\r
112             },\r
113             {\r
114                 header: "Due Date",\r
115                 width: 150,\r
116                 sortable: true,\r
117                 renderer: Ext.util.Format.dateRenderer('D m/d/Y'),\r
118                 dataIndex: 'dueDate',\r
119                 groupRenderer: textDate(),\r
120                 groupName: 'Due',\r
121                 editor: new Ext.form.DateField({\r
122                     format : "m/d/Y"\r
123                 })\r
124             }\r
125         ],\r
126 \r
127         view: new Ext.grid.GroupingView({\r
128             forceFit:true,\r
129             ignoreAdd: true,\r
130             emptyText: 'No Tasks to display',\r
131 \r
132             templates: {\r
133                 header: headerTpl\r
134             },\r
135 \r
136             getRowClass : function(r){\r
137                 var d = r.data;\r
138                 if(d.completed){\r
139                     return 'task-completed';\r
140                 }\r
141                 if(d.dueDate && d.dueDate.getTime() < new Date().clearTime().getTime()){\r
142                     return 'task-overdue';\r
143                 }\r
144                 return '';\r
145             }\r
146         })\r
147     });\r
148 \r
149     var viewPanel = new Ext.Panel({\r
150         frame:true,\r
151         title: 'Views',\r
152         collapsible:true,\r
153         contentEl:'task-views',\r
154         titleCollapse: true\r
155     });\r
156     \r
157     var taskActions = new Ext.Panel({\r
158         frame:true,\r
159         title: 'Task Actions',\r
160         collapsible:true,\r
161         contentEl:'task-actions',\r
162         titleCollapse: true\r
163     });\r
164     \r
165     var groupActions = new Ext.Panel({\r
166         frame:true,\r
167         title: 'Task Grouping',\r
168         collapsible:true,\r
169         contentEl:'task-grouping',\r
170         titleCollapse: true\r
171     });\r
172     \r
173     var actionPanel = new Ext.Panel({\r
174         id:'action-panel',\r
175         region:'west',\r
176         split:true,\r
177         collapsible: true,\r
178         collapseMode: 'mini',\r
179         width:200,\r
180         minWidth: 150,\r
181         border: false,\r
182         baseCls:'x-plain',\r
183         items: [taskActions, viewPanel, groupActions]\r
184     });\r
185 \r
186     if(Ext.isAir){ // create AIR window\r
187         var win = new Ext.air.MainWindow({\r
188             layout:'border',\r
189             items: [actionPanel, grid],\r
190             title: 'Simple Tasks',\r
191             iconCls: 'icon-show-all'\r
192         }).render();\r
193         }else{\r
194         var viewport = new Ext.Viewport({\r
195             layout:'border',\r
196             items: [actionPanel, grid]\r
197         });\r
198     }\r
199 \r
200     var ab = actionPanel.body;\r
201     ab.on('mousedown', doAction, null, {delegate:'a'});\r
202         ab.on('click', Ext.emptyFn, null, {delegate:'a', preventDefault:true});\r
203 \r
204     grid.on('resize', syncFields);\r
205         grid.on('columnresize', syncFields);\r
206 \r
207     grid.on('afteredit', function(e){\r
208         if(e.field == 'category'){\r
209             catStore.addCategory(e.value);\r
210         }\r
211         if(e.field == taskStore.getGroupState()){\r
212             taskStore.applyGrouping();\r
213         }\r
214 \r
215     });\r
216 \r
217     grid.on('keydown', function(e){\r
218          if(e.getKey() == e.DELETE && !grid.editing){\r
219              actions['action-delete']();\r
220          }\r
221     });\r
222 \r
223     selections.on('selectionchange', function(sm){\r
224         var bd = taskActions.body, c = sm.getCount();\r
225         bd.select('li:not(#new-task)').setDisplayed(c > 0);\r
226         bd.select('span.s').setDisplayed(c > 1);\r
227     });\r
228 \r
229     // The fields in the grid's header\r
230     var ntTitle = new Ext.form.TextField({\r
231         renderTo: 'new-task-title',\r
232         emptyText: 'Add a task...'\r
233     });\r
234 \r
235     var ntCat = new Ext.form.ComboBox({\r
236         renderTo: 'new-task-cat',\r
237         disabled:true,\r
238         displayField: 'text',\r
239         triggerAction: 'all',\r
240         mode:'local',\r
241         selectOnFocus:true,\r
242         listClass:'x-combo-list-small',\r
243         listeners: comboEvents\r
244     });\r
245 \r
246     var ntDue = new Ext.form.DateField({\r
247         renderTo: 'new-task-due',\r
248         value: new Date(),\r
249         disabled:true,\r
250         format : "m/d/Y"\r
251     });\r
252 \r
253     // syncs the header fields' widths with the grid column widths\r
254     function syncFields(){\r
255         var cm = grid.getColumnModel();\r
256         ntTitle.setSize(cm.getColumnWidth(1)-2);\r
257         ntCat.setSize(cm.getColumnWidth(2)-4);\r
258         ntDue.setSize(cm.getColumnWidth(3)-4);\r
259     }\r
260     syncFields();\r
261 \r
262     var editing = false, focused = false, userTriggered = false;\r
263     var handlers = {\r
264         focus: function(){\r
265             focused = true;\r
266         },\r
267         blur: function(){\r
268             focused = false;\r
269             doBlur.defer(250);\r
270         },\r
271         specialkey: function(f, e){\r
272             if(e.getKey()==e.ENTER){\r
273                 userTriggered = true;\r
274                 e.stopEvent();\r
275                 f.el.blur();\r
276                 if(f.triggerBlur){\r
277                     f.triggerBlur();\r
278                 }\r
279             }\r
280         }\r
281     }\r
282     ntTitle.on(handlers);\r
283     ntCat.on(handlers);\r
284     ntDue.on(handlers);\r
285 \r
286     ntTitle.on('focus', function(){\r
287         focused = true;\r
288         if(!editing){\r
289             ntCat.enable();\r
290             ntDue.enable();\r
291             syncFields();\r
292             editing = true;\r
293         }\r
294     });\r
295 \r
296     // when a field in the add bar is blurred, this determines\r
297     // whether a new task should be created\r
298     function doBlur(){\r
299         if(editing && !focused){\r
300             var title = ntTitle.getValue();\r
301             if(!Ext.isEmpty(title)){\r
302                 taskStore.addTask({\r
303                     taskId: Task.nextId(),\r
304                     title: title,\r
305                     dueDate: ntDue.getValue()||'',\r
306                     description: '', // ???\r
307                     category: ntCat.getValue(),\r
308                     completed: false\r
309                 });\r
310                 ntTitle.setValue('');\r
311                 if(userTriggered){ // if the entered to add the task, then go to a new add automatically\r
312                     userTriggered = false;\r
313                     ntTitle.focus.defer(100, ntTitle);\r
314                 }\r
315             }\r
316             ntCat.disable();\r
317             ntDue.disable();\r
318             editing = false;\r
319         }\r
320     }\r
321         \r
322     var actions = {\r
323         'view-all' : function(){\r
324                 taskStore.applyFilter('all');\r
325                 grid.setTitle('All Tasks', 'icon-show-all');\r
326         },\r
327         \r
328         'view-active' : function(){\r
329                 taskStore.applyFilter(false);\r
330                 grid.setTitle('Active Tasks', 'icon-show-active');\r
331         },\r
332         \r
333         'view-complete' : function(){\r
334                 taskStore.applyFilter(true);\r
335                 grid.setTitle('Completed Tasks', 'icon-show-complete');\r
336         },\r
337         \r
338         'action-new' : function(){\r
339                 ntTitle.focus();\r
340         },\r
341         \r
342         'action-complete' : function(){\r
343                 selections.each(function(s){\r
344                         s.set('completed', true);\r
345                 });\r
346             taskStore.applyFilter();\r
347         },\r
348         \r
349         'action-active' : function(){\r
350                 selections.each(function(s){\r
351                         s.set('completed', false);\r
352                 });\r
353             taskStore.applyFilter();\r
354         },\r
355         \r
356         'action-delete' : function(){\r
357                 Ext.Msg.confirm('Confirm', 'Are you sure you want to delete the selected task(s)?', \r
358                 function(btn){\r
359                 if(btn == 'yes'){\r
360                         selections.each(function(s){\r
361                                         taskStore.remove(s);\r
362                                 });\r
363                 }\r
364             });\r
365         },\r
366         \r
367         'group-date' : function(){\r
368                 taskStore.groupBy('dueDate');\r
369         },\r
370         \r
371         'group-cat' : function(){\r
372                 taskStore.groupBy('category');\r
373         },\r
374         \r
375         'no-group' : function(){\r
376                 taskStore.clearGrouping();\r
377         }\r
378     };\r
379     \r
380     function doAction(e, t){\r
381         e.stopEvent();\r
382         actions[t.id]();\r
383     }\r
384     \r
385     \r
386     // generates a renderer function to be used for textual date groups\r
387     function textDate(){\r
388         // create the cache of ranges to be reused\r
389         var today = new Date().clearTime(true);\r
390         var year = today.getFullYear();\r
391         var todayTime = today.getTime();\r
392         var yesterday = today.add('d', -1).getTime();\r
393         var tomorrow = today.add('d', 1).getTime();\r
394         var weekDays = today.add('d', 6).getTime();\r
395         var lastWeekDays = today.add('d', -6).getTime();\r
396 \r
397         return function(date){\r
398             if(!date) {\r
399                 return '(No Date)';\r
400             }\r
401             var notime = date.clearTime(true).getTime();\r
402 \r
403             if (notime == todayTime) {\r
404                 return 'Today';\r
405             }\r
406             if(notime > todayTime){\r
407                 if (notime == tomorrow) {\r
408                     return 'Tomorrow';\r
409                 }\r
410                 if (notime <= weekDays) {\r
411                     return date.format('l');\r
412                 }\r
413             }else {\r
414                 if(notime == yesterday) {\r
415                         return 'Yesterday';\r
416                     }\r
417                     if(notime >= lastWeekDays) {\r
418                         return 'Last ' + date.format('l');\r
419                     }\r
420             }            \r
421             return date.getFullYear() == year ? date.format('D m/d') : date.format('D m/d/Y');\r
422        }\r
423     }\r
424 });\r
425 \r
426 /* This is used to laod some demo tasks if the task database is empty */\r
427 function loadDemoTasks(store){\r
428         var s = new Date();\r
429         // hardcoded demo tasks\r
430         store.addTask({taskId: Task.nextId(), title:'Start documentation of Ext 2.0', category:'Ext', description:'', dueDate: s.add('d', 21), completed: false});\r
431         store.addTask({taskId: Task.nextId(), title:'Release Ext 1.l Beta 2', category:'Ext', description:'', dueDate:s.add('d', 2), completed: false});\r
432         store.addTask({taskId: Task.nextId(), title:'Take wife to see movie', category:'Family', description:'', dueDate:s.add('d', 2), completed: false});\r
433         store.addTask({taskId: Task.nextId(), title:'Finish task list demo app', category:'Ext', description:'', dueDate:s.add('d', 2), completed: false});\r
434         store.addTask({taskId: Task.nextId(), title:'Do something other than work', category:'Family', description:'', dueDate:s.add('d', -1), completed: false});\r
435         store.addTask({taskId: Task.nextId(), title:'Go to the grocery store', category:'Family', description:'', dueDate:s.add('d', -1), completed: true});\r
436         store.addTask({taskId: Task.nextId(), title:'Reboot my computer', category:'Misc', description:'', dueDate:s, completed: false});\r
437         store.addTask({taskId: Task.nextId(), title:'Respond to emails', category:'Ext', description:'', dueDate:s, completed: true});\r
438 }\r
439 \r
440     \r
441 \r
442 </pre>    \r
443 </body>\r
444 </html>