Upgrade to ExtJS 3.2.2 - Released 06/02/2010
[extjs.git] / examples / tasks / tasks.js
index 8ad158c..7132786 100644 (file)
 /*!
 /*!
- * Ext JS Library 3.1.1
- * Copyright(c) 2006-2010 Ext JS, LLC
+ * Ext JS Library 3.2.2
+ * Copyright(c) 2006-2010 Ext JS, Inc.
  * licensing@extjs.com
  * http://www.extjs.com/license
  */
  * licensing@extjs.com
  * http://www.extjs.com/license
  */
-Ext.onReady(function(){\r
-    Ext.QuickTips.init();\r
-\r
-    var xg = Ext.grid;\r
-    // turn off default shadows which look funky in air\r
-    xg.GridEditor.prototype.shadow = false;\r
-    \r
-    var conn = Ext.data.SqlDB.getInstance();\r
-       conn.open('tasks.db');\r
-    \r
-    // the main grid store\r
-    var taskStore = new TaskStore(conn);\r
-    \r
-    // Category store shared by category combos\r
-    var catStore = new CategoryStore();\r
-    \r
-       taskStore.load({\r
-               callback: function(){\r
-                       // first time?\r
-                       if(taskStore.getCount() < 1){\r
-                               Ext.Msg.confirm('Create Tasks?', 'Your database is currently empty. Would you like to insert some demo data?', \r
-                                       function(btn){\r
-                                               if(btn == 'yes'){\r
-                                                       loadDemoTasks(taskStore);       \r
-                                               }\r
-                                               catStore.init(taskStore);\r
-                                       });\r
-                       }else{\r
-                               catStore.init(taskStore);\r
-                       }\r
-               }\r
-       });\r
-\r
-    // custom event to notify when a new category is available\r
-    taskStore.on('newcategory', catStore.addCategory, catStore);\r
-\r
-    // set of event handlers shared by combos to allow them to share\r
-    // the same local store\r
-    var comboEvents = {\r
-        focus: function(){\r
-            this.bindStore(catStore);\r
-        },\r
-        blur: function(c){\r
-            catStore.purgeListeners();\r
-        }\r
-    }\r
-\r
-    var completeColumn = new CompleteColumn();\r
-\r
-    // custom template for the grid header\r
-    var headerTpl = new Ext.Template(\r
-        '<table border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',\r
-        '<thead><tr class="x-grid3-hd-row">{cells}</tr></thead>',\r
-        '<tbody><tr class="new-task-row">',\r
-            '<td><div id="new-task-icon"></div></td>',\r
-            '<td><div class="x-small-editor" id="new-task-title"></div></td>',\r
-            '<td><div class="x-small-editor" id="new-task-cat"></div></td>',\r
-            '<td><div class="x-small-editor" id="new-task-due"></div></td>',\r
-        '</tr></tbody>',\r
-        "</table>"\r
-    );\r
-\r
-    var selections = new Ext.grid.RowSelectionModel();\r
-\r
-    // The main grid in all its configuration option glory\r
-    var grid = new xg.EditorGridPanel({\r
-        id:'tasks-grid',\r
-        store: taskStore,\r
-        sm: selections,\r
-        clicksToEdit: 'auto',\r
-        enableColumnHide:false,\r
-        enableColumnMove:false,\r
-               border:false,\r
-               title:'All Tasks',\r
-               iconCls:'icon-show-all',\r
-               region:'center',\r
-               \r
-        plugins: completeColumn,\r
-\r
-        columns: [\r
-            completeColumn,\r
-            {\r
-                header: "Task",\r
-                width:400,\r
-                sortable: true,\r
-                dataIndex: 'title',\r
-                id:'task-title',\r
-                editor: new Ext.form.TextField({\r
-                    allowBlank: false\r
-                })\r
-            },\r
-            {\r
-                header: "Category",\r
-                width:150,\r
-                sortable: true,\r
-                dataIndex: 'category',\r
-                editor: new Ext.form.ComboBox({\r
-                    displayField: 'text',\r
-                    triggerAction: 'all',\r
-                    mode:'local',\r
-                    selectOnFocus:true,\r
-                    listClass:'x-combo-list-small',\r
-                    listeners: comboEvents\r
-                })\r
-            },\r
-            {\r
-                header: "Due Date",\r
-                width: 150,\r
-                sortable: true,\r
-                renderer: Ext.util.Format.dateRenderer('D m/d/Y'),\r
-                dataIndex: 'dueDate',\r
-                groupRenderer: textDate(),\r
-                groupName: 'Due',\r
-                editor: new Ext.form.DateField({\r
-                    format : "m/d/Y"\r
-                })\r
-            }\r
-        ],\r
-\r
-        view: new Ext.grid.GroupingView({\r
-            forceFit:true,\r
-            ignoreAdd: true,\r
-            emptyText: 'No Tasks to display',\r
-\r
-            templates: {\r
-                header: headerTpl\r
-            },\r
-\r
-            getRowClass : function(r){\r
-                var d = r.data;\r
-                if(d.completed){\r
-                    return 'task-completed';\r
-                }\r
-                if(d.dueDate && d.dueDate.getTime() < new Date().clearTime().getTime()){\r
-                    return 'task-overdue';\r
-                }\r
-                return '';\r
-            }\r
-        })\r
-    });\r
-\r
-    var viewPanel = new Ext.Panel({\r
-       frame:true,\r
-       title: 'Views',\r
-       collapsible:true,\r
-       contentEl:'task-views',\r
-       titleCollapse: true\r
-    });\r
-    \r
-    var taskActions = new Ext.Panel({\r
-       frame:true,\r
-       title: 'Task Actions',\r
-       collapsible:true,\r
-       contentEl:'task-actions',\r
-       titleCollapse: true\r
-    });\r
-    \r
-    var groupActions = new Ext.Panel({\r
-       frame:true,\r
-       title: 'Task Grouping',\r
-       collapsible:true,\r
-       contentEl:'task-grouping',\r
-       titleCollapse: true\r
-    });\r
-    \r
-    var actionPanel = new Ext.Panel({\r
-       id:'action-panel',\r
-       region:'west',\r
-       split:true,\r
-       collapsible: true,\r
-       collapseMode: 'mini',\r
-        header: false,\r
-       width:200,\r
-       minWidth: 150,\r
-       border: false,\r
-       baseCls:'x-plain',\r
-       items: [taskActions, viewPanel, groupActions]\r
-    });\r
-\r
-    if(Ext.isAir){ // create AIR window\r
-        var win = new Ext.air.MainWindow({\r
-            layout:'border',\r
-            items: [actionPanel, grid],\r
-            title: 'Simple Tasks',\r
-            iconCls: 'icon-show-all'\r
-        }).render();\r
-       }else{\r
-        var viewport = new Ext.Viewport({\r
-            layout:'border',\r
-            items: [actionPanel, grid]\r
-        });\r
-    }\r
-\r
-    var ab = actionPanel.body;\r
-    ab.on('mousedown', doAction, null, {delegate:'a'});\r
-       ab.on('click', Ext.emptyFn, null, {delegate:'a', preventDefault:true});\r
-\r
-    grid.on('resize', syncFields);\r
-       grid.on('columnresize', syncFields);\r
-\r
-    grid.on('afteredit', function(e){\r
-        if(e.field == 'category'){\r
-            catStore.addCategory(e.value);\r
-        }\r
-        if(e.field == taskStore.getGroupState()){\r
-            taskStore.applyGrouping();\r
-        }\r
-\r
-    });\r
-\r
-    grid.on('keydown', function(e){\r
-         if(e.getKey() == e.DELETE && !grid.editing){\r
-             actions['action-delete']();\r
-         }\r
-    });\r
-\r
-    selections.on('selectionchange', function(sm){\r
-       var bd = taskActions.body, c = sm.getCount();\r
-       bd.select('li:not(#new-task)').setDisplayed(c > 0);\r
-       bd.select('span.s').setDisplayed(c > 1);\r
-    });\r
-\r
-    // The fields in the grid's header\r
-    var ntTitle = new Ext.form.TextField({\r
-        renderTo: 'new-task-title',\r
-        emptyText: 'Add a task...'\r
-    });\r
-\r
-    var ntCat = new Ext.form.ComboBox({\r
-        renderTo: 'new-task-cat',\r
-        disabled:true,\r
-        displayField: 'text',\r
-        triggerAction: 'all',\r
-        mode:'local',\r
-        selectOnFocus:true,\r
-        listClass:'x-combo-list-small',\r
-        listeners: comboEvents\r
-    });\r
-\r
-    var ntDue = new Ext.form.DateField({\r
-        renderTo: 'new-task-due',\r
-        value: new Date(),\r
-        disabled:true,\r
-        format : "m/d/Y"\r
-    });\r
-\r
-    // syncs the header fields' widths with the grid column widths\r
-    function syncFields(){\r
-        var cm = grid.getColumnModel();\r
-        ntTitle.setSize(cm.getColumnWidth(1)-2);\r
-        ntCat.setSize(cm.getColumnWidth(2)-4);\r
-        ntDue.setSize(cm.getColumnWidth(3)-4);\r
-    }\r
-    syncFields();\r
-\r
-    var editing = false, focused = false, userTriggered = false;\r
-    var handlers = {\r
-        focus: function(){\r
-            focused = true;\r
-        },\r
-        blur: function(){\r
-            focused = false;\r
-            doBlur.defer(250);\r
-        },\r
-        specialkey: function(f, e){\r
-            if(e.getKey()==e.ENTER){\r
-                userTriggered = true;\r
-                e.stopEvent();\r
-                f.el.blur();\r
-                if(f.triggerBlur){\r
-                    f.triggerBlur();\r
-                }\r
-            }\r
-        }\r
-    }\r
-    ntTitle.on(handlers);\r
-    ntCat.on(handlers);\r
-    ntDue.on(handlers);\r
-\r
-    ntTitle.on('focus', function(){\r
-        focused = true;\r
-        if(!editing){\r
-            ntCat.enable();\r
-            ntDue.enable();\r
-            syncFields();\r
-            editing = true;\r
-        }\r
-    });\r
-\r
-    // when a field in the add bar is blurred, this determines\r
-    // whether a new task should be created\r
-    function doBlur(){\r
-        if(editing && !focused){\r
-            var title = ntTitle.getValue();\r
-            if(!Ext.isEmpty(title)){\r
-                taskStore.addTask({\r
-                    taskId: Task.nextId(),\r
-                    title: title,\r
-                    dueDate: ntDue.getValue()||'',\r
-                    description: '', // ???\r
-                    category: ntCat.getValue(),\r
-                    completed: false\r
-                });\r
-                ntTitle.setValue('');\r
-                if(userTriggered){ // if the entered to add the task, then go to a new add automatically\r
-                    userTriggered = false;\r
-                    ntTitle.focus.defer(100, ntTitle);\r
-                }\r
-            }\r
-            ntCat.disable();\r
-            ntDue.disable();\r
-            editing = false;\r
-        }\r
-    }\r
-       \r
-    var actions = {\r
-       'view-all' : function(){\r
-               taskStore.applyFilter('all');\r
-               grid.setTitle('All Tasks', 'icon-show-all');\r
-       },\r
-       \r
-       'view-active' : function(){\r
-               taskStore.applyFilter(false);\r
-               grid.setTitle('Active Tasks', 'icon-show-active');\r
-       },\r
-       \r
-       'view-complete' : function(){\r
-               taskStore.applyFilter(true);\r
-               grid.setTitle('Completed Tasks', 'icon-show-complete');\r
-       },\r
-       \r
-       'action-new' : function(){\r
-               ntTitle.focus();\r
-       },\r
-       \r
-       'action-complete' : function(){\r
-               selections.each(function(s){\r
-                       s.set('completed', true);\r
-               });\r
-            taskStore.applyFilter();\r
-       },\r
-       \r
-       'action-active' : function(){\r
-               selections.each(function(s){\r
-                       s.set('completed', false);\r
-               });\r
-            taskStore.applyFilter();\r
-       },\r
-       \r
-       'action-delete' : function(){\r
-               Ext.Msg.confirm('Confirm', 'Are you sure you want to delete the selected task(s)?', \r
-               function(btn){\r
-                if(btn == 'yes'){\r
-                       selections.each(function(s){\r
-                                       taskStore.remove(s);\r
-                               });\r
-                }\r
-            });\r
-       },\r
-       \r
-       'group-date' : function(){\r
-               taskStore.groupBy('dueDate');\r
-       },\r
-       \r
-       'group-cat' : function(){\r
-               taskStore.groupBy('category');\r
-       },\r
-       \r
-       'no-group' : function(){\r
-               taskStore.clearGrouping();\r
-       }\r
-    };\r
-    \r
-    function doAction(e, t){\r
-       e.stopEvent();\r
-       actions[t.id]();\r
-    }\r
-    \r
-    \r
-    // generates a renderer function to be used for textual date groups\r
-    function textDate(){\r
-        // create the cache of ranges to be reused\r
-        var today = new Date().clearTime(true);\r
-        var year = today.getFullYear();\r
-        var todayTime = today.getTime();\r
-        var yesterday = today.add('d', -1).getTime();\r
-        var tomorrow = today.add('d', 1).getTime();\r
-        var weekDays = today.add('d', 6).getTime();\r
-        var lastWeekDays = today.add('d', -6).getTime();\r
-\r
-        return function(date){\r
-            if(!date) {\r
-                return '(No Date)';\r
-            }\r
-            var notime = date.clearTime(true).getTime();\r
-\r
-            if (notime == todayTime) {\r
-                return 'Today';\r
-            }\r
-            if(notime > todayTime){\r
-                if (notime == tomorrow) {\r
-                    return 'Tomorrow';\r
-                }\r
-                if (notime <= weekDays) {\r
-                    return date.format('l');\r
-                }\r
-            }else {\r
-               if(notime == yesterday) {\r
-                       return 'Yesterday';\r
-                   }\r
-                   if(notime >= lastWeekDays) {\r
-                       return 'Last ' + date.format('l');\r
-                   }\r
-            }            \r
-            return date.getFullYear() == year ? date.format('D m/d') : date.format('D m/d/Y');\r
-       }\r
-    }\r
-});\r
-\r
-/* This is used to laod some demo tasks if the task database is empty */\r
-function loadDemoTasks(store){\r
-       var s = new Date();\r
-       // hardcoded demo tasks\r
-       store.addTask({taskId: Task.nextId(), title:'Start documentation of Ext 2.0', category:'Ext', description:'', dueDate: s.add('d', 21), completed: false});\r
-       store.addTask({taskId: Task.nextId(), title:'Release Ext 1.l Beta 2', category:'Ext', description:'', dueDate:s.add('d', 2), completed: false});\r
-       store.addTask({taskId: Task.nextId(), title:'Take wife to see movie', category:'Family', description:'', dueDate:s.add('d', 2), completed: false});\r
-       store.addTask({taskId: Task.nextId(), title:'Finish task list demo app', category:'Ext', description:'', dueDate:s.add('d', 2), completed: false});\r
-       store.addTask({taskId: Task.nextId(), title:'Do something other than work', category:'Family', description:'', dueDate:s.add('d', -1), completed: false});\r
-       store.addTask({taskId: Task.nextId(), title:'Go to the grocery store', category:'Family', description:'', dueDate:s.add('d', -1), completed: true});\r
-       store.addTask({taskId: Task.nextId(), title:'Reboot my computer', category:'Misc', description:'', dueDate:s, completed: false});\r
-       store.addTask({taskId: Task.nextId(), title:'Respond to emails', category:'Ext', description:'', dueDate:s, completed: true});\r
-}\r
-\r
-    \r
-\r
+Ext.onReady(function(){
+    Ext.QuickTips.init();
+
+    var xg = Ext.grid;
+    // turn off default shadows which look funky in air
+    xg.GridEditor.prototype.shadow = false;
+    
+    var conn = Ext.data.SqlDB.getInstance();
+       conn.open('tasks.db');
+    
+    // the main grid store
+    var taskStore = new TaskStore(conn);
+    
+    // Category store shared by category combos
+    var catStore = new CategoryStore();
+    
+       taskStore.load({
+               callback: function(){
+                       // first time?
+                       if(taskStore.getCount() < 1){
+                               Ext.Msg.confirm('Create Tasks?', 'Your database is currently empty. Would you like to insert some demo data?', 
+                                       function(btn){
+                                               if(btn == 'yes'){
+                                                       loadDemoTasks(taskStore);       
+                                               }
+                                               catStore.init(taskStore);
+                                       });
+                       }else{
+                               catStore.init(taskStore);
+                       }
+               }
+       });
+
+    // custom event to notify when a new category is available
+    taskStore.on('newcategory', catStore.addCategory, catStore);
+
+    // set of event handlers shared by combos to allow them to share
+    // the same local store
+    var comboEvents = {
+        focus: function(){
+            this.bindStore(catStore);
+        },
+        blur: function(c){
+            catStore.purgeListeners();
+        }
+    }
+
+    var completeColumn = new CompleteColumn();
+
+    // custom template for the grid header
+    var headerTpl = new Ext.Template(
+        '<table border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
+        '<thead><tr class="x-grid3-hd-row">{cells}</tr></thead>',
+        '<tbody><tr class="new-task-row">',
+            '<td><div id="new-task-icon"></div></td>',
+            '<td><div class="x-small-editor" id="new-task-title"></div></td>',
+            '<td><div class="x-small-editor" id="new-task-cat"></div></td>',
+            '<td><div class="x-small-editor" id="new-task-due"></div></td>',
+        '</tr></tbody>',
+        "</table>"
+    );
+
+    var selections = new Ext.grid.RowSelectionModel();
+
+    // The main grid in all its configuration option glory
+    var grid = new xg.EditorGridPanel({
+        id:'tasks-grid',
+        store: taskStore,
+        sm: selections,
+        clicksToEdit: 'auto',
+        enableColumnHide:false,
+        enableColumnMove:false,
+               border:false,
+               title:'All Tasks',
+               iconCls:'icon-show-all',
+               region:'center',
+               
+        plugins: completeColumn,
+
+        columns: [
+            completeColumn,
+            {
+                header: "Task",
+                width:400,
+                sortable: true,
+                dataIndex: 'title',
+                id:'task-title',
+                editor: new Ext.form.TextField({
+                    allowBlank: false
+                })
+            },
+            {
+                header: "Category",
+                width:150,
+                sortable: true,
+                dataIndex: 'category',
+                editor: new Ext.form.ComboBox({
+                    displayField: 'text',
+                    triggerAction: 'all',
+                    mode:'local',
+                    selectOnFocus:true,
+                    listClass:'x-combo-list-small',
+                    listeners: comboEvents
+                })
+            },
+            {
+                header: "Due Date",
+                width: 150,
+                sortable: true,
+                renderer: Ext.util.Format.dateRenderer('D m/d/Y'),
+                dataIndex: 'dueDate',
+                groupRenderer: textDate(),
+                groupName: 'Due',
+                editor: new Ext.form.DateField({
+                    format : "m/d/Y"
+                })
+            }
+        ],
+
+        view: new Ext.grid.GroupingView({
+            forceFit:true,
+            ignoreAdd: true,
+            emptyText: 'No Tasks to display',
+
+            templates: {
+                header: headerTpl
+            },
+
+            getRowClass : function(r){
+                var d = r.data;
+                if(d.completed){
+                    return 'task-completed';
+                }
+                if(d.dueDate && d.dueDate.getTime() < new Date().clearTime().getTime()){
+                    return 'task-overdue';
+                }
+                return '';
+            }
+        })
+    });
+
+    var viewPanel = new Ext.Panel({
+       frame:true,
+       title: 'Views',
+       collapsible:true,
+       contentEl:'task-views',
+       titleCollapse: true
+    });
+    
+    var taskActions = new Ext.Panel({
+       frame:true,
+       title: 'Task Actions',
+       collapsible:true,
+       contentEl:'task-actions',
+       titleCollapse: true
+    });
+    
+    var groupActions = new Ext.Panel({
+       frame:true,
+       title: 'Task Grouping',
+       collapsible:true,
+       contentEl:'task-grouping',
+       titleCollapse: true
+    });
+    
+    var actionPanel = new Ext.Panel({
+       id:'action-panel',
+       region:'west',
+       split:true,
+       collapsible: true,
+       collapseMode: 'mini',
+        header: false,
+       width:200,
+       minWidth: 150,
+       border: false,
+       baseCls:'x-plain',
+       items: [taskActions, viewPanel, groupActions]
+    });
+
+    if(Ext.isAir){ // create AIR window
+        var win = new Ext.air.MainWindow({
+            layout:'border',
+            items: [actionPanel, grid],
+            title: 'Simple Tasks',
+            iconCls: 'icon-show-all'
+        }).render();
+       }else{
+        var viewport = new Ext.Viewport({
+            layout:'border',
+            items: [actionPanel, grid]
+        });
+    }
+
+    var ab = actionPanel.body;
+    ab.on('mousedown', doAction, null, {delegate:'a'});
+       ab.on('click', Ext.emptyFn, null, {delegate:'a', preventDefault:true});
+
+    grid.on('resize', syncFields);
+       grid.on('columnresize', syncFields);
+
+    grid.on('afteredit', function(e){
+        if(e.field == 'category'){
+            catStore.addCategory(e.value);
+        }
+        if(e.field == taskStore.getGroupState()){
+            taskStore.applyGrouping();
+        }
+
+    });
+
+    grid.on('keydown', function(e){
+         if(e.getKey() == e.DELETE && !grid.editing){
+             actions['action-delete']();
+         }
+    });
+
+    selections.on('selectionchange', function(sm){
+       var bd = taskActions.body, c = sm.getCount();
+       bd.select('li:not(#new-task)').setDisplayed(c > 0);
+       bd.select('span.s').setDisplayed(c > 1);
+    });
+
+    // The fields in the grid's header
+    var ntTitle = new Ext.form.TextField({
+        renderTo: 'new-task-title',
+        emptyText: 'Add a task...'
+    });
+
+    var ntCat = new Ext.form.ComboBox({
+        renderTo: 'new-task-cat',
+        disabled:true,
+        displayField: 'text',
+        triggerAction: 'all',
+        mode:'local',
+        selectOnFocus:true,
+        listClass:'x-combo-list-small',
+        listeners: comboEvents
+    });
+
+    var ntDue = new Ext.form.DateField({
+        renderTo: 'new-task-due',
+        value: new Date(),
+        disabled:true,
+        format : "m/d/Y"
+    });
+
+    // syncs the header fields' widths with the grid column widths
+    function syncFields(){
+        var cm = grid.getColumnModel();
+        ntTitle.setSize(cm.getColumnWidth(1)-2);
+        ntCat.setSize(cm.getColumnWidth(2)-4);
+        ntDue.setSize(cm.getColumnWidth(3)-4);
+    }
+    syncFields();
+
+    var editing = false, focused = false, userTriggered = false;
+    var handlers = {
+        focus: function(){
+            focused = true;
+        },
+        blur: function(){
+            focused = false;
+            doBlur.defer(250);
+        },
+        specialkey: function(f, e){
+            if(e.getKey()==e.ENTER){
+                userTriggered = true;
+                e.stopEvent();
+                f.el.blur();
+                if(f.triggerBlur){
+                    f.triggerBlur();
+                }
+            }
+        }
+    }
+    ntTitle.on(handlers);
+    ntCat.on(handlers);
+    ntDue.on(handlers);
+
+    ntTitle.on('focus', function(){
+        focused = true;
+        if(!editing){
+            ntCat.enable();
+            ntDue.enable();
+            syncFields();
+            editing = true;
+        }
+    });
+
+    // when a field in the add bar is blurred, this determines
+    // whether a new task should be created
+    function doBlur(){
+        if(editing && !focused){
+            var title = ntTitle.getValue();
+            if(!Ext.isEmpty(title)){
+                taskStore.addTask({
+                    taskId: Task.nextId(),
+                    title: title,
+                    dueDate: ntDue.getValue()||'',
+                    description: '', // ???
+                    category: ntCat.getValue(),
+                    completed: false
+                });
+                ntTitle.setValue('');
+                if(userTriggered){ // if the entered to add the task, then go to a new add automatically
+                    userTriggered = false;
+                    ntTitle.focus.defer(100, ntTitle);
+                }
+            }
+            ntCat.disable();
+            ntDue.disable();
+            editing = false;
+        }
+    }
+       
+    var actions = {
+       'view-all' : function(){
+               taskStore.applyFilter('all');
+               grid.setTitle('All Tasks', 'icon-show-all');
+       },
+       
+       'view-active' : function(){
+               taskStore.applyFilter(false);
+               grid.setTitle('Active Tasks', 'icon-show-active');
+       },
+       
+       'view-complete' : function(){
+               taskStore.applyFilter(true);
+               grid.setTitle('Completed Tasks', 'icon-show-complete');
+       },
+       
+       'action-new' : function(){
+               ntTitle.focus();
+       },
+       
+       'action-complete' : function(){
+               selections.each(function(s){
+                       s.set('completed', true);
+               });
+            taskStore.applyFilter();
+       },
+       
+       'action-active' : function(){
+               selections.each(function(s){
+                       s.set('completed', false);
+               });
+            taskStore.applyFilter();
+       },
+       
+       'action-delete' : function(){
+               Ext.Msg.confirm('Confirm', 'Are you sure you want to delete the selected task(s)?', 
+               function(btn){
+                if(btn == 'yes'){
+                       selections.each(function(s){
+                                       taskStore.remove(s);
+                               });
+                }
+            });
+       },
+       
+       'group-date' : function(){
+               taskStore.groupBy('dueDate');
+       },
+       
+       'group-cat' : function(){
+               taskStore.groupBy('category');
+       },
+       
+       'no-group' : function(){
+               taskStore.clearGrouping();
+       }
+    };
+    
+    function doAction(e, t){
+       e.stopEvent();
+       actions[t.id]();
+    }
+    
+    
+    // generates a renderer function to be used for textual date groups
+    function textDate(){
+        // create the cache of ranges to be reused
+        var today = new Date().clearTime(true);
+        var year = today.getFullYear();
+        var todayTime = today.getTime();
+        var yesterday = today.add('d', -1).getTime();
+        var tomorrow = today.add('d', 1).getTime();
+        var weekDays = today.add('d', 6).getTime();
+        var lastWeekDays = today.add('d', -6).getTime();
+
+        return function(date){
+            if(!date) {
+                return '(No Date)';
+            }
+            var notime = date.clearTime(true).getTime();
+
+            if (notime == todayTime) {
+                return 'Today';
+            }
+            if(notime > todayTime){
+                if (notime == tomorrow) {
+                    return 'Tomorrow';
+                }
+                if (notime <= weekDays) {
+                    return date.format('l');
+                }
+            }else {
+               if(notime == yesterday) {
+                       return 'Yesterday';
+                   }
+                   if(notime >= lastWeekDays) {
+                       return 'Last ' + date.format('l');
+                   }
+            }            
+            return date.getFullYear() == year ? date.format('D m/d') : date.format('D m/d/Y');
+       }
+    }
+});
+
+/* This is used to laod some demo tasks if the task database is empty */
+function loadDemoTasks(store){
+       var s = new Date();
+       // hardcoded demo tasks
+       store.addTask({taskId: Task.nextId(), title:'Start documentation of Ext 2.0', category:'Ext', description:'', dueDate: s.add('d', 21), completed: false});
+       store.addTask({taskId: Task.nextId(), title:'Release Ext 1.l Beta 2', category:'Ext', description:'', dueDate:s.add('d', 2), completed: false});
+       store.addTask({taskId: Task.nextId(), title:'Take wife to see movie', category:'Family', description:'', dueDate:s.add('d', 2), completed: false});
+       store.addTask({taskId: Task.nextId(), title:'Finish task list demo app', category:'Ext', description:'', dueDate:s.add('d', 2), completed: false});
+       store.addTask({taskId: Task.nextId(), title:'Do something other than work', category:'Family', description:'', dueDate:s.add('d', -1), completed: false});
+       store.addTask({taskId: Task.nextId(), title:'Go to the grocery store', category:'Family', description:'', dueDate:s.add('d', -1), completed: true});
+       store.addTask({taskId: Task.nextId(), title:'Reboot my computer', category:'Misc', description:'', dueDate:s, completed: false});
+       store.addTask({taskId: Task.nextId(), title:'Respond to emails', category:'Ext', description:'', dueDate:s, completed: true});
+}
+
+    
+