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