From b34e3fa7aab59a88f1da50b24757029329cac966 Mon Sep 17 00:00:00 2001 From: Morgan McMillian Date: Tue, 6 Mar 2012 14:32:49 -0500 Subject: [PATCH] initial import of beta source tree --- .gitignore | 4 + app/LICENSE-2.0.txt | 202 +++++++++++ app/appinfo.json | 22 ++ app/depends.js | 11 + app/framework_config.json | 3 + app/icon.png | Bin 0 -> 1531 bytes app/images/menu-icon-new.png | Bin 0 -> 1293 bytes app/images/menu-icon-prefs.png | Bin 0 -> 4208 bytes app/images/menu-icon-sync.png | Bin 0 -> 2897 bytes app/index.html | 25 ++ app/mock/todoTxt_getConn.json | 4 + app/mock/todoTxt_makeDir.json | 1 + app/mock/todoTxt_readFile.json | 5 + app/mock/todoTxt_writeFile.json | 5 + app/source/Dropbox.js | 223 ++++++++++++ app/source/TodoEdit.js | 40 +++ app/source/TodoList.js | 363 ++++++++++++++++++++ app/source/TodoPrefs.js | 193 +++++++++++ app/source/TodoTxt.js | 358 +++++++++++++++++++ app/source/dropbox-auth.js.sample | 9 + app/source/oauth.js | 551 ++++++++++++++++++++++++++++++ app/source/sha1.js | 202 +++++++++++ app/source/styles.css | 35 ++ pkg/packageinfo.json | 10 + srv/MakeDirAssistant.js | 12 + srv/ReadDirAssistant.js | 10 + srv/ReadFileAssistant.js | 16 + srv/WriteFileAssistant.js | 11 + srv/framework_config.json | 3 + srv/services.json | 32 ++ srv/sources.json | 7 + 31 files changed, 2357 insertions(+) create mode 100644 .gitignore create mode 100644 app/LICENSE-2.0.txt create mode 100644 app/appinfo.json create mode 100644 app/depends.js create mode 100644 app/framework_config.json create mode 100644 app/icon.png create mode 100644 app/images/menu-icon-new.png create mode 100644 app/images/menu-icon-prefs.png create mode 100644 app/images/menu-icon-sync.png create mode 100644 app/index.html create mode 100644 app/mock/todoTxt_getConn.json create mode 100644 app/mock/todoTxt_makeDir.json create mode 100644 app/mock/todoTxt_readFile.json create mode 100644 app/mock/todoTxt_writeFile.json create mode 100644 app/source/Dropbox.js create mode 100644 app/source/TodoEdit.js create mode 100644 app/source/TodoList.js create mode 100644 app/source/TodoPrefs.js create mode 100644 app/source/TodoTxt.js create mode 100644 app/source/dropbox-auth.js.sample create mode 100644 app/source/oauth.js create mode 100644 app/source/sha1.js create mode 100644 app/source/styles.css create mode 100644 pkg/packageinfo.json create mode 100644 srv/MakeDirAssistant.js create mode 100644 srv/ReadDirAssistant.js create mode 100644 srv/ReadFileAssistant.js create mode 100644 srv/WriteFileAssistant.js create mode 100644 srv/framework_config.json create mode 100644 srv/services.json create mode 100644 srv/sources.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..86c8a7d --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.swp +*.ipk +*.*~ +dropbox-auth.js diff --git a/app/LICENSE-2.0.txt b/app/LICENSE-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/app/LICENSE-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/app/appinfo.json b/app/appinfo.json new file mode 100644 index 0000000..97e0d55 --- /dev/null +++ b/app/appinfo.json @@ -0,0 +1,22 @@ +{ + "id": "com.monkeystew.todotxtenyo.beta", + "version": "0.1.0", + "vendor": "Monkeystew", + "type": "web", + "main": "index.html", + "title": "Todo.txt Enyo beta", + "icon": "icon.png", + "uiRevision": 2, + "universalSearch": { + "search": { + "displayName":"Todo.txt Enyo", + "url":"com.monkeystew.todotxtenyo.beta", + "launchParam":"search" + }, + "action": { + "displayName":"New todo.txt task", + "url":"com.monkeystew.todotxtenyo.beta", + "launchParam":"addTodoText" + } + } +} diff --git a/app/depends.js b/app/depends.js new file mode 100644 index 0000000..7cbadb1 --- /dev/null +++ b/app/depends.js @@ -0,0 +1,11 @@ +enyo.depends( + "source/TodoTxt.js", + "source/TodoList.js", + "source/TodoEdit.js", + "source/TodoPrefs.js", + "source/dropbox-auth.js", + "source/Dropbox.js", + "source/oauth.js", + "source/sha1.js", + "source/styles.css" +); diff --git a/app/framework_config.json b/app/framework_config.json new file mode 100644 index 0000000..9624b26 --- /dev/null +++ b/app/framework_config.json @@ -0,0 +1,3 @@ +{ + "logLevel": 99 +} diff --git a/app/icon.png b/app/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..abc335734a67f5434d3ea904ed210268aae3eb5c GIT binary patch literal 1531 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 Dxz=Ig literal 0 HcmV?d00001 diff --git a/app/images/menu-icon-prefs.png b/app/images/menu-icon-prefs.png new file mode 100644 index 0000000000000000000000000000000000000000..f703d7e4e5b001d11c63f0f19946d89bc5a28cec GIT binary patch literal 4208 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 literal 0 HcmV?d00001 diff --git a/app/index.html b/app/index.html new file mode 100644 index 0000000..bb93b50 --- /dev/null +++ b/app/index.html @@ -0,0 +1,25 @@ + + + + Todo.txt Enyo + + + + + + + + diff --git a/app/mock/todoTxt_getConn.json b/app/mock/todoTxt_getConn.json new file mode 100644 index 0000000..b1c3a51 --- /dev/null +++ b/app/mock/todoTxt_getConn.json @@ -0,0 +1,4 @@ +{ +"returnValue": true, +"isInternetConnectionAvailable": false +} diff --git a/app/mock/todoTxt_makeDir.json b/app/mock/todoTxt_makeDir.json new file mode 100644 index 0000000..c44f3a7 --- /dev/null +++ b/app/mock/todoTxt_makeDir.json @@ -0,0 +1 @@ +{ "returnValue": true } diff --git a/app/mock/todoTxt_readFile.json b/app/mock/todoTxt_readFile.json new file mode 100644 index 0000000..835a97b --- /dev/null +++ b/app/mock/todoTxt_readFile.json @@ -0,0 +1,5 @@ +{ "returnValue": true, + "path": "/dummy", + "content": "x TEST ENTRY 2\n(C) Alpha TEST ENTRY 1\n(A) Beta TEST ENTRY 3\nTEST ENTRY 4\n(B) Some TEST ENTRY 5\n+TestProject1 @Bug this is my next bug for testing\n+someotherp testing some other one\n" + +} diff --git a/app/mock/todoTxt_writeFile.json b/app/mock/todoTxt_writeFile.json new file mode 100644 index 0000000..b463932 --- /dev/null +++ b/app/mock/todoTxt_writeFile.json @@ -0,0 +1,5 @@ +{ +"returnValue": true, +"path": "no dummy", +"bytes": "no bytes either" +} diff --git a/app/source/Dropbox.js b/app/source/Dropbox.js new file mode 100644 index 0000000..48158bd --- /dev/null +++ b/app/source/Dropbox.js @@ -0,0 +1,223 @@ +/* + * Copyright 2012 Morgan McMillian + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +enyo.kind({ + name: "Dropbox", + kind: enyo.Control, + published: { + token: "", + tokenSecret: "", + requestToken: "", + requestSecret: "", + authorized: false + }, + events: { + "onAuthSuccess": "", + "onAuthFailure": "", + "onGetFileSuccess": "", + "onGetFileFailure": "", + "onPutFileSuccess": "", + "onPutFileFailure": "", + "onMetadataSuccess": "", + "onMetadataFailure": "" + }, + components: [ + {name: "authPopup", kind: "ModalDialog", components: [ + {content: "Please click DONE to complete the process."}, + {kind:"Button", caption:"DONE", onclick:"requestAccessToken"} + ]}, + {name: "launch", kind: "PalmService", + service: "palm://com.palm.applicationManager", + method: "launch", onSuccess: "launchSuccess", + onFailure: "launchFailed" + }, + {name: "webSrv", kind: "WebService" } + ], + + create: function() { + this.inherited(arguments); + + this.contentURL = "https://api-content.dropbox.com/1"; + this.apiURL = "https://api.dropbox.com/1"; + this.mainURL = "https://www.dropbox.com/1"; + + /* valid values are either "dropbox" or "sandbox" + * + * See the following URL for the additional details. + * https://www.dropbox.com/developers/reference/api + */ + this.root = "dropbox"; + + /* The following two properties are contained in the + * dropbox-auth.js file. Dropbox will NOT work unless you + * update the file to contain the correct values. + */ + this.consumerKey = consumerKey; + this.consumerSecret = consumerSecret; + }, + + /* url - URL needed for a web service call + * params - (optional) Object containing paramters for the request + * body - (required for files_put) request body to be submitted + * method - method required for the request (GET, POST, PUT) + * onSuccess - callback function when web service call is successful + * onFailure - callback function when web service call has failed + */ + dropboxCall: function(url, params, body, method, onSuccess, onFailure) { + + var token = (this.authorized) ? this.token : this.requestToken; + var secret = (this.authorized) ? this.tokenSecret : this.requestSecret; + + var accessor = { + consumerKey: this.consumerKey, + consumerSecret: this.consumerSecret, + token: token, + tokenSecret: secret + }; + + var message = { + action: url, + method: method, + parameters: params + }; + + OAuth.completeRequest(message, accessor); + OAuth.SignatureMethod.sign(message, accessor); + var post = OAuth.formEncode(message.parameters); + + if (url.match(/files_put/)) { + requrl = url + "?" + post; + this.$.webSrv.setContentType("text/plain"); + } else { + body = post; + requrl = url; + } + + this.$.webSrv.setUrl(requrl); + this.$.webSrv.setMethod(method); + this.$.webSrv.onSuccess = onSuccess; + this.$.webSrv.onFailure = onFailure; + this.$.webSrv.call(body); + }, + + /* ******************** OAuth Functions ******************** */ + + validateAccess: function() { + if (this.token.length > 0 && this.tokenSecret.length > 0) { + var url = this.apiURL + "/account/info"; + this.dropboxCall(url, {}, "", "POST", + "doAuthSuccess", "doAuthFailure"); + } else { + this.$.authPopup.openAtCenter(); + this.startTokenRequest(); + } + }, + + startTokenRequest: function() { + var url = this.apiURL + "/oauth/request_token"; + this.dropboxCall(url, {}, "", "POST", + "processRequestToken", "doAuthFailure"); + }, + + processRequestToken: function(inSender, inResponse, inRequest) { + if (inResponse) { + var url = this.mainURL + "/oauth/authorize?" + inResponse; + + var tokens = inResponse.split("&"); + this.requestSecret = tokens[0].split("=")[1]; + this.requestToken = tokens[1].split("=")[1]; + + console.log("...launching browser window..."); + this.$.launch.call({ + "id": "com.palm.app.browser", + "params": {"target": url} + }); + } + }, + + requestAccessToken: function() { + var url = this.apiURL + "/oauth/access_token"; + this.dropboxCall(url, {}, "", "POST", + "processAccessToken", "doAuthFailure"); + }, + + processAccessToken: function(inSender, inResponse, inRequest) { + var tokens = inResponse.split("&"); + var accessSecret = tokens[0].split("=")[1]; + var accessToken = tokens[1].split("=")[1]; + + this.token = accessToken; + this.tokenSecret = accessSecret; + console.log("..authorized.."); + //console.log(this.token); + //console.log(this.tokenSecret); + this.authorized = true; + this.doAuthSuccess(); + this.$.authPopup.close(); + }, + + + /* ******************** Dropbox REST API ******************** */ + + + /* file - Relative path of file to be uploaded. + * data - File contents to be uploaded. + * params - (optional) Object containing additional parameters. + * + * Returns the metadata for the uploaded file. + * + * See the following URL for the additional details + * https://www.dropbox.com/developers/reference/api#files_put + */ + putFile: function(file, data, params) { + var url = this.contentURL+"/files_put/"+this.root+file; + this.dropboxCall(url, params, data, "PUT", + "doPutFileSuccess", "doPutFileFailure"); + }, + + /* file - Relative path of file to be retrieved + * rev - (optional) File revision to be retrieved. Defaults to + * the most recent revision. + * + * Returns the file contents at the requested revision. The + * HTTP response contains the content metadata in JSON format + * within an x-dropbox-metadata header. + * + * See the following URL for the additional details. + * https://www.dropbox.com/developers/reference/api#files_put + */ + getFile: function(file, rev) { + var url = this.contentURL+"/files/"+this.root+file; + var params = { rev: rev }; + this.dropboxCall(url, params, "", "GET", + "doGetFileSuccess", "doGetFileFailure"); + }, + + /* path - path to a file or folder + * params - (optional) Object containing additional parameters. + * + * Returns metadata for requested file or folder + * + * See the following URL for the additional details + * https://www.dropbox.com/developers/reference/api#metadata + */ + getMetadata: function(path, params) { + var url = this.apiURL+"/metadata/"+this.root+path; + this.dropboxCall(url, params, "", "GET", + "doMetadataSuccess", "doMetadataFailure"); + } + +}); diff --git a/app/source/TodoEdit.js b/app/source/TodoEdit.js new file mode 100644 index 0000000..dc7b24a --- /dev/null +++ b/app/source/TodoEdit.js @@ -0,0 +1,40 @@ +/* + * Copyright 2012 Morgan McMillian + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +enyo.kind({ + name: "TodoEdit", + kind: enyo.VFlexBox, + events: { + "onClose": "", + "onSave": "" + }, + components: [ + + {flex: 1, kind: "Scroller", components: [ + {kind: "RichText", name: "tododetail"}, + ]}, + {name: "editToolbar", kind: "Toolbar", pack: "justify", className: "enyo-toolbar-light", + components: [ + {flex: 1, kind: "Button", caption: "Cancel", + onclick: "doClose", align: "left"}, + {flex: 1, kind: "Button", caption: "Save", + onclick: "doSave", align: "right"} + ] + } + + ] + +}); diff --git a/app/source/TodoList.js b/app/source/TodoList.js new file mode 100644 index 0000000..b922aff --- /dev/null +++ b/app/source/TodoList.js @@ -0,0 +1,363 @@ +/* + * Copyright 2012 Morgan McMillian + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +enyo.kind({ + name: "TodoList", + kind: enyo.VFlexBox, + published: { + replaceItem: false, + completeItem: false, + sortOrder: "pri", + cacheChanges: "NO", + searchFilter: null, + sortedList: undefined + }, + events: { + "onEdit": "", + "onPrefs": "", + "onReload": "" + }, + components: [ + + {name: "todoPopup", kind: "ModalDialog", components: [ + {kind: "Button", caption: "Complete", onclick: "completeTodoItem"}, + {kind: "Button", caption: "Prioritize", onclick: "showPriList"}, + {kind: "Button", caption: "Update", onclick: "updateTodoItem"}, + {kind: "Button", caption: "Delete", onclick: "deleteTodoItem"}, + {kind: "Button", caption: "Dismiss", onclick: "closePopup"} + ]}, + {name: "completedPopup", kind: "ModalDialog", components: [ + {kind: "Button", caption: "Undo Complete", onclick: "undoCompleteTodoItem"}, + {kind: "Button", caption: "Delete", onclick: "deleteTodoItem"}, + {kind: "Button", caption: "Dismiss", onclick: "closePopup"} + ]}, + {name: "priorityPopup", kind: "ModalDialog", components: [ + {kind: "HtmlContent", content: "Select priority"}, + {kind: "RadioGroup", name: "priGroup", onChange: "setPriority", components: [ + {caption: "-", value: "-"}, + {caption: "A", value: "A"}, + {caption: "B", value: "B"}, + {caption: "C", value: "C"}, + {caption: "D", value: "D"}, + {caption: "E", value: "E"} + ]}, + {kind: "Button", caption: "Dismiss", onclick: "closePopup"} + ]}, + {kind: "SearchInput", name: "searchbox", onchange: "searchList", onCancel: "clearSearch"}, + {flex: 1, kind: "Scroller", name: "scroller", components: [ + {kind: "VirtualRepeater", name: "todoList", + onSetupRow: "getTodoList", onclick: "todoTap", + components: [ + {kind: "SwipeableItem", onConfirm: "deleteTodo", + layoutKind: enyo.HFlexLayout, tapHighlight: true, name: "todoRow", + components: [ + {name: "lineNum", className: "left-col"}, + {name: "priority", className: "mid-col"}, + {flex: 1, name: "todoItem"} + ] + } + ] + } + ]}, + {name: "listToolbar", kind: "Toolbar", pack: "justify", className: "enyo-toolbar-light", + components: [ + {flex: 1}, + //{kind: "Button", caption: "Filter"}, + //TODO: consider moving to the top + {kind: "ListSelector", value: "pri", + onChange: "changeSort", items: [ + {caption: "Priority", value: "pri"}, + {caption: "ID Ascending", value: "asc"}, + {caption: "ID Descending", value: "dsc"}, + {caption: "Text (A-Z)", value: "az"} + ]}, + {icon: "images/menu-icon-new.png", + onclick: "doEdit", align: "right"}, + {icon: "images/menu-icon-sync.png", + onclick: "doReload", align: "right"}, + {icon: "images/menu-icon-prefs.png", + onclick: "doPrefs", align: "right"} + ] + }, + + ], + + getTodoList: function(inSender, inIndex) { + + if (this.sortedList == undefined) { + this.sortedList = this.owner.todoList.slice(0); + this.changeSort(null, this.sortOrder, null); + } + + var r = this.sortedList[inIndex]; + + if (r) { + var filtered = false; + var s = r.detail.replace(/^x\s/,""); + var s = s.replace(/^\([A-E]\)\s/,""); + var filter = new RegExp(this.searchFilter, "i"); + if (this.search && s.match(filter)) { + filtered = true; + } else if (!this.search) { + filtered = true; + } + if (this.owner.preferences["lineNumbers"]) { + this.$.lineNum.setContent(r.num); + } + this.$.priority.setContent(r.pri); + var pri = r.detail.replace(/^\(([A-E])\)\s.*$/,"$1"); + if (r.pri == "(A) ") this.$.priority.addClass("pri-a"); + if (r.pri == "(B) ") this.$.priority.addClass("pri-b"); + if (r.pri == "(C) ") this.$.priority.addClass("pri-c"); + this.$.todoItem.setContent(s); + if (r.detail.match(/^x\s/)) { + this.$.todoItem.addStyles("text-decoration:line-through;"); + this.$.todoItem.addClass("completed-item"); + } + if (inIndex == this.selectedIndex) { + this.$.todoRow.addClass("selected-item"); + } + if (!filtered) { + this.$.todoRow.hide(); + } + return true; + } + }, + + todoTap: function(inSender, inEvent) { + this.selectedIndex = inEvent.rowIndex; + if (this.selectedIndex != undefined) { + this.selectedId = this.sortedList[this.selectedIndex].num-1; + } + var r = this.sortedList[inEvent.rowIndex]; + + if (r) { + var completed = r.detail.match(/^x\s/); + var quick = this.owner.preferences["quickComplete"]; + if (completed) { + this.$.completedPopup.openAtCenter(); + } else if (quick) { + this.completeTodoItem(); + } else { + this.$.todoPopup.openAtCenter(); + } + } + this.$.todoList.render(); + }, + + completeTodoItem: function() { + this.completeItem = true; + var dfmt = new enyo.g11n.DateFmt({date:"yyyy-MM-dd"}); + this.cacheChanges = "START"; + this.clearPriority(); + this.owner.$.editView.$.tododetail.setValue( + "x " + dfmt.format(new Date()) + " " + + this.owner.todoList[this.selectedId].detail + ); + this.replaceItem = true; + this.cacheChanges = "COMMIT"; + this.owner.addTodo(); + this.completeItem = false; + this.$.todoPopup.close(); + }, + + undoCompleteTodoItem: function() { + this.completeItem = true; + this.owner.$.editView.$.tododetail.setValue( + this.owner.todoList[this.selectedId].detail.replace(/^x\s[0-9]{4}-[0-9]{2}-[0-9]{2}\s/,"") + ); + this.replaceItem = true; + this.owner.addTodo(); + this.completeItem = false; + this.closePopup(); + }, + + updateTodoItem: function() { + this.owner.$.editView.$.tododetail.setValue(this.owner.todoList[this.selectedId].detail); + this.replaceItem = true; + this.owner.showEditView(); + this.$.todoPopup.close(); + }, + + addTodo: function() { + var task = new Object(); + task.num = this.owner.todoList.length + 1; + task.pri = null; + task.detail = this.owner.$.editView.$.tododetail.getValue(); + task.detail = task.detail.replace(/(<\/?[A-Za-z][A-Za-z0-9]*>)+/g," "); + if (this.owner.preferences["dateTasks"] && !this.completeItem) { + var dfmt = new enyo.g11n.DateFmt({date:"yyyy-MM-dd"}); + task.detail = dfmt.format(new Date()) + " " + task.detail; + } + if (this.owner.preferences["storage"] != "none" && this.cacheChanges != "YES" && this.cacheChanges != "COMMIT") { + console.log("saving backup"); + this.owner.saveFile( + this.owner.preferences["filepath"]+".bak", this.owner.todoList); + if (this.cacheChanges == "START") { + this.cacheChanges = "YES" + } + } + if (this.replaceItem) { + this.owner.todoList[this.selectedId].detail = task.detail; + this.owner.todoList[this.selectedId].pri = task.detail.match(/^\([A-E]\)\s/); + this.replaceItem = false; + } else { + this.owner.todoList.push(task); + } + this.listRefresh(); + if (this.owner.preferences["storage"] != "none" && this.cacheChanges != "START" && this.cacheChanges != "YES") { + console.log("saving list"); + this.owner.saveFile( + this.owner.preferences["filepath"], this.owner.todoList); + if (this.cacheChanges == "COMMIT") { + this.cacheChanges = "NO" + } + } + this.owner.closeView(); + }, + + deleteTodoItem: function() { + this.deleteTodo(null, this.selectedId); + this.closePopup(); + }, + + deleteTodo: function(inSender, inIndex) { + if (this.owner.preferences["storage"] != "none") { + this.owner.saveFile( + this.owner.preferences["filepath"]+".bak", this.owner.todoList); + } + this.owner.todoList.splice(inIndex, 1); + this.listRefresh(); + if (this.owner.preferences["storage"] != "none") { + this.owner.saveFile( + this.owner.preferences["filepath"], this.owner.todoList); + } + }, + + closePopup: function() { + this.$.todoPopup.close(); + this.$.completedPopup.close(); + this.$.priorityPopup.close(); + this.selectedIndex = null; + this.selectedId = null; + this.$.todoList.render(); + }, + + showPriList: function() { + var r = this.sortedList[this.selectedIndex]; + + this.$.todoPopup.close(); + this.$.priorityPopup.openAtCenter(); + if (r.detail.match(/^\(([A-E])\)\s/)) { + var pri = r.detail.replace(/^\(([A-E])\)\s.*$/,"$1"); + this.$.priGroup.setValue(pri); + } else { + this.$.priGroup.setValue(pri); + } + }, + + setPriority: function(inSender) { + var val = inSender.getValue(); + this.clearPriority(); + if (val.match(/[A-E]/)) { + this.owner.$.editView.$.tododetail.setValue( + "(" + val + ") " + this.owner.todoList[this.selectedId].detail); + this.replaceItem = true; + this.addTodo(); + } + this.$.priorityPopup.close(); + }, + + clearPriority: function() { + this.owner.$.editView.$.tododetail.setValue( + this.owner.todoList[this.selectedId].detail.replace(/^\([A-E]\)\s/,"") + ); + this.replaceItem = true; + this.owner.addTodo(); + }, + + searchList: function(inSender) { + this.searchFilter = inSender.getValue(); + this.searchFilter = this.searchFilter.replace(/\+/,"\\+"); + //console.log(this.searchFilter); + this.search = true; + this.$.scroller.scrollIntoView(0,0); + this.$.todoList.render(); + }, + + clearSearch: function() { + this.searchFilter = null; + this.search = false; + this.$.todoList.render(); + }, + + changeSort: function(inSender, inValue, inOldValue) { + this.sortOrder = inValue; + if (inValue == "pri") { + this.sortedList.sort(function (a,b) { + if (!a["pri"] && a["detail"].match(/^x\s/)) { + checka = "-"; + } else if (!a["pri"]) { + checka = "+"; + } else { + checka = a["pri"]; + } + if (!b["pri"] && b["detail"].match(/^x\s/)) { + checkb = "-"; + } else if (!b["pri"]) { + checkb = "+"; + } else { + checkb = b["pri"]; + } + if (checka < checkb) return -1; + if (checka > checkb) return 1; + return 0; + }); + this.$.todoList.render(); + } else if (inValue == "asc") { + this.sortedList.sort(function (a,b) { + if (a["num"] < b["num"]) return -1; + if (a["num"] > b["num"]) return 1; + return 0; + }); + this.$.todoList.render(); + } else if (inValue == "dsc") { + this.sortedList.sort(function (a,b) { + if (a["num"] > b["num"]) return -1; + if (a["num"] < b["num"]) return 1; + return 0; + }); + this.$.todoList.render(); + } else if (inValue == "az") { + this.sortedList.sort(function (a,b) { + var checka = a["detail"].replace(/^\([A-E]\)\s/,""); + var checkb = b["detail"].replace(/^\([A-E]\)\s/,""); + if (checka < checkb) return -1; + if (checka > checkb) return 1; + return 0; + }); + this.$.todoList.render(); + } else { + console.log("wait what?"); + } + }, + + listRefresh: function() { + this.sortedList = undefined; + this.$.todoList.render(); + } + +}); diff --git a/app/source/TodoPrefs.js b/app/source/TodoPrefs.js new file mode 100644 index 0000000..8149bde --- /dev/null +++ b/app/source/TodoPrefs.js @@ -0,0 +1,193 @@ +/* + * Copyright 2012 Morgan McMillian + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +enyo.kind({ + name: "TodoPrefs", + kind: enyo.VFlexBox, + events: { + "onClose": "", + "onAbout": "", + "onPrefReset": "" + }, + components: [ + + {flex: 1, kind: "Scroller", components: [ + {kind: "VFlexBox", className: "box-center", components: [ + {kind: "RowGroup", caption: "todo.txt", components: [ + {kind: "Item", layoutKind: "HFlexLayout", + components: [ + {content: "Show line numbers"}, + {kind: "Spacer"}, + {kind: "CheckBox", name: "lineNumbers", + preferenceProperty: "lineNumbers", + onChange: "setPreference"} + ]}, + {kind: "Item", layoutKind: "HFlexLayout", + components: [ + {content: "Date new tasks"}, + {kind: "Spacer"}, + {kind: "CheckBox", name: "dateTasks", + preferenceProperty: "dateTasks", + onChange: "setPreference"} + ]}, + {kind: "Item", layoutKind: "HFlexLayout", + components: [ + {content: "Quick complete"}, + {kind: "Spacer"}, + {kind: "CheckBox", name: "quickComplete", + preferenceProperty: "quickComplete", + onChange: "setPreference"} + ]}, + {kind: "Item", layoutKind: "HFlexLayout", + components: [ + {content: "Work offline"}, + {kind: "Spacer"}, + {kind: "CheckBox", name: "offline", + preferenceProperty: "offline", + onChange: "setPreference"} + ]} + ]}, + {kind: "RowGroup", caption: "storage", components: [ + {kind: "Item", layoutKind: "HFlexLayout", + components: [ + {flex: 1, kind: "ListSelector", name: "storage", + preferenceProperty: "storage", + onChange: "setPreference", + items: [ + {caption: "No Storage", value: "none"}, + {caption: "Internal Storage", value: "file"}, + {caption: "Dropbox", value: "dropbox"} + ]} + ]}, + {kind: "Item", layoutKind: "HFlexLayout", + name: "filepathselect", showing: true, + components: [ + {flex: 1, kind: "Input", name: "filepath", + preferenceProperty: "filepath", + hint: "file path", + disabled: true + } + ]}, + {kind: "Item", layoutKind: "HFlexLayout", + name: "dboxpathselect", showing: true, + components: [ + {flex: 1, kind: "Input", name: "dboxpath", + preferenceProperty: "dboxpath", + hint: "Dropbox path", + onchange: "setPreference", + disabled: false + } + ]}, + {kind: "Item", layoutKind: "HFlexLayout", + name: "dboxlogout", showing: false, + components: [ + {flex: 1, kind: "Button", + caption: "Log out of Dropbox", + className: "enyo-button-negative", + onclick: "clearDropbox" + } + ]} + ]}, + {kind: "Button", caption: "About", onclick: "doAbout", + className: "enyo-button-dark" + }, + {kind: "Button", caption: "Reset Prefs", onclick: "doPrefReset", + className: "enyo-button-dark" + } + ]} + ]}, + {name: "prefToolbar", kind: "Toolbar", pack: "justify", className: "enyo-toolbar-light", + components: [ + {kind: "Spacer"}, + {flex: 1, kind: "Button", caption: "Done", + onclick: "doClose", align: "center"}, + {kind: "Spacer"} + ] + }, + {name: "todoFilePicker", kind: "FilePicker", fileType: ["document"], + onPickFile: "fileSelected", allowMultiSelect: false} + + ], + + setPreference: function(inSender, inEvent, inValue) { + //var value = (inSender.kind === "CheckBox") ? inSender.getChecked() : inValue; + if (inSender.kind === "CheckBox") { + value = inSender.getChecked(); + } else if (inSender.kind === "Input") { + value = inValue; + } else { + value = inEvent; + } + + this.owner.preferences[inSender.preferenceProperty] = value; + + if (inSender.preferenceProperty == "storage") { + if (value == "file") { + //this.$.todoFilePicker.pickFile(); + var mypath = "/media/internal/todo/todo.txt" + this.owner.preferences["filepath"] = mypath; + this.$.filepath.setValue(mypath); + this.$.filepath.render(); + this.$.dboxlogout.hide(); + this.owner.preferences["offline"] = true; + this.owner.$.preferenceView.$.offline.setChecked(true); + this.owner.refreshTodo(); + } else if (value == "dropbox") { + this.owner.$.dropbox.validateAccess(); + } else { + this.owner.preferences["filepath"] = ""; + this.$.filepath.setValue(""); + this.$.filepath.render(); + this.$.dboxlogout.hide(); + this.owner.preferences["offline"] = true; + this.owner.$.preferenceView.$.offline.setChecked(true); + } + } else if (inSender.preferenceProperty == "dboxpath") { + //console.log(this.owner.preferences["dboxpath"]); + this.owner.dropboxRefresh = true; + this.owner.refreshTodo(); + } + + localStorage.setItem("TodoPreferences", JSON.stringify(this.owner.preferences)); + this.owner.$.listView.$.todoList.render(); + }, + + fileSelected: function(inSender, inResponse) { + //console.log(inResponse[0].fullPath); + value = inResponse[0].fullPath; + if (value) { + this.owner.preferences["filepath"] = value; + this.$.filepath.setValue(value); + this.$.filepath.render(); + this.owner.refreshTodo(); + } + }, + + clearDropbox: function() { + this.owner.preferences["dboxuid"] = ""; + this.owner.preferences["dboxtoken"] = ""; + this.owner.preferences["dboxsecret"] = ""; + this.owner.preferences["dboxname"] = ""; + this.owner.preferences["dboxrev"] = ""; + this.owner.preferences["storage"] = "file"; + this.owner.preferences["offline"] = true; + this.owner.$.preferenceView.$.offline.setChecked(true); + localStorage.setItem("TodoPreferences", JSON.stringify(this.owner.preferences)); + this.$.storage.setValue("file"); + this.$.dboxlogout.hide(); + } + +}); diff --git a/app/source/TodoTxt.js b/app/source/TodoTxt.js new file mode 100644 index 0000000..90257c1 --- /dev/null +++ b/app/source/TodoTxt.js @@ -0,0 +1,358 @@ +/* + * Copyright 2012 Morgan McMillian + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +enyo.kind({ + name: "TodoTxt", + kind: enyo.VFlexBox, + published: { + launchParams: null + }, + components: [ + + {kind: "AppMenu", components: [ + {caption: "Preferences", onclick: "showPrefView"}, + {caption: "About", onclick: "showAbout"} + ]}, + {kind: "Popup", name: "about", layoutKind: "VFlexLayout", + contentHeight: "100%", height: "80%", width: "80%", + components: [ + {name: "aboutTitle", content: ""}, + {content: "by Morgan McMillian"}, + {kind: "Divider", caption: "Version History"}, + {flex: 1, kind: "Scroller", components: [ + {kind: "HtmlContent", className: "ver-history", + srcId: "history"} + ]}, + {kind: "Button", caption: "Done", onclick: "closeAbout" } + ]}, + {kind: "PageHeader", pack: "justify", components: [ + {kind: "HtmlContent", content: "Todo.txt Enyo [beta]"}, + {flex: 1}, + {name: "viewTitle", kind: "HtmlContent", + className: "todo-view-title", content: ""} + ]}, + {flex: 1, kind: "Pane", onSelectView: "viewSelected", components: [ + {name: "listView", kind: "TodoList", onEdit: "showEditView", + onPrefs: "showPrefView", onReload: "refreshTodo" + }, + {name: "editView", kind: "TodoEdit", + onClose: "closeView", onSave: "addTodo" + }, + {name: "preferenceView", kind: "TodoPrefs", + onClose: "closeView", onAbout: "showAbout", + onPrefReset: "resetPreferences" + } + ]}, + {name: "dropbox", kind: "Dropbox", + onAuthSuccess: "enableDropbox", + onAuthFailure: "disableDropbox", + onGetFileSuccess: "loadDropbox", + onGetFileFailure: "fail", + onPutFileSuccess: "dboxPutFileSuccess", + onPutFileFailure: "fail" + }, + {name: "readFile", kind: "PalmService", + service: "palm://com.monkeystew.todotxtenyo.beta.service/", + method: "readfile", + onSuccess: "parseFile", onFailure: "doNothing" + }, + {name: "writeFile", kind: "PalmService", + service: "palm://com.monkeystew.todotxtenyo.beta.service/", + method: "writefile", onSuccess: "saveSuccess" + }, + {name: "makeDir", kind: "PalmService", + service: "palm://com.monkeystew.todotxtenyo.beta.service/", + method: "makedir", onSuccess: "dirCreated", + onFailure: "doNothing" + }, + {name: "getConn", kind: "PalmService", + service: "palm://com.palm.connectionmanager/", + method: "getstatus", + onSuccess: "handleConnectionChange", + subscribe: true + } + + ], + + ready: function() { + this.$.getConn.call(); + + this.preferences = localStorage.getItem("TodoPreferences"); + if (this.preferences == undefined) { + this.resetPreferences(); + } else { + this.preferences = JSON.parse(this.preferences); + } + + if (this.preferences["storage"] == "dropbox") { + if (this.preferences["dboxtoken"]) { + this.$.dropbox.setToken( + this.preferences["dboxtoken"] + ); + this.$.dropbox.setTokenSecret( + this.preferences["dboxsecret"] + ); + this.$.dropbox.setAuthorized(true); + this.$.preferenceView.$.dboxlogout.show(); + this.$.preferenceView.$.dboxpathselect.show(); + this.$.preferenceView.$.filepathselect.hide(); + } + } + + //TODO: need to derive a better method for introducing new + //preferences into the application + + if (this.preferences["dboxpath"] == undefined) { + this.preferences["dboxpath"] = "/todo"; + localStorage.setItem("TodoPreferences", JSON.stringify(this.preferences)); + } + + if (this.preferences["offline"] == true) { + this.$.viewTitle.setContent("[offline]"); + } + + this.$.makeDir.call({ path: "/media/internal/todo" }); + + this.todoList = []; + this.refreshTodo(); + + }, + + launchParamsChanged: function() { + if (this.launchParams) { + if (this.launchParams.addTodoText) { + this.$.editView.$.tododetail.setValue( + this.launchParams.addTodoText + ); + this.showEditView(); + } else if (this.launchParams.search) { + this.$.listView.$.searchbox.setValue( + this.launchParams.search + ); + this.$.listView.$.searchbox.fire("onchange"); + } + } + }, + + viewSelected: function(inSender, inView) { + if (inView == this.$.listView) { + if (this.preferences["offline"] == true) { + this.$.viewTitle.setContent("[offline]"); + } else { + this.$.viewTitle.setContent(""); + } + } else if (inView == this.$.preferenceView) { + this.$.viewTitle.setContent("preferences"); + } + }, + + refreshTodo: function() { + if (this.preferences["storage"] == "file") { + this.getLocalFile(); + } else if (this.preferences["storage"] == "dropbox") { + if (this.preferences["offline"] == false) { + var dboxpath = this.preferences["dboxpath"]; + this.$.dropbox.getFile(dboxpath+"/todo.txt"); + } else { + console.log("working offline, loading local copy instead"); + this.getLocalFile(); + } + } + }, + + addTodo: function() { + this.$.listView.addTodo(); + }, + + showEditView: function() { + this.$.pane.selectViewByName("editView"); + if (this.$.listView.getReplaceItem()) { + this.$.viewTitle.setContent("update task"); + } else { + this.$.viewTitle.setContent("add task"); + } + this.$.editView.$.tododetail.forceFocus(); + }, + + showPrefView: function() { + for ( item in this.preferences ) { + var component = eval("this.$.preferenceView.$."+item); + if (component != undefined) { + if (component.kind === "CheckBox") { + component.setChecked(this.preferences[component.preferenceProperty]); + } else { + component.setValue(this.preferences[component.preferenceProperty]); + } + } + } + this.$.pane.selectViewByName("preferenceView"); + }, + + showAbout: function() { + this.$.about.openAtCenter(); + this.$.aboutTitle.setContent( + "Todo.txt Enyo [beta] v" + enyo.fetchAppInfo().version); + this.$.about.render(); + }, + + closeAbout: function() { + this.$.about.close(); + }, + + closeView: function() { + this.$.editView.$.tododetail.setValue(""); + this.$.pane.selectViewByName("listView"); + }, + + parseFile: function(path, file) { + var todofile = file.content.split("\n"); + this.todoList = []; + for (line in todofile) { + if (todofile[line]) { + if (typeof line == "string") { + line = parseInt(line, 10); + } + var task = new Object(); + task.num = line + 1; + task.pri = todofile[line].match(/^\([A-E]\)\s/); + task.detail = todofile[line]; + this.todoList.push(task); + } + } + this.$.listView.setSortedList(undefined); + this.$.listView.$.todoList.render(); + console.log("row count: " + this.todoList.length); + }, + + saveFile: function(path, list) { + data = ""; + for (item in list) { + data = data + list[item].detail + "\n"; + } + this.$.writeFile.call({ + path: path, content: data }); + + if (this.preferences["storage"] == "dropbox" && + this.preferences["offline"] == false && + this.dropboxRefresh == false) { + var filename = path.match(/todo\.txt.*/); + filename = this.preferences["dboxpath"]+"/"+filename; + //var params = { overwrite: true }; + this.$.dropbox.putFile(filename, data); + } else if (this.dropboxRefresh == true) { + this.dropboxRefresh = false; + } + }, + + saveSuccess: function(inSender, inEvent) { + if (inEvent.error) { + console.log("error: "+inEvent.error.message); + } else { + enyo.windows.addBannerMessage(inEvent.path + " saved", "{}"); + console.log(inEvent.path + " saved..."); + console.log(inEvent.bytes + " bytes..."); + } + }, + + dboxPutFileSuccess: function(inSender, inResponse) { + console.log(inResponse.path + " uploaded to Dropbox"); + console.log("at revision " + inResponse.revision); + console.log(inResponse.size + " bytes..."); + }, + + doNothing: function(inSender) { + console.log("errrr"); + console.log(":: " + inSender); + }, + + dirCreated: function(inSender, inEvent) { + if (inEvent.error) { + console.log("error: " + inEvent.error.message); + } + }, + + getLocalFile: function() { + this.$.readFile.call({ path: this.preferences["filepath"] }); + }, + + loadDropbox: function(inSender, inResponse, inRequest) { + var file = new Object(); + file.content = inResponse; + this.parseFile(null, file); + this.dropboxRefresh = true; + this.saveFile(this.preferences["filepath"], this.todoList); + }, + + resetPreferences: function() { + this.preferences = new Object(); + this.preferences["storage"] = "file"; + this.preferences["offline"] = true; + this.preferences["filepath"] = "/media/internal/todo/todo.txt"; + this.preferences["dboxpath"] = "/todo"; + this.$.preferenceView.$.offline.setChecked(true); + this.$.preferenceView.$.dboxlogout.hide(); + this.$.preferenceView.$.dboxpathselect.hide(); + this.$.preferenceView.$.filepathselect.show(); + localStorage.setItem("TodoPreferences", JSON.stringify(this.preferences)); + }, + + handleConnectionChange: function(inSender, inResponse) { + var r = inResponse.isInternetConnectionAvailable; + + if (r) { + console.log("went online..."); + } else { + console.log("went offline..."); + if (this.preferences["offline"] == false) { + enyo.windows.addBannerMessage("offline mode", "{}"); + this.preferences["offline"] = true; + this.$.preferenceView.$.offline.setChecked(true); + } + } + }, + + fail: function(inSender, inResponse, inRequest) { + console.log("error"); + console.log(JSON.stringify(inResponse)); + enyo.windows.addBannerMessage(inResponse.error, "{}"); + }, + + enableDropbox: function() { + console.log("authentication successful, enabling dropbox"); + var token = this.$.dropbox.getToken(); + var secret = this.$.dropbox.getTokenSecret(); + this.preferences["dboxtoken"] = token; + this.preferences["dboxsecret"] = secret; + this.preferences["offline"] = false; + localStorage.setItem("TodoPreferences", JSON.stringify(this.preferences)); + this.$.preferenceView.$.dboxlogout.show(); + this.$.preferenceView.$.dboxpathselect.show(); + this.$.preferenceView.$.filepathselect.hide(); + this.dropboxRefresh = true; + this.refreshTodo(); + }, + + disableDropbox: function() { + this.$.dropbox.setToken(""); + this.$.dropbox.setTokenSecret(""); + this.$.dropbox.setAuthorized(false); + this.preferences["storage"] = "file"; + this.preferences["dboxtoken"] = ""; + this.preferences["dboxsecret"] = ""; + localStorage.setItem("TodoPreferences", JSON.stringify(this.preferences)); + } + +}); diff --git a/app/source/dropbox-auth.js.sample b/app/source/dropbox-auth.js.sample new file mode 100644 index 0000000..c0aed71 --- /dev/null +++ b/app/source/dropbox-auth.js.sample @@ -0,0 +1,9 @@ + +/* Dropbox will NOT work unless you replace the following two +* properties with the appropriate values for your registered +* application and rename the file to dropbox-auth.js or you +* will be able to package and run this correctly. +*/ + +var consumerKey = ""; +var consumerSecret = ""; diff --git a/app/source/oauth.js b/app/source/oauth.js new file mode 100644 index 0000000..295569a --- /dev/null +++ b/app/source/oauth.js @@ -0,0 +1,551 @@ +/* + * Copyright 2008 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Here's some JavaScript software for implementing OAuth. + + This isn't as useful as you might hope. OAuth is based around + allowing tools and websites to talk to each other. However, + JavaScript running in web browsers is hampered by security + restrictions that prevent code running on one website from + accessing data stored or served on another. + + Before you start hacking, make sure you understand the limitations + posed by cross-domain XMLHttpRequest. + + On the bright side, some platforms use JavaScript as their + language, but enable the programmer to access other web sites. + Examples include Google Gadgets, and Microsoft Vista Sidebar. + For those platforms, this library should come in handy. +*/ + +// The HMAC-SHA1 signature method calls b64_hmac_sha1, defined by +// http://pajhome.org.uk/crypt/md5/sha1.js + +/* An OAuth message is represented as an object like this: + {method: "GET", action: "http://server.com/path", parameters: ...} + + The parameters may be either a map {name: value, name2: value2} + or an Array of name-value pairs [[name, value], [name2, value2]]. + The latter representation is more powerful: it supports parameters + in a specific sequence, or several parameters with the same name; + for example [["a", 1], ["b", 2], ["a", 3]]. + + Parameter names and values are NOT percent-encoded in an object. + They must be encoded before transmission and decoded after reception. + For example, this message object: + {method: "GET", action: "http://server/path", parameters: {p: "x y"}} + ... can be transmitted as an HTTP request that begins: + GET /path?p=x%20y HTTP/1.0 + (This isn't a valid OAuth request, since it lacks a signature etc.) + Note that the object "x y" is transmitted as x%20y. To encode + parameters, you can call OAuth.addToURL, OAuth.formEncode or + OAuth.getAuthorization. + + This message object model harmonizes with the browser object model for + input elements of an form, whose value property isn't percent encoded. + The browser encodes each value before transmitting it. For example, + see consumer.setInputs in example/consumer.js. + */ + +/* This script needs to know what time it is. By default, it uses the local + clock (new Date), which is apt to be inaccurate in browsers. To do + better, you can load this script from a URL whose query string contains + an oauth_timestamp parameter, whose value is a current Unix timestamp. + For example, when generating the enclosing document using PHP: + +