From 132af874114a2e3df57a9c5a04c2356f3ef6b10d Mon Sep 17 00:00:00 2001 From: Giulio Cesare Solaroli Date: Fri, 2 Jan 2015 10:13:04 +0100 Subject: [PATCH] offline copy link and better feedback when saving Added offline copy link (still rough UI) and improved feedback when performing tasks that would eventually save data (long operation) --- .../PM/DataModel/EncryptedRemoteObject.js | 24 +++--- .../Clipperz/PM/DataModel/Record.Version.js | 77 +++++++----------- .../delta/js/Clipperz/PM/DataModel/Record.js | 81 +++++++++++-------- .../PM/DataModel/User.Header.RecordIndex.js | 2 +- .../delta/js/Clipperz/PM/DataModel/User.js | 23 +++--- .../Components/Panels/ExtraFeaturesPanel.js | 63 +++++++++------ .../Clipperz/PM/UI/Components/Selections.js | 2 +- .../delta/js/Clipperz/PM/UI/MainController.js | 53 +++++++++--- 8 files changed, 180 insertions(+), 145 deletions(-) diff --git a/frontend/delta/js/Clipperz/PM/DataModel/EncryptedRemoteObject.js b/frontend/delta/js/Clipperz/PM/DataModel/EncryptedRemoteObject.js index b76e4a6..8171121 100644 --- a/frontend/delta/js/Clipperz/PM/DataModel/EncryptedRemoteObject.js +++ b/frontend/delta/js/Clipperz/PM/DataModel/EncryptedRemoteObject.js @@ -22,12 +22,12 @@ refer to http://www.clipperz.com. */ "use strict"; +Clipperz.Base.module('Clipperz.PM.DataModel'); + try { if (typeof(Clipperz.KeyValueObjectStore) == 'undefined') { throw ""; }} catch (e) { throw "Clipperz.PM.DataModel.EncryptedRemoteObject depends on Clipperz.KeyValueObjectStore!"; } -Clipperz.Base.module('Clipperz.PM.DataModel'); - //if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; } //if (typeof(Clipperz.PM.DataModel) == 'undefined') { Clipperz.PM.DataModel = {}; } @@ -46,21 +46,19 @@ Clipperz.PM.DataModel.EncryptedRemoteObject = function(args) { this._retrieveRemoteDataFunction = args.retrieveRemoteDataFunction || null; this._remoteData = args.remoteData || null; -// this._remoteData = args.remoteData ? Clipperz.Base.deepClone(args.remoteData) : null; + if ((!this._isBrandNew) && ((this._retrieveRemoteDataFunction == null) && (this._remoteData == null))) { Clipperz.Base.exception.raise('MandatoryParameter'); } + this._encryptedDataKeypath = args.encryptedDataKeypath || 'data'; + this._encryptedVersionKeypath = args.encryptedVersionKeypath || 'version'; - this._encryptedDataKeypath = args.encryptedDataKeypath || 'data'; //Clipperz.Base.exception.raise('MandatoryParameter'); - this._encryptedVersionKeypath = args.encryptedVersionKeypath || 'version'; //Clipperz.Base.exception.raise('MandatoryParameter'); - - this._transientState = null; this._deferredLocks = {}; if (this._isBrandNew == true) { - this._objectDataStore = new Clipperz.KeyValueObjectStore(/*{'name':'EncryptedRemoteObject.objectDataStore [1]'}*/); + this._objectDataStore = new Clipperz.KeyValueObjectStore(); } else { this._objectDataStore = null; } @@ -111,7 +109,7 @@ Clipperz.PM.DataModel.EncryptedRemoteObject.prototype = MochiKit.Base.update(nul 'transientState': function () { if (this._transientState == null) { - this._transientState = new Clipperz.KeyValueObjectStore(/*{'name':'EncryptedRemoteObject.transientState [2]'}*/); + this._transientState = new Clipperz.KeyValueObjectStore(); } return this._transientState; @@ -166,6 +164,7 @@ Clipperz.PM.DataModel.EncryptedRemoteObject.prototype = MochiKit.Base.update(nul //------------------------------------------------------------------------- 'hasLoadedRemoteData': function () { +//console.log("EncryptedRemoteObject.hasLoadedRemoteData", this._remoteData); return (this._remoteData != null); }, @@ -237,7 +236,7 @@ Clipperz.PM.DataModel.EncryptedRemoteObject.prototype = MochiKit.Base.update(nul 'decryptedDataStore': function () { if (this._decryptedDataStore == null) { - this._decryptedDataStore = new Clipperz.KeyValueObjectStore(/*{'name':'EncryptedRemoteObject.decryptedDataStore [3]'}*/); + this._decryptedDataStore = new Clipperz.KeyValueObjectStore(); }; return this._decryptedDataStore; @@ -343,7 +342,7 @@ Clipperz.PM.DataModel.EncryptedRemoteObject.prototype = MochiKit.Base.update(nul if (this._objectDataStore == null) { //console.log("EncryptedRemoteObject._getObjectDataStore", this._reference); - this._objectDataStore = new Clipperz.KeyValueObjectStore(/*{'name':'EncryptedRemoteObject.objectDataStore [4]'}*/); + this._objectDataStore = new Clipperz.KeyValueObjectStore(); innerDeferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject._getObjectDataStore ", {trace:false}); innerDeferredResult.addMethod(this, 'getDecryptedData'); @@ -434,7 +433,6 @@ Clipperz.PM.DataModel.EncryptedRemoteObject.prototype = MochiKit.Base.update(nul 'commitTransientState': function () { var deferredResult; -// if (this.transientState().getValue('__prepareRemoteData') == true) { if (this.transientState().getValue('packedRemoteData') != null) { deferredResult = Clipperz.Async.callbacks("EncryptedRemoteObject.commitTransientState - prepareRemoteData", [ MochiKit.Base.bind(function (someData) { @@ -463,6 +461,7 @@ Clipperz.PM.DataModel.EncryptedRemoteObject.prototype = MochiKit.Base.update(nul //------------------------------------------------------------------------- 'revertChanges': function () { +//console.log("> EncryptedRemoveObject.revertChanges", this.toString(), this.hasInitiatedObjectDataStore()); if (this.hasInitiatedObjectDataStore()) { this._objectDataStore.removeAllData(); this._objectDataStore = null; @@ -523,7 +522,6 @@ Clipperz.PM.DataModel.EncryptedRemoteObject.prototype = MochiKit.Base.update(nul 'prepareRemoteDataWithKey': function (aKey) { return Clipperz.Async.callbacks("EncryptedRemoteObject.prepareRemoteDataWithKey", [ -// MochiKit.Base.method(this.transientState(), 'setValue', '__prepareRemoteData', true), MochiKit.Base.method(this, '_getObjectDataStore'), MochiKit.Base.methodcaller('values'), MochiKit.Base.method(this, 'packData'), diff --git a/frontend/delta/js/Clipperz/PM/DataModel/Record.Version.js b/frontend/delta/js/Clipperz/PM/DataModel/Record.Version.js index b7de8c8..e0a0f46 100644 --- a/frontend/delta/js/Clipperz/PM/DataModel/Record.Version.js +++ b/frontend/delta/js/Clipperz/PM/DataModel/Record.Version.js @@ -21,6 +21,9 @@ refer to http://www.clipperz.com. */ +"use strict"; + +Clipperz.Base.module('Clipperz.PM.DataModel'); try { if (typeof(Clipperz.PM.DataModel.Record) == 'undefined') { throw ""; }} catch (e) { throw "Clipperz.PM.DataModel.Record.Version depends on Clipperz.PM.DataModel.Record!"; } @@ -29,7 +32,7 @@ Clipperz.PM.DataModel.Record.Version = function(args) { Clipperz.PM.DataModel.Record.Version.superclass.constructor.apply(this, arguments); this._getVersionFunction = args.getVersion || Clipperz.Base.exception.raise('MandatoryParameter'); - this._fields = null; +// this._fields = null; return this; } @@ -43,9 +46,9 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record.Version, Clipperz.PM.DataModel //------------------------------------------------------------------------- - 'reference': function () { - return this._reference; - }, +// 'reference': function () { +// return this._reference; +// }, //------------------------------------------------------------------------- /* @@ -128,13 +131,13 @@ console.log("Record.Version.hasPendingChanges"); deferredResult.addCallback(MochiKit.Base.bind(function () { var innerDeferredResult; - if (this._fields == null) { +// if (this._fields == null) { innerDeferredResult = new Clipperz.Async.Deferred("Record.Version.fields ", {trace:false}); innerDeferredResult.addMethod(this, 'getValue', 'fields'); innerDeferredResult.addCallback(MochiKit.Base.bind(function (someObjectData) { var reference; - - this._fields = {}; + var result = {}; +// this._fields = {}; for (reference in someObjectData) { var recordVersionField; @@ -144,15 +147,17 @@ console.log("Record.Version.hasPendingChanges"); 'reference': reference }); - this._fields[reference] = recordVersionField; +// this._fields[reference] = recordVersionField; + result[reference] = recordVersionField; } - return this._fields; +// return this._fields; + return result; }, this)); innerDeferredResult.callback(); - } else { - innerDeferredResult = MochiKit.Async.succeed(this._fields); - } +// } else { +// innerDeferredResult = MochiKit.Async.succeed(this._fields); +// } return innerDeferredResult; }, this)); @@ -182,10 +187,9 @@ console.log("Record.Version.hasPendingChanges"); MochiKit.Base.methodcaller('values'), Clipperz.Base.serializeJSON, - MochiKit.Base.bind(function () { this._fields[newField.reference()] = newField; }, this), +// MochiKit.Base.bind(function () { this._fields[newField.reference()] = newField; }, this), MochiKit.Base.method(newField, 'setLabel', someParameters['label']), MochiKit.Base.method(newField, 'setValue', someParameters['value']), -// MochiKit.Base.method(newField, 'setIsHidden', someParameters['isHidden']), MochiKit.Base.method(newField, 'setIsHidden', someParameters['hidden']), MochiKit.Base.method(this, '_getObjectDataStore'), @@ -201,39 +205,12 @@ console.log("Record.Version.hasPendingChanges"); 'removeField': function (aField) { return Clipperz.Async.callbacks("Record.Version.removeField", [ MochiKit.Base.method(this, 'fields'), - MochiKit.Base.bind(function () { delete this._fields[aField.reference()]; }, this), +// MochiKit.Base.bind(function () { delete this._fields[aField.reference()]; }, this), MochiKit.Base.method(this, 'removeValue', 'fields' + '.' + aField.reference()) ], {trace:false}); }, //------------------------------------------------------------------------- -/* - 'sortFieldReference': function (someSortedFieldReferences) { - - - - }, -*/ - //========================================================================= -/* - 'directLogins': function () { - return MochiKit.Base.values(this._directLogins); - }, - - 'addDirectLogin': function (aDirectLogin) { - this._directLogins[aDirectLogin.reference()] = aDirectLogin; - }, -*/ - - //========================================================================= -/* - 'updateValues': function (anotherVersion) { - return Clipperz.Async.callbacks("Record.Version.updateValue", [ - MochiKit.Base.partial(MochiKit.Async.succeed, this) - ], {trace:false}); - }, -*/ - //========================================================================= 'setRemoteData': function (aValue) { this._remoteData = aValue; @@ -241,7 +218,7 @@ console.log("Record.Version.hasPendingChanges"); return aValue; }, - //========================================================================= + //------------------------------------------------------------------------- 'getVersionFunction': function () { return this._getVersionFunction; @@ -276,9 +253,10 @@ console.log("Record.Version.hasPendingChanges"); //========================================================================= 'revertChanges': function () { +//console.log("Record.Version.revertChanges", this.reference(), this.transientState()['originalReference']); this.setReference(this.transientState()['originalReference']); Clipperz.PM.DataModel.Record.Version.superclass.revertChanges.apply(this, arguments); - this._fields = null; +// this._fields = null; }, //------------------------------------------------------------------------- @@ -313,15 +291,15 @@ console.log("Record.Version.hasPendingChanges"); }, //========================================================================= - +/* 'deleteAllCleanTextData': function () { - this._fields = null; +// this._fields = null; return Clipperz.PM.DataModel.Record.Version.superclass.deleteAllCleanTextData.apply(this, arguments); }, 'hasAnyCleanTextData': function () { -// return Clipperz.PM.DataModel.Record.Version.superclass.hasAnyCleanTextData.apply(this, arguments); - + return Clipperz.PM.DataModel.Record.Version.superclass.hasAnyCleanTextData.apply(this, arguments); +/ * var deferredResult; deferredResult = new Clipperz.Async.Deferred("Record.Version.hasAnyCleanTextData", {trace:false}); @@ -335,8 +313,9 @@ console.log("Record.Version.hasPendingChanges"); deferredResult.callback(); return deferredResult; +* / }, - +*/ //========================================================================= __syntaxFix__: "syntax fix" }); diff --git a/frontend/delta/js/Clipperz/PM/DataModel/Record.js b/frontend/delta/js/Clipperz/PM/DataModel/Record.js index e86a480..a9081ff 100644 --- a/frontend/delta/js/Clipperz/PM/DataModel/Record.js +++ b/frontend/delta/js/Clipperz/PM/DataModel/Record.js @@ -77,9 +77,9 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt //------------------------------------------------------------------------- - 'reference': function () { - return this._reference; - }, +// 'reference': function () { +// return this._reference; +// }, //========================================================================= @@ -171,6 +171,10 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt return new RegExp('^\\s+|\\s+$', 'g'); }, +// 'tagCleanupRegExp': function () { +// return new RegExp('\\' + Clipperz.PM.DataModel.Record.tagSpace, 'g'); +// }, + //............................................................................ 'filterOutTags': function (aValue) { @@ -217,7 +221,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt match = tagRegEx.exec(aLabel); while (match != null) { result[match[1]] = true; - match = tagRegEx.exec(aLabel); + match = tagRegEx.exec(aLabel); } return result; @@ -232,10 +236,12 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt }, 'addTag': function (aNewTag) { +// var tag = aNewTag.replace(/\s/g, Clipperz.PM.DataModel.Record.tagSpace); +//console.log("TAG", aNewTag, tag); return Clipperz.Async.callbacks("Record.addTag", [ MochiKit.Base.method(this, 'fullLabel'), MochiKit.Base.method(this, 'extractTagsFromFullLabel'), - function (someTags) { someTags[aNewTag] = true; /* console.log("UPDATED TAGS", someTags); */ return someTags; }, + function (someTags) { someTags[aNewTag] = true; return someTags; }, MochiKit.Base.method(this, 'updateTags') ], {trace:false}); }, @@ -631,12 +637,18 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt var deferredResult; var transientStateKey; + if (typeof(aVersionReference) == 'undefined') { + console.log("ERROR; getVersionKey aVersionReference is undefined"); + } + transientStateKey = 'versionKeys' + '.' + aVersionReference; if (this.transientState().getValue(transientStateKey) != null) { deferredResult = MochiKit.Async.succeed(this.transientState().getValue(transientStateKey)); } else { deferredResult = Clipperz.Async.callbacks("Record.getVersionKey", [ +//MochiKit.Base.bind(function () {console.log("VERSION REFERENCE", aVersionReference, this.currentVersionReference()); }, this), MochiKit.Base.method(this, 'getVersions'), +//function (aValue) { console.log("VERSIONs", aValue); return aValue; }, MochiKit.Base.partial(MochiKit.Base.operator.eq, aVersionReference, this.currentVersionReference()), Clipperz.Async.deferredIf("getVersionKey for current version", [ MochiKit.Base.method(this, 'getCurrentRecordVersionKey'), @@ -758,7 +770,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt 'invokeCurrentRecordVersionMethod': function (aMethodName, someValues) { return Clipperz.Async.callbacks("Record.invokeCurrentRecordVersionMethod", [ MochiKit.Base.method(this, 'getCurrentRecordVersion'), - MochiKit.Base.methodcaller(aMethodName, someValues) + MochiKit.Base.methodcaller(aMethodName, someValues), ], {trace:false}); }, @@ -833,26 +845,18 @@ deferredResult.addCallback(function (aValue) { console.log("Record.hasPendingCha 'hasPendingChanges': function () { var deferredResult; -// var recordReference = this.reference(); - var self = this; + var recordReference = this.reference(); +// var self = this; deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.hasPendingChanges", {trace:false}); deferredResult.collectResults({ 'super': [ MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.hasPendingChanges, this), - -// MochiKit.Base.method(this, 'hasInitiatedObjectDataStore'), -// Clipperz.Async.deferredIf("Record.hasPendingChanges - hasInitiatedObjectDataStore", [ -// MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.hasPendingChanges, this), -// ], [ -// MochiKit.Base.partial(MochiKit.Async.succeed, false), -// ]), ], 'currentVersion': [ -// MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'hasPendingChanges') MochiKit.Base.method(this, 'hasInitiatedObjectDataStore'), Clipperz.Async.deferredIf("Record.hasPendingChanges - hasInitiatedObjectDataStore", [ - MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'hasPendingChanges') + MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'hasPendingChanges'), ], [ MochiKit.Base.partial(MochiKit.Async.succeed, false), ]), @@ -939,39 +943,47 @@ console.log("Record.hasPendingChanges RESULT", result); 'revertChanges': function () { var deferredResult; - var recordReference = this.reference(); +// var recordReference = this.reference(); if (this.isBrandNew() == false) { -/* +/* */ deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.DataModel.Record.revertChanges", {trace:false}); deferredResult.addMethod(this, 'hasPendingChanges'); -deferredResult.addCallback(function (aValue) { - if (recordReference == 'd620764a656bfd4e1d3758500d5db72e460a0cf729d56ed1a7755b5725c50045') { - console.log("Record.revertChanges - hasPendingChanges", aValue); - } +//deferredResult.addCallback(function (aValue) { +// if (recordReference == 'd620764a656bfd4e1d3758500d5db72e460a0cf729d56ed1a7755b5725c50045') { +// console.log("Record.revertChanges - hasPendingChanges", aValue); +// } // return aValue; - return true; -}); +// return true; +//}); deferredResult.addIf([ +//function (aValue) { console.log("Record.revertChanges - 1"); return aValue; }, MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'revertChanges'), +//function (aValue) { console.log("Record.revertChanges - 2"); return aValue; }, + MochiKit.Base.method(this, 'directLogins'), +//function (aValue) { console.log("Record.revertChanges - 3"); return aValue; }, MochiKit.Base.values, +//function (aValue) { console.log("Record.revertChanges - 4"); return aValue; }, MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('revertChanges')), +//function (aValue) { console.log("Record.revertChanges - 5"); return aValue; }, - MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.revertChanges, this) + MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.revertChanges, this), +//function (aValue) { console.log("Record.revertChanges - 6"); return aValue; }, ], [ MochiKit.Async.succeed ]); deferredResult.callback(); -*/ +/* * / deferredResult = Clipperz.Async.callbacks("Clipperz.PM.DataModel.Record.revertChanges", [ - MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'revertChanges'), MochiKit.Base.method(this, 'directLogins'), MochiKit.Base.values, MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('revertChanges')), - MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.revertChanges, this) + MochiKit.Base.method(this, 'invokeCurrentRecordVersionMethod', 'revertChanges'), + MochiKit.Base.bind(Clipperz.PM.DataModel.Record.superclass.revertChanges, this), ], {trace:false}); +/ * */ } else { // this.deleteAllCleanTextData(); deferredResult = MochiKit.Async.succeed(); @@ -1115,7 +1127,7 @@ deferredResult.addCallback(function (aValue) { }, //function (aValue) { console.log("Sorted Keys", aValue); return aValue; }, MochiKit.Base.partial(MochiKit.Base.map, function (aReference) { return currentFieldValues[aReference]; }), -function (aValue) { console.log("Sorted Field values", aValue); return aValue; }, +//function (aValue) { console.log("Sorted Field values", aValue); return aValue; }, MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.method(this, 'addField')), Clipperz.Async.collectAll, ], [ @@ -1147,7 +1159,7 @@ function (aValue) { console.log("Sorted Field values", aValue); return aValue; } Clipperz.Async.collectAll, MochiKit.Base.method(aRecord, 'directLogins'), MochiKit.Base.values, -function (aValue) { console.log("-> DirectLogin Values", aValue); return aValue; }, +//function (aValue) { console.log("-> DirectLogin Values", aValue); return aValue; }, MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.method(this, 'addDirectLogin')), //function (aValue) { console.log("-> DirectLogin Values", aValue); return aValue; }, // Clipperz.Async.collectAll, @@ -1173,10 +1185,11 @@ Clipperz.PM.DataModel.Record.defaultCardInfo = { }; Clipperz.PM.DataModel.Record.defaultSearchField = '_searchableContent'; -Clipperz.PM.DataModel.Record.tagChar = '\uE009'; -Clipperz.PM.DataModel.Record.specialTagChar = '\uE010'; +Clipperz.PM.DataModel.Record.tagChar = '\uE009'; +Clipperz.PM.DataModel.Record.specialTagChar = '\uE010'; +//Clipperz.PM.DataModel.Record.tagSpace = '\uE011'; Clipperz.PM.DataModel.Record.specialTagsConstructor = function (aTag) { - return Clipperz.PM.DataModel.Record.specialTagChar + aTag; + return Clipperz.PM.DataModel.Record.specialTagChar + aTag; //.replace(/\s/g, Clipperz.PM.DataModel.Record.tagSpace); } Clipperz.PM.DataModel.Record.archivedTag = Clipperz.PM.DataModel.Record.specialTagsConstructor('ARCH'); Clipperz.PM.DataModel.Record.regExpForTag = function (aTag) { diff --git a/frontend/delta/js/Clipperz/PM/DataModel/User.Header.RecordIndex.js b/frontend/delta/js/Clipperz/PM/DataModel/User.Header.RecordIndex.js index 43d95af..68e7de3 100644 --- a/frontend/delta/js/Clipperz/PM/DataModel/User.Header.RecordIndex.js +++ b/frontend/delta/js/Clipperz/PM/DataModel/User.Header.RecordIndex.js @@ -227,7 +227,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.RecordIndex, Object, { this._records[reference] = record; } else { -Clipperz.log("SKIPPING record " + reference + " as there are no stas associated - " + Clipperz.Base.serializeJSON(someData['records'][reference])); +Clipperz.log("SKIPPING record " + reference + " as there are no stats associated - " + Clipperz.Base.serializeJSON(someData['records'][reference])); } } diff --git a/frontend/delta/js/Clipperz/PM/DataModel/User.js b/frontend/delta/js/Clipperz/PM/DataModel/User.js index 11f9674..8d8b0ef 100644 --- a/frontend/delta/js/Clipperz/PM/DataModel/User.js +++ b/frontend/delta/js/Clipperz/PM/DataModel/User.js @@ -547,11 +547,12 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, { ], {trace:false}); }, - 'getRecordsInfo': function (someInfo, shouldIncludeArchivedCards) { + 'getRecordsInfo': function (someInfo /*, shouldIncludeArchivedCards */) { return Clipperz.Async.callbacks("User.getRecordsInfo", [ MochiKit.Base.method(this, 'getRecords'), MochiKit.Base.partial(MochiKit.Base.map, Clipperz.Async.collectResults("collectResults", someInfo, {trace:false})), Clipperz.Async.collectAll, +/* function (aResult) { var result; @@ -563,7 +564,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, { return result; } - +*/ ], {trace:false}); }, @@ -665,21 +666,15 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, { var user = this; return Clipperz.Async.callbacks("User.cloneRecord", [ -// MochiKit.Base.method(this, 'createNewRecord'), -// MochiKit.Base.methodcaller('setUpWithRecord', aRecord), -// function (aValue) { result = aValue; return aValue; }, -// MochiKit.Base.method(this, 'saveChanges'), -// function () { return result; } - MochiKit.Base.method(this, 'hasPendingChanges'), Clipperz.Async.deferredIf("User has pending changes", [ MochiKit.Async.fail ], [ MochiKit.Base.method(user, 'createNewRecord'), MochiKit.Base.methodcaller('setUpWithRecord', aRecord), - function (aValue) { result = aValue; return aValue; }, - MochiKit.Base.method(user, 'saveChanges'), - function () { return result; } +// function (aValue) { result = aValue; return aValue; }, +// MochiKit.Base.method(user, 'saveChanges'), +// function () { return result; } ]) ], {trace:false}); }, @@ -781,9 +776,13 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, { 'revertChanges': function () { return Clipperz.Async.callbacks("User.revertChanges", [ +//function (aValue) { console.log("User.revertChanges - 1"); return aValue; }, MochiKit.Base.method(this, 'invokeMethodNamedOnHeader', 'revertChanges'), +//function (aValue) { console.log("User.revertChanges - 2"); return aValue; }, MochiKit.Base.method(this, 'invokeMethodNamedOnRecords', 'revertChanges'), - MochiKit.Base.method(this, 'resetTransientState', false) +//function (aValue) { console.log("User.revertChanges - 3"); return aValue; }, + MochiKit.Base.method(this, 'resetTransientState', false), +//function (aValue) { console.log("User.revertChanges - 4"); return aValue; }, ], {trace:false}); }, diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Panels/ExtraFeaturesPanel.js b/frontend/delta/js/Clipperz/PM/UI/Components/Panels/ExtraFeaturesPanel.js index 18baf4a..f8bcd4d 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/Panels/ExtraFeaturesPanel.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Panels/ExtraFeaturesPanel.js @@ -21,6 +21,7 @@ refer to http://www.clipperz.com. */ +"use strict"; Clipperz.Base.module('Clipperz.PM.UI.Components.Panels'); Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanel = React.createClass({ @@ -30,6 +31,10 @@ Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanel = React.createClass({ MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'toggleSettingsPanel'); }, + handleDownloadOfflineCopyLink: function (anEvent) { + MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'downloadOfflineCopy'); + }, + //========================================================================= render: function () { @@ -45,33 +50,39 @@ Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanel = React.createClass({ Clipperz.PM.UI.Components.Button({eventName:'settingsToggleButton', label:"menu", handler:this.settingsToggleHandler}) ]) ]), - React.DOM.h2({}, "Extra features") + + React.DOM.div({}, [ + React.DOM.ul({}, [ + React.DOM.li({}, [ + React.DOM.h1({}, "Account"), + ]), + React.DOM.li({}, [ + React.DOM.h1({}, "Data"), + React.DOM.ul({}, [ + React.DOM.li({}, [ + React.DOM.h2({}, "Offline copy"), + React.DOM.div({}, [ + React.DOM.p({}, "With just one click you can dump all your encrypted data from Clipperz servers to your hard disk and create a read-only offline version of Clipperz to be used when you are not connected to the Internet."), + React.DOM.a({'onClick':this.handleDownloadOfflineCopyLink}, "Download") + ]) + ]), + React.DOM.li({}, [ + React.DOM.h2({}, "Sharing"), + ]), + React.DOM.li({}, [ + React.DOM.h2({}, "Import"), + ]), + React.DOM.li({}, [ + React.DOM.h2({}, "Export"), + ]) + ]) + ]), + React.DOM.li({}, [ + React.DOM.h1({}, "Tools"), + ]) + ]) + ]) ]); -/* -
- -
-
    -
  • Synchronize local data
  • -
-
- -
    -
  • Account
  • -
  • Subscription
  • -
- -
    -
  • Local Data
  • -
  • OTP
  • -
- - -
-*/ - } //========================================================================= diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Selections.js b/frontend/delta/js/Clipperz/PM/UI/Components/Selections.js index 21c5511..d396e11 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/Selections.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Selections.js @@ -60,7 +60,7 @@ Clipperz.PM.UI.Components.Selections = React.createClass({ var filterType; var filterValue; -console.log("SELECTIONS PROPS", this.props); +//console.log("SELECTIONS PROPS", this.props); tagInfo = this.props['tags'] ? this.props['tags'] : {}; tags = MochiKit.Base.filter(Clipperz.PM.DataModel.Record.isRegularTag, MochiKit.Base.keys(tagInfo)).sort(Clipperz.Base.caseInsensitiveCompare); archivedCardsCount = this.props['archivedCardsCount']; diff --git a/frontend/delta/js/Clipperz/PM/UI/MainController.js b/frontend/delta/js/Clipperz/PM/UI/MainController.js index 19ee432..714f35b 100644 --- a/frontend/delta/js/Clipperz/PM/UI/MainController.js +++ b/frontend/delta/js/Clipperz/PM/UI/MainController.js @@ -73,6 +73,7 @@ Clipperz.PM.UI.MainController = function() { 'showArchivedCards', 'hideArchivedCards', 'goBackToMainPage', 'maskClick', + 'downloadOfflineCopy', ]); // MochiKit.Signal.connect(MochiKit.DOM.currentDocument(), 'onselectionchange', this, 'selectionChange_handler'); @@ -636,6 +637,7 @@ console.log("SET USER", aUser); var deferredResult; deferredResult = new Clipperz.Async.Deferred('MainController.refreshUI', {trace:false}); + deferredResult.addMethod(this, 'resetRecordsInfo'), deferredResult.addMethod(this, 'refreshSelectedCards'); deferredResult.addMethod(this, 'renderTags'); @@ -1034,9 +1036,12 @@ console.log("SET USER", aUser); // }, saveChanges: function () { + // TODO: handle errors while savings return Clipperz.Async.callbacks("MainController.saveChanges", [ + MochiKit.Base.method(this.overlay(), 'show', "saving …", true), MochiKit.Base.method(this.user(), 'saveChanges'), - MochiKit.Base.method(this, 'resetRecordsInfo'), +// MochiKit.Base.method(this, 'resetRecordsInfo'), + MochiKit.Base.method(this.overlay(), 'done', "saved", 1), ], {trace:false}); }, @@ -1046,11 +1051,11 @@ console.log("SET USER", aUser); return Clipperz.Async.callbacks("MainController.saveCardEdits_handler", [ MochiKit.Base.method(currentPage, 'setProps', {'showGlobalMask':true}), - MochiKit.Base.method(this.overlay(), 'show', "saving …", true), +// MochiKit.Base.method(this.overlay(), 'show', "saving …", true), MochiKit.Base.method(this, 'saveChanges'), MochiKit.Base.method(currentPage, 'setProps', {'mode':'view', 'showGlobalMask':false}), MochiKit.Base.method(this, 'refreshUI', aRecordReference), - MochiKit.Base.method(this.overlay(), 'done', "saved", 1), +// MochiKit.Base.method(this.overlay(), 'done', "saved", 1), ], {trace:false}); }, @@ -1160,16 +1165,26 @@ console.log("SET USER", aUser); }, cloneCard_handler: function (anEvent) { + var cardInfo; + //console.log("CLONE CARD", anEvent['reference']); return Clipperz.Async.callbacks("MainController.cloneCard_handler", [ MochiKit.Base.method(this.user(), 'getRecord', anEvent['reference']), MochiKit.Base.method(this.user(), 'cloneRecord'), - MochiKit.Base.methodcaller('reference'), + Clipperz.Async.collectResults("MainController.cloneCard_handler ", { + 'label': MochiKit.Base.methodcaller('label'), + 'reference': MochiKit.Base.methodcaller('reference') + }, {trace:false}), + function (aValue) { cardInfo = aValue; return aValue; }, + MochiKit.Base.method(this, 'saveChanges'), + + function (aValue) { + MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'cardSelected', cardInfo); + }, + + function (aValue) { return cardInfo['reference']; }, MochiKit.Base.method(this, 'refreshUI'), -// MochiKit.Base.bind(function () { -// this.pages()[this.currentPage()].setProps({'mode': 'edit'}); -// }, this), - ], {trace:false}); + ], {trace:true}); }, enterEditMode: function () { @@ -1322,7 +1337,27 @@ console.log("SET USER", aUser); hasKeyboard: function () { return this._hasKeyboard; }, - + + //============================================================================ + + 'downloadOfflineCopy_handler': function (anEvent) { + var downloadHref; + var deferredResult; + var newWindow; + + downloadHref = window.location.href.replace(/\/[^\/]*$/,'') + Clipperz_dumpUrl; + newWindow = window.open("", ""); + + deferredResult = new Clipperz.Async.Deferred("AppController.handleDownloadOfflineCopy", {trace:false}); + deferredResult.addCallback(MochiKit.Base.method(this.user().connection(), 'message'), 'echo', {'echo':"echo"}); + deferredResult.addCallback(function(aWindow) { + aWindow.location.href = downloadHref; + }, newWindow); + deferredResult.callback(); + + return deferredResult; + }, + //============================================================================ /* wrongAppVersion: function (anError) {