2 * Ext JS Library 0.30
\r
3 * Copyright(c) 2006-2009, Ext JS, LLC.
\r
4 * licensing@extjs.com
\r
6 * http://extjs.com/license
\r
9 // Initialize the state provider
\r
10 Ext.state.Manager.setProvider(new Ext.air.FileProvider({
\r
11 file: 'tasks.state',
\r
12 // if first time running
\r
20 defaultReminder: 480
\r
24 Ext.onReady(function(){
\r
25 Ext.QuickTips.init();
\r
27 // maintain window state automatically
\r
28 var win = new Ext.air.NativeWindow({
\r
30 instance: window.nativeWindow,
\r
31 minimizeToTray: true,
\r
32 trayIcon: 'ext-air/resources/icons/extlogo16.png',
\r
33 trayTip: 'Simple Tasks',
\r
35 text: 'Open Simple Tasks',
\r
36 handler: function(){
\r
41 handler: function(){
\r
42 air.NativeApplication.nativeApplication.exit();
\r
47 tx.data.conn.open('tasks.db');
\r
49 var grid = new TaskGrid();
\r
50 var selections = grid.getSelectionModel();
\r
53 // Shared actions used by Ext toolbars, menus, etc.
\r
55 newTask: new Ext.Action({
\r
57 iconCls: 'icon-active',
\r
58 tooltip: 'New Task',
\r
59 handler: function(){
\r
60 taskHeader.ntTitle.focus();
\r
64 deleteTask: new Ext.Action({
\r
66 iconCls: 'icon-delete-task',
\r
67 tooltip: 'Delete Task',
\r
69 handler: function(){
\r
70 Ext.Msg.confirm('Confirm', 'Are you sure you want to delete the selected task(s)?', function(btn){
\r
72 selections.each(function(s){
\r
73 tx.data.tasks.remove(s);
\r
80 complete: new Ext.Action({
\r
81 itemText: 'Mark Complete',
\r
82 iconCls: 'icon-mark-complete',
\r
83 tooltip: 'Mark Complete',
\r
85 handler: function(){
\r
86 selections.each(function(s){
\r
87 s.set('completed', true);
\r
89 tx.data.tasks.applyFilter();
\r
93 active: new Ext.Action({
\r
94 itemText: 'Mark Active',
\r
95 tooltip: 'Mark Active',
\r
96 iconCls: 'icon-mark-active',
\r
98 handler: function(){
\r
99 selections.each(function(s){
\r
100 s.set('completed', false);
\r
102 tx.data.tasks.applyFilter();
\r
106 newList: new Ext.Action({
\r
107 itemText: 'New List',
\r
108 tooltip: 'New List',
\r
109 iconCls: 'icon-list-new',
\r
110 handler: function(){
\r
111 var id = tx.data.lists.newList(false, tree.getActiveFolderId()).id;
\r
112 tree.startEdit(id, true);
\r
116 deleteList: new Ext.Action({
\r
117 itemText: 'Delete',
\r
118 tooltip: 'Delete List',
\r
119 iconCls: 'icon-list-delete',
\r
121 handler: function(){
\r
122 tree.removeList(tree.getSelectionModel().getSelectedNode());
\r
126 newFolder: new Ext.Action({
\r
127 itemText: 'New Folder',
\r
128 tooltip: 'New Folder',
\r
129 iconCls: 'icon-folder-new',
\r
130 handler: function(){
\r
131 var id = tx.data.lists.newList(true, tree.getActiveFolderId()).id;
\r
132 tree.startEdit(id, true);
\r
136 deleteFolder: new Ext.Action({
\r
137 itemText: 'Delete',
\r
138 tooltip: 'Delete Folder',
\r
139 iconCls: 'icon-folder-delete',
\r
141 handler: function(s){
\r
142 tree.removeList(tree.getSelectionModel().getSelectedNode());
\r
146 quit : new Ext.Action({
\r
148 handler: function(){
\r
149 air.NativeApplication.nativeApplication.exit();
\r
153 pasteAsTask : new Ext.Action({
\r
154 itemText: 'Paste as New Task',
\r
155 tooltip: 'Paste as New Task',
\r
156 iconCls: 'icon-paste-new',
\r
157 handler: function(){
\r
158 if(air.Clipboard.generalClipboard.hasFormat(air.ClipboardFormats.TEXT_FORMAT)){
\r
159 var text = air.Clipboard.generalClipboard.getData(air.ClipboardFormats.TEXT_FORMAT);
\r
160 tx.data.tasks.addTask({
\r
161 taskId: Ext.uniqueId(),
\r
162 title: Ext.util.Format.htmlEncode(text.replace(/[\n\r]/g, '')),
\r
163 dueDate: new Date(),
\r
165 listId: tx.data.getActiveListId(),
\r
170 Ext.Msg.alert('Warning', 'Could not create task. The clipboard is empty.');
\r
175 tx.actions = actions;
\r
177 var menus = Ext.air.SystemMenu;
\r
179 menus.add('File', [
\r
182 actions.newFolder,
\r
185 handler: function(){
\r
186 var importer = new tx.Importer();
\r
187 importer.doImport(function(){
\r
188 tx.data.lists.load();
\r
196 handler: function(){
\r
204 menus.add('Edit', [
\r
205 actions.pasteAsTask
\r
209 var viewMenu = menus.add('View', [{
\r
212 handler: function(){
\r
213 Ext.getCmp('filter').setActiveItem(0);
\r
216 text: 'Active Tasks',
\r
218 handler: function(){
\r
219 Ext.getCmp('filter').setActiveItem(1);
\r
222 text: 'Completed Tasks',
\r
224 handler: function(){
\r
225 Ext.getCmp('filter').setActiveItem(2);
\r
229 menus.add('Help', [{
\r
231 handler: function(){
\r
232 Ext.air.NativeWindowManager.getAboutWindow().activate();
\r
237 var tree = new ListTree({
\r
239 store: tx.data.lists
\r
242 var root = tree.getRootNode();
\r
244 var listSm = tree.getSelectionModel();
\r
246 tx.data.lists.bindTree(tree);
\r
247 tx.data.lists.on('update', function(){
\r
248 tx.data.tasks.applyGrouping();
\r
249 if(grid.titleNode){
\r
250 grid.setTitle(grid.titleNode.text);
\r
254 var tb = new Ext.Toolbar({
\r
259 xtype:'splitbutton',
\r
260 iconCls:'icon-edit',
\r
262 handler: actions.newTask.initialConfig.handler,
\r
263 menu: [actions.newTask, actions.newList, actions.newFolder]
\r
265 actions.deleteTask,
\r
269 actions.pasteAsTask,
\r
275 tooltip:'All Tasks',
\r
277 iconCls:'icon-all',
\r
280 tooltip:'Active Tasks',
\r
282 iconCls:'icon-active',
\r
285 tooltip:'Completed Tasks',
\r
287 iconCls:'icon-complete',
\r
291 change: function(btn, item){
\r
292 tx.data.tasks.applyFilter(item.filter);
\r
293 for (var i = 0; i < 3; i++) {
\r
294 viewMenu.items[i].checked = item.menuIndex === i;
\r
297 delay: 10 // delay gives user instant click feedback before filtering tasks
\r
303 var viewport = new Ext.Viewport({
\r
305 items: [tb, tree, grid]
\r
308 grid.on('keydown', function(e){
\r
309 if(e.getKey() == e.DELETE && !grid.editing){
\r
310 actions.deleteTask.execute();
\r
314 tree.el.on('keydown', function(e){
\r
315 if(e.getKey() == e.DELETE && !tree.editor.editing){
\r
316 actions.deleteList.execute();
\r
320 selections.on('selectionchange', function(sm){
\r
321 var disabled = sm.getCount() < 1;
\r
322 actions.complete.setDisabled(disabled);
\r
323 actions.active.setDisabled(disabled);
\r
324 actions.deleteTask.setDisabled(disabled);
\r
327 var taskHeader = new TaskHeader(grid);
\r
330 win.instance.activate();
\r
332 tx.data.tasks.init();
\r
334 tree.root.select();
\r
336 var loadList = function(listId){
\r
337 var node = tree.getNodeById(listId);
\r
338 if(node && !node.isSelected()){
\r
342 actions.deleteList.setDisabled(!node || !node.attributes.editable);
\r
343 actions.deleteFolder.setDisabled(!node || node.attributes.editable === false || !node.attributes.isFolder);
\r
345 if (node.attributes.isFolder) {
\r
347 node.cascade(function(n){
\r
348 if (!n.attributes.isFolder) {
\r
349 lists.push(n.attributes.id);
\r
352 tx.data.tasks.loadList(lists);
\r
355 tx.data.tasks.loadList(node.id);
\r
357 grid.titleNode = node;
\r
358 grid.setTitle(node.text);
\r
359 grid.setIconClass(node.attributes.iconCls);
\r
363 listSm.on('selectionchange', function(t, node){
\r
364 loadList(node ? node.id : null);
\r
369 if(Ext.state.Manager.get('defaultReminder') === undefined){
\r
370 Ext.state.Manager.set('defaultReminder', 9 * 60); // default to 9am
\r
373 win.on('closing', function(){
\r
374 Ext.air.NativeWindowManager.closeAll();
\r
377 tx.ReminderManager.init();
\r
379 grid.body.on('dragover', function(e){
\r
380 if(e.hasFormat(Ext.air.DragType.TEXT)){
\r
381 e.preventDefault();
\r
385 grid.body.on('drop', function(e){
\r
386 if(e.hasFormat(Ext.air.DragType.TEXT)){
\r
387 var text = e.getData(Ext.air.DragType.TEXT);
\r
390 if(text.indexOf("Subject\t") != -1){
\r
391 var tasks = text.split("\n");
\r
392 for(var i = 1, len = tasks.length; i < len; i++){
\r
393 var data = tasks[i].split("\t");
\r
394 var list = tx.data.lists.findList(data[2]);
\r
395 tx.data.tasks.addTask({
\r
396 taskId: Ext.uniqueId(),
\r
397 title: Ext.util.Format.htmlEncode(data[0]),
\r
398 dueDate: Date.parseDate(data[1], 'D n/j/Y') || '',
\r
400 listId: list ? list.id : tx.data.getActiveListId(),
\r
406 tx.data.tasks.addTask({
\r
407 taskId: Ext.uniqueId(),
\r
408 title: Ext.util.Format.htmlEncode(text),
\r
409 dueDate: new Date(),
\r
411 listId: tx.data.getActiveListId(),
\r
417 air.trace('An error occured trying to import drag drop tasks.');
\r