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(
+ '
',
+ '
{cells}
',
+ '
',
+ '
',
+ '
',
+ '
',
+ '
',
+ '
',
+ "
"
+ );
+
+ 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',
+ 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});
+}
+
+
+
+
+
+
\ No newline at end of file