mirror of
http://git.whoc.org.uk/git/password-manager.git
synced 2025-10-28 18:07:35 +01:00
Interim synchronization with internal repository
This is an intermir commit to share what is going on with the development of the new /delta version.
This commit is contained in:
@@ -21,11 +21,8 @@ refer to http://www.clipperz.com.
|
||||
|
||||
*/
|
||||
|
||||
//Clipperz.Async = MochiKit.Async;
|
||||
|
||||
|
||||
if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
|
||||
if (typeof(Clipperz.Async) == 'undefined') { Clipperz.Async = {}; }
|
||||
"use strict";
|
||||
Clipperz.Base.module('Clipperz.Async');
|
||||
|
||||
Clipperz.Async.VERSION = "0.1";
|
||||
Clipperz.Async.NAME = "Clipperz.Async";
|
||||
@@ -276,6 +273,12 @@ Clipperz.Base.extend(Clipperz.Async.Deferred, MochiKit.Async.Deferred, {
|
||||
}, this));
|
||||
},
|
||||
|
||||
'values': function () {
|
||||
this.addCallback(MochiKit.Base.bind(function () {
|
||||
return this.vars();
|
||||
}, this));
|
||||
},
|
||||
|
||||
//=============================================================================
|
||||
|
||||
'wait': function (someSeconds) {
|
||||
@@ -702,6 +705,6 @@ MochiKit.Base.update(Clipperz.Async, {
|
||||
|
||||
//#############################################################################
|
||||
|
||||
CLIPPERZ_DEFERRED_LOGGING_ENABLED = true;
|
||||
CLIPPERZ_DEFERRED_TRACING_ENABLED = false;
|
||||
CLIPPERZ_DEFERRED_CALL_LOGGING_ENABLED = false;
|
||||
var CLIPPERZ_DEFERRED_LOGGING_ENABLED = true;
|
||||
var CLIPPERZ_DEFERRED_TRACING_ENABLED = false;
|
||||
var CLIPPERZ_DEFERRED_CALL_LOGGING_ENABLED = false;
|
||||
|
||||
@@ -21,6 +21,8 @@ refer to http://www.clipperz.com.
|
||||
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
|
||||
if (typeof(Clipperz.Base) == 'undefined') { Clipperz.Base = {}; }
|
||||
|
||||
@@ -189,6 +191,10 @@ MochiKit.Base.update(Clipperz.Base, {
|
||||
return Clipperz.Base.removeObjectFromArray(anObject, anArray);
|
||||
},
|
||||
|
||||
'arrayWithUniqueValues': function (anArray) {
|
||||
return anArray.filter(function (value, index, self) { return self.indexOf(value) === index; });
|
||||
},
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
'splitStringAtFixedTokenSize': function(aString, aTokenSize) {
|
||||
|
||||
@@ -21,6 +21,7 @@ refer to http://www.clipperz.com.
|
||||
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
|
||||
|
||||
//=============================================================================
|
||||
|
||||
@@ -21,7 +21,8 @@ refer to http://www.clipperz.com.
|
||||
|
||||
*/
|
||||
|
||||
if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
|
||||
"use strict";
|
||||
Clipperz.Base.module('Clipperz');
|
||||
|
||||
|
||||
Clipperz.CSVProcessor = function(args) {
|
||||
@@ -32,9 +33,9 @@ Clipperz.CSVProcessor = function(args) {
|
||||
// this._string = undefined;
|
||||
// this._fields = undefined;
|
||||
|
||||
this._quoteChar = args['quoteChar'] || "\042";
|
||||
this._quoteChar = args['quoteChar'] || "\0x42";
|
||||
this._eol = args['eol'] || "";
|
||||
this._escapeChar = args['escapeChar'] || "\042";
|
||||
this._escapeChar = args['escapeChar'] || "\0x42";
|
||||
this._separatorChar = args['separatorChar'] || ",";
|
||||
this._binary = args['binary'] || false;
|
||||
this._alwaysQuote = args['alwaysQuote'] || false;
|
||||
|
||||
@@ -293,7 +293,7 @@ Clipperz.Crypto.PRNG.MouseRandomnessSource.prototype = MochiKit.Base.update(new
|
||||
Clipperz.Crypto.PRNG.CryptoRandomRandomnessSource = function(args) {
|
||||
args = args || {};
|
||||
|
||||
this._intervalTime = args.intervalTime || 1000;
|
||||
this._intervalTime = args.intervalTime || 500;
|
||||
this._browserCrypto = args.browserCrypto;
|
||||
|
||||
Clipperz.Crypto.PRNG.RandomnessSource.call(this, args);
|
||||
@@ -318,7 +318,7 @@ Clipperz.Crypto.PRNG.CryptoRandomRandomnessSource.prototype = MochiKit.Base.upda
|
||||
var bytesToCollect;
|
||||
|
||||
if (this.boostMode() == true) {
|
||||
bytesToCollect = 64;
|
||||
bytesToCollect = 256;
|
||||
} else {
|
||||
bytesToCollect = 8;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ MochiKit.Base.update(Clipperz.Crypto.SRP, {
|
||||
return Clipperz.Crypto.SRP._n;
|
||||
},
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//.........................................................................
|
||||
|
||||
'g': function() {
|
||||
if (Clipperz.Crypto.SRP._g == null) {
|
||||
@@ -66,6 +66,8 @@ MochiKit.Base.update(Clipperz.Crypto.SRP, {
|
||||
return Clipperz.Crypto.SRP._g;
|
||||
},
|
||||
|
||||
//.........................................................................
|
||||
|
||||
'k': function() {
|
||||
if (Clipperz.Crypto.SRP._k == null) {
|
||||
// Clipperz.Crypto.SRP._k = new Clipperz.Crypto.BigInt(this.stringHash(this.n().asString() + this.g().asString()), 16);
|
||||
|
||||
@@ -21,8 +21,8 @@ refer to http://www.clipperz.com.
|
||||
|
||||
*/
|
||||
|
||||
if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
|
||||
if (typeof(Clipperz.DOM) == 'undefined') { Clipperz.DOM = {}; }
|
||||
"use strict";
|
||||
Clipperz.Base.module('Clipperz.DOM');
|
||||
|
||||
Clipperz.DOM.VERSION = "0.1";
|
||||
Clipperz.DOM.NAME = "Clipperz.DOM";
|
||||
|
||||
@@ -21,8 +21,8 @@ refer to http://www.clipperz.com.
|
||||
|
||||
*/
|
||||
|
||||
if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
|
||||
if (typeof(Clipperz.Date) == 'undefined') { Clipperz.Date = {}; }
|
||||
"use strict";
|
||||
Clipperz.Base.module('Clipperz.Date');
|
||||
|
||||
Clipperz.Date.VERSION = "0.1";
|
||||
Clipperz.Date.NAME = "Clipperz.Date";
|
||||
|
||||
@@ -30,6 +30,7 @@ Clipperz.PM.DataModel.Record = function(args) {
|
||||
Clipperz.PM.DataModel.Record.superclass.constructor.apply(this, arguments);
|
||||
|
||||
this._updateDate = (args.updateDate ? Clipperz.PM.Date.parse(args.updateDate) : Clipperz.Base.exception.raise('MandatoryParameter'));
|
||||
this._accessDate = (args.accessDate ? Clipperz.PM.Date.parse(args.accessDate) : Clipperz.Base.exception.raise('MandatoryParameter'));
|
||||
|
||||
this._retrieveIndexDataFunction = args.retrieveIndexDataFunction || Clipperz.Base.exception.raise('MandatoryParameter');
|
||||
this._updateIndexDataFunction = args.updateIndexDataFunction || Clipperz.Base.exception.raise('MandatoryParameter');
|
||||
@@ -40,6 +41,8 @@ Clipperz.PM.DataModel.Record = function(args) {
|
||||
|
||||
this._createNewDirectLoginFunction = args.createNewDirectLoginFunction || null;
|
||||
|
||||
this._tags = [];
|
||||
|
||||
this._directLogins = {};
|
||||
|
||||
this._versions = {};
|
||||
@@ -128,22 +131,109 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
|
||||
return deferredResult;
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
//============================================================================
|
||||
/*
|
||||
'key': function () {
|
||||
return this.getIndexDataForKey('key');
|
||||
},
|
||||
*/
|
||||
//=========================================================================
|
||||
//============================================================================
|
||||
|
||||
'fullLabel': function () {
|
||||
return this.getIndexDataForKey('label');
|
||||
},
|
||||
|
||||
'updateFullLabelWithTags': function (someTags) {
|
||||
return Clipperz.Async.callbacks("Record.updateFullLabelWithTags", [
|
||||
MochiKit.Base.method(this, 'label'),
|
||||
function (aLabel) {
|
||||
return aLabel + ' ' + MochiKit.Base.map(function (aTag) { return Clipperz.PM.DataModel.Record.tagChar + aTag; }, MochiKit.Base.keys(someTags)).join(' ');
|
||||
},
|
||||
MochiKit.Base.method(this, 'setIndexDataForKey', 'label')
|
||||
], {trace:false});
|
||||
},
|
||||
|
||||
//............................................................................
|
||||
|
||||
'tagChar': function () {
|
||||
return Clipperz.PM.DataModel.Record.tagChar;
|
||||
},
|
||||
|
||||
'tagRegExp': function () {
|
||||
return new RegExp('\\' + this.tagChar() + '(\\w+)', 'g');
|
||||
},
|
||||
|
||||
'trimSpacesRegExp': function () {
|
||||
return new RegExp('^\\s+|\\s+$', 'g');
|
||||
},
|
||||
|
||||
//............................................................................
|
||||
|
||||
'filterOutTags': function (aValue) {
|
||||
var value;
|
||||
|
||||
value = aValue;
|
||||
value = value.replace(this.tagRegExp(), '');
|
||||
value = value.replace(this.trimSpacesRegExp(), '');
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
'label': function () {
|
||||
return this.getIndexDataForKey('label');
|
||||
return Clipperz.Async.callbacks("Record.label", [
|
||||
MochiKit.Base.method(this, 'fullLabel'),
|
||||
MochiKit.Base.method(this, 'filterOutTags')
|
||||
], {trace:false});
|
||||
},
|
||||
|
||||
'setLabel': function (aValue) {
|
||||
return this.setIndexDataForKey('label', aValue); // [???]
|
||||
},
|
||||
|
||||
//.........................................................................
|
||||
|
||||
'setLabel': function (aValue) {
|
||||
return this.setIndexDataForKey('label', aValue);
|
||||
'extractTags': function (aLabel) {
|
||||
var tagRegEx;
|
||||
var result;
|
||||
var match;
|
||||
|
||||
result = {};
|
||||
tagRegEx = this.tagRegExp();
|
||||
match = tagRegEx.exec(aLabel);
|
||||
while (match != null) {
|
||||
result[match[1]] = true;
|
||||
match = tagRegEx.exec(aLabel);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
'tags': function () {
|
||||
return Clipperz.Async.callbacks("Record.label", [
|
||||
MochiKit.Base.method(this, 'fullLabel'),
|
||||
MochiKit.Base.method(this, 'extractTags'),
|
||||
MochiKit.Base.keys
|
||||
], {trace:false});
|
||||
},
|
||||
|
||||
'addTag': function (aNewTag) {
|
||||
//console.log("ADD TAG", aNewTag);
|
||||
return Clipperz.Async.callbacks("Record.addTag", [
|
||||
MochiKit.Base.method(this, 'fullLabel'),
|
||||
MochiKit.Base.method(this, 'extractTags'),
|
||||
function (someTags) { someTags[aNewTag] = true; console.log("UPDATED TAGS", someTags); return someTags; },
|
||||
MochiKit.Base.method(this, 'updateFullLabelWithTags')
|
||||
], {trace:false});
|
||||
},
|
||||
|
||||
'removeTag': function (aTag) {
|
||||
//console.log("ADD TAG", aNewTag);
|
||||
return Clipperz.Async.callbacks("Record.removeTag", [
|
||||
MochiKit.Base.method(this, 'fullLabel'),
|
||||
MochiKit.Base.method(this, 'extractTags'),
|
||||
function (someTags) { delete someTags[aTag]; return someTags; },
|
||||
MochiKit.Base.method(this, 'updateFullLabelWithTags')
|
||||
], {trace:false});
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
@@ -183,6 +273,10 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
|
||||
return MochiKit.Async.succeed(this._updateDate);
|
||||
},
|
||||
|
||||
'accessDate': function () {
|
||||
return MochiKit.Async.succeed(this._accessDate);
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
'favicon': function () {
|
||||
@@ -208,7 +302,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
|
||||
deferredResult = new Clipperz.Async.Deferred("Record.searchableContent", {trace:false});
|
||||
|
||||
deferredResult.collectResults({
|
||||
'recordLabel': MochiKit.Base.method(this, 'label'),
|
||||
'recordLabel': MochiKit.Base.method(this, 'fullLabel'),
|
||||
'directLoginLabels': [
|
||||
MochiKit.Base.method(this, 'directLoginReferences'),
|
||||
MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.itemgetter('label'))
|
||||
@@ -889,3 +983,20 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
|
||||
});
|
||||
|
||||
|
||||
Clipperz.PM.DataModel.Record.defaultCardInfo = {
|
||||
'_rowObject': MochiKit.Async.succeed,
|
||||
'_reference': MochiKit.Base.methodcaller('reference'),
|
||||
'_searchableContent': MochiKit.Base.methodcaller('searchableContent'),
|
||||
'_accessDate': MochiKit.Base.methodcaller('accessDate'),
|
||||
'label': MochiKit.Base.methodcaller('label'),
|
||||
'favicon': MochiKit.Base.methodcaller('favicon')
|
||||
};
|
||||
Clipperz.PM.DataModel.Record.defaultSearchField = '_searchableContent';
|
||||
|
||||
Clipperz.PM.DataModel.Record.tagChar = '#';
|
||||
Clipperz.PM.DataModel.Record.regExpForTag = function (aTag) {
|
||||
return new RegExp('\\' + Clipperz.PM.DataModel.Record.tagChar + aTag, 'g');
|
||||
};
|
||||
Clipperz.PM.DataModel.Record.regExpForSearch = function (aSearch) {
|
||||
return new RegExp(aSearch.replace(/[^A-Za-z0-9]/g, '\\$&'), 'i');
|
||||
};
|
||||
|
||||
@@ -25,26 +25,26 @@ try { if (typeof(Clipperz.PM.DataModel.User) == 'undefined') { throw ""; }} catc
|
||||
throw "Clipperz.PM.DataModel.User.Subscription depends on Clipperz.PM.DataModel.User!";
|
||||
}
|
||||
|
||||
Clipperz.PM.DataModel.User.Subscription = function(args) {
|
||||
Clipperz.PM.DataModel.User.AccountInfo = function(args) {
|
||||
this._attributes = args;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
Clipperz.Base.extend(Clipperz.PM.DataModel.User.Subscription, Object, {
|
||||
Clipperz.Base.extend(Clipperz.PM.DataModel.User.AccountInfo, Object, {
|
||||
|
||||
'features': function () {
|
||||
return this._attributes['features'];
|
||||
},
|
||||
|
||||
'type': function () {
|
||||
return this._attributes['type'];
|
||||
'featureSet': function () {
|
||||
return this._attributes['featureSet'];
|
||||
},
|
||||
|
||||
'validity': function () {
|
||||
return {
|
||||
'from': this._attributes['fromDate'],
|
||||
'to': this._attributes['toDate']
|
||||
// 'from': this._attributes['fromDate'],
|
||||
'to': this._attributes['expirationDate']
|
||||
};
|
||||
},
|
||||
|
||||
@@ -133,6 +133,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.Legacy, Clipperz.PM.DataM
|
||||
'retrieveIndexDataFunction': MochiKit.Base.method(this, 'getRecordIndexData'),
|
||||
'updateIndexDataFunction': MochiKit.Base.method(this, 'updateRecordIndexData'),
|
||||
'updateDate': someObjectData['recordsStats'][reference]['updateDate'],
|
||||
'accessDate': someObjectData['recordsStats'][reference]['accessDate'],
|
||||
|
||||
'retrieveDirectLoginIndexDataFunction': MochiKit.Base.method(this, 'getDirectLoginIndexData'),
|
||||
'setDirectLoginIndexDataFunction': MochiKit.Base.method(this, 'setDirectLoginIndexData'),
|
||||
|
||||
@@ -29,7 +29,7 @@ if (typeof(Clipperz.PM.DataModel.User.Header) == 'undefined') { Clipperz.PM.Data
|
||||
|
||||
Clipperz.PM.DataModel.User.Header.RecordIndex = function(args) {
|
||||
Clipperz.PM.DataModel.User.Header.RecordIndex.superclass.constructor.apply(this, arguments);
|
||||
|
||||
//console.log("RECORD INDEX ARGS", args);
|
||||
this._recordsData = new Clipperz.PM.DataModel.EncryptedRemoteObject({
|
||||
'name': 'recordsData',
|
||||
'retrieveKeyFunction': args.retrieveKeyFunction,
|
||||
@@ -37,9 +37,7 @@ Clipperz.PM.DataModel.User.Header.RecordIndex = function(args) {
|
||||
'data': args.recordsData['data'],
|
||||
'version': args.encryptedDataVersion,
|
||||
'recordsStats': args.recordsStats
|
||||
}//,
|
||||
// 'encryptedDataKeypath': 'data',
|
||||
// 'encryptedVersionKeypath': 'version'
|
||||
}
|
||||
});
|
||||
|
||||
this._directLoginsData = new Clipperz.PM.DataModel.EncryptedRemoteObject({
|
||||
@@ -48,11 +46,10 @@ Clipperz.PM.DataModel.User.Header.RecordIndex = function(args) {
|
||||
'remoteData': {
|
||||
'data': args.directLoginsData['data'],
|
||||
'version': args.encryptedDataVersion
|
||||
}//,
|
||||
// 'encryptedDataKeypath': 'data',
|
||||
// 'encryptedVersionKeypath': 'version'
|
||||
}
|
||||
});
|
||||
|
||||
this._tagsData =
|
||||
this._lock = new MochiKit.Async.DeferredLock();
|
||||
this._transientState = null;
|
||||
|
||||
@@ -154,9 +151,6 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.RecordIndex, Object, {
|
||||
},
|
||||
|
||||
'setDirectLoginIndexData': function (aDirectLoginReference, aKey, aValue) {
|
||||
//if (MochiKit.Base.isUndefinedOrNull(this.directLoginsIndex()[aDirectLoginReference])) {
|
||||
// throw "PIPPO";
|
||||
//}
|
||||
return this.directLoginsData().setValue(this.directLoginsIndex()[aDirectLoginReference] + '.' + aKey, aValue);
|
||||
},
|
||||
|
||||
@@ -182,8 +176,6 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.RecordIndex, Object, {
|
||||
innerDeferredResult = new Clipperz.Async.Deferred("User.Header.RecordIndex.records <inner deferred>", {trace:false});
|
||||
innerDeferredResult.collectResults({
|
||||
'records': [
|
||||
// MochiKit.Base.method(this.recordsData(), 'getObjectDataStore'),
|
||||
// MochiKit.Base.methodcaller('values')
|
||||
MochiKit.Base.method(this.recordsData(), 'values')
|
||||
],
|
||||
'recordsStats': [
|
||||
@@ -191,8 +183,6 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.RecordIndex, Object, {
|
||||
MochiKit.Base.itemgetter('recordsStats')
|
||||
],
|
||||
'directLogins': [
|
||||
// MochiKit.Base.method(this.directLoginsData(), 'getObjectDataStore'),
|
||||
// MochiKit.Base.methodcaller('values')
|
||||
MochiKit.Base.method(this.directLoginsData(), 'values')
|
||||
]
|
||||
})
|
||||
@@ -210,11 +200,13 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.RecordIndex, Object, {
|
||||
var record;
|
||||
var reference;
|
||||
var updateDate;
|
||||
var accessDate;
|
||||
|
||||
reference = recordsInvertedIndex[indexReference];
|
||||
|
||||
if (typeof(someData['recordsStats'][reference]) != 'undefined') {
|
||||
updateDate = someData['recordsStats'][reference]['updateDate'];
|
||||
accessDate = someData['recordsStats'][reference]['accessDate'];
|
||||
|
||||
record = new Clipperz.PM.DataModel.Record({
|
||||
'reference': reference,
|
||||
@@ -224,6 +216,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.RecordIndex, Object, {
|
||||
'retrieveIndexDataFunction': MochiKit.Base.method(this, 'getRecordIndexData'),
|
||||
'updateIndexDataFunction': MochiKit.Base.method(this, 'updateRecordIndexData'),
|
||||
'updateDate': updateDate,
|
||||
'accessDate': accessDate,
|
||||
|
||||
'retrieveDirectLoginIndexDataFunction': MochiKit.Base.method(this, 'getDirectLoginIndexData'),
|
||||
'setDirectLoginIndexDataFunction': MochiKit.Base.method(this, 'setDirectLoginIndexData'),
|
||||
@@ -235,13 +228,10 @@ 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]));
|
||||
// # skip the record, as it seems it is not present in the DB
|
||||
// updateDate = Clipperz.PM.Date.formatDateWithUTCFormat(new Date());
|
||||
}
|
||||
}
|
||||
|
||||
for (indexReference in someData['directLogins']) {
|
||||
// var directLogin;
|
||||
var reference;
|
||||
var record;
|
||||
|
||||
@@ -249,7 +239,6 @@ Clipperz.log("SKIPPING record " + reference + " as there are no stas associated
|
||||
record = this._records[recordsInvertedIndex[someData['directLogins'][indexReference]['record']]];
|
||||
|
||||
if (record != null) {
|
||||
// directLogin = new Clipperz.PM.DataModel.DirectLogin({
|
||||
new Clipperz.PM.DataModel.DirectLogin({
|
||||
'reference': reference,
|
||||
'record': record
|
||||
@@ -301,6 +290,7 @@ Clipperz.log("SKIPPING record " + reference + " as there are no stas associated
|
||||
'retrieveIndexDataFunction': MochiKit.Base.method(this, 'getRecordIndexData'),
|
||||
'updateIndexDataFunction': MochiKit.Base.method(this, 'updateRecordIndexData'),
|
||||
'updateDate': Clipperz.PM.Date.formatDateWithUTCFormat(new Date()),
|
||||
'accessDate': Clipperz.PM.Date.formatDateWithUTCFormat(new Date()),
|
||||
|
||||
'retrieveDirectLoginIndexDataFunction': MochiKit.Base.method(this, 'getDirectLoginIndexData'),
|
||||
'setDirectLoginIndexDataFunction': MochiKit.Base.method(this, 'setDirectLoginIndexData'),
|
||||
@@ -384,10 +374,6 @@ Clipperz.log("SKIPPING record " + reference + " as there are no stas associated
|
||||
|
||||
'deleteAllCleanTextData': function () {
|
||||
return Clipperz.Async.callbacks("User.Header.RecordIndex.deleteAllCleanTextData", [
|
||||
// MochiKit.Base.method(this, 'records'),
|
||||
// MochiKit.Base.values,
|
||||
// MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('deleteAllCleanTextData')),
|
||||
|
||||
MochiKit.Base.method(this, 'recordsData'),
|
||||
MochiKit.Base.methodcaller('deleteAllCleanTextData'),
|
||||
MochiKit.Base.method(this, 'directLoginsData'),
|
||||
@@ -410,21 +396,9 @@ Clipperz.log("SKIPPING record " + reference + " as there are no stas associated
|
||||
MochiKit.Base.method(this, 'directLoginsData'),
|
||||
MochiKit.Base.methodcaller('hasAnyCleanTextData')
|
||||
],
|
||||
// 'records': [
|
||||
// MochiKit.Base.method(this, 'records'),
|
||||
// MochiKit.Base.values,
|
||||
// MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('hasAnyCleanTextData')),
|
||||
// Clipperz.Async.collectAll
|
||||
// ]
|
||||
});
|
||||
|
||||
// deferredResult.addCallback(MochiKit.Base.values);
|
||||
// deferredResult.addCallback(MochiKit.Base.flattenArguments);
|
||||
// deferredResult.addCallback(function(someValues) {
|
||||
// return MochiKit.Iter.some(someValues, MochiKit.Base.operator.identity);
|
||||
// });
|
||||
deferredResult.addCallback(Clipperz.Async.or);
|
||||
|
||||
deferredResult.callback();
|
||||
|
||||
return deferredResult;
|
||||
@@ -447,11 +421,6 @@ Clipperz.log("SKIPPING record " + reference + " as there are no stas associated
|
||||
]
|
||||
});
|
||||
deferredResult.addCallback(Clipperz.Async.or);
|
||||
// deferredResult.addCallback(MochiKit.Base.values);
|
||||
// deferredResult.addCallback(MochiKit.Base.flattenArguments);
|
||||
// deferredResult.addCallback(function(someValues) {
|
||||
// return MochiKit.Iter.some(someValues, MochiKit.Base.operator.identity);
|
||||
// });
|
||||
deferredResult.callback();
|
||||
|
||||
return deferredResult;
|
||||
@@ -482,9 +451,6 @@ Clipperz.log("SKIPPING record " + reference + " as there are no stas associated
|
||||
MochiKit.Base.method(this, 'recordsData'),
|
||||
MochiKit.Base.methodcaller('revertChanges'),
|
||||
|
||||
// MochiKit.Base.method(this, 'directLoginsData'),
|
||||
// MochiKit.Base.methodcaller('revertChanges'),
|
||||
|
||||
MochiKit.Base.method(this, 'records'),
|
||||
MochiKit.Base.bind(function (someRecords) {
|
||||
var recordReference;
|
||||
@@ -500,22 +466,10 @@ Clipperz.log("SKIPPING record " + reference + " as there are no stas associated
|
||||
}
|
||||
}, this),
|
||||
|
||||
// MochiKit.Base.method(this, 'directLogins'),
|
||||
MochiKit.Base.bind(function () {
|
||||
var directLoginReference;
|
||||
|
||||
// this.transientState().setValue('newDirectLoginReferences' + '.' + newDirectLogin.reference(), newDirectLogin);
|
||||
//
|
||||
// this.directLoginsIndex()[newDirectLogin.reference()] = newDirectLoginIndexValue;
|
||||
// this.directLoginsData().setValue(this.directLoginsIndex()[newDirectLogin.reference()], {'record': this.recordsIndex()[aRecord.reference()]});
|
||||
|
||||
|
||||
// for (directLoginReference in this.transientState().getValue('deleteDirectLoginReferences')) {
|
||||
// someDirectLogins[directLoginReference] = this.transientState().getValue('deleteDirectLoginReferences' + '.' + recordReference);
|
||||
// }
|
||||
|
||||
for (directLoginReference in this.transientState().getValue('newDirectLoginReferences')) {
|
||||
// this.directLoginsData().removeValue(this.directLoginsIndex()[directLoginReference]);
|
||||
delete this.directLoginsIndex()[directLoginReference];
|
||||
}
|
||||
}, this),
|
||||
|
||||
@@ -41,7 +41,7 @@ Clipperz.PM.DataModel.User = function (args) {
|
||||
this._connection = null;
|
||||
this._connectionVersion = 'current';
|
||||
|
||||
this._subscription = null;
|
||||
this._accountInfo = null;
|
||||
this._serverData = null;
|
||||
// this._serverLockValue = null;
|
||||
this._transientState = null;
|
||||
@@ -78,12 +78,12 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// this.setSubscription(new Clipperz.PM.DataModel.User.Subscription(someServerData['subscription']));
|
||||
'subscription': function () {
|
||||
return this._subscription;
|
||||
'accountInfo': function () {
|
||||
return this._accountInfo;
|
||||
},
|
||||
|
||||
'setSubscription': function (aValue) {
|
||||
this._subscription = aValue;
|
||||
'setAccountInfo': function (aValue) {
|
||||
this._accountInfo = aValue;
|
||||
},
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -247,19 +247,16 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
|
||||
var deferredResult;
|
||||
|
||||
deferredResult = new Clipperz.Async.Deferred("User.login", {trace:false});
|
||||
// deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'updateProgress', {'extraSteps':3});
|
||||
deferredResult.addMethod(this, 'getPassphrase');
|
||||
deferredResult.addCallback(Clipperz.PM.DataModel.OneTimePassword.isValidOneTimePasswordValue);
|
||||
deferredResult.addCallback(Clipperz.Async.deferredIf("Is the passphrase an OTP", [
|
||||
// MochiKit.Base.partial(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'updateProgress', {'extraSteps':1}),
|
||||
MochiKit.Base.method(this, 'getCredentials'),
|
||||
MochiKit.Base.method(this.connection(), 'redeemOneTimePassword'),
|
||||
MochiKit.Base.method(this.data(), 'setValue', 'passphrase')
|
||||
], []));
|
||||
deferredResult.addErrback(MochiKit.Base.method(this, 'getPassphrase'));
|
||||
deferredResult.addMethod(this.connection(), 'login', false);
|
||||
deferredResult.addMethod(this, 'setupConnectionInfo');
|
||||
// deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'userSuccessfullyLoggedIn');
|
||||
deferredResult.addMethod(this, 'setupAccountInfo');
|
||||
deferredResult.addErrback (MochiKit.Base.method(this, 'handleConnectionFallback'));
|
||||
|
||||
deferredResult.callback();
|
||||
@@ -295,9 +292,10 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
'setupConnectionInfo': function (aValue) {
|
||||
'setupAccountInfo': function (aValue) {
|
||||
//console.log("User.setupAccountInfo", aValue, aValue['accountInfo']);
|
||||
// this.setLoginInfo(aValue['loginInfo']);
|
||||
this.setSubscription(new Clipperz.PM.DataModel.User.Subscription(aValue['subscription']));
|
||||
this.setAccountInfo(new Clipperz.PM.DataModel.User.AccountInfo(aValue['accountInfo']));
|
||||
},
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -511,6 +509,19 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
|
||||
|
||||
//=========================================================================
|
||||
|
||||
'getTags': function () {
|
||||
return Clipperz.Async.callbacks("User.getTags", [
|
||||
MochiKit.Base.method(this, 'getRecords'),
|
||||
MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('tags')),
|
||||
Clipperz.Async.collectAll,
|
||||
MochiKit.Base.flattenArray,
|
||||
Clipperz.Base.arrayWithUniqueValues
|
||||
|
||||
], {trace:false});
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
'getRecords': function () {
|
||||
return Clipperz.Async.callbacks("User.getRecords", [
|
||||
MochiKit.Base.method(this, 'getHeaderIndex', 'recordsIndex'),
|
||||
@@ -519,6 +530,36 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
|
||||
], {trace:false});
|
||||
},
|
||||
|
||||
'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
|
||||
], {trace:false});
|
||||
},
|
||||
/*
|
||||
'filterRecordsInfo': function (someArgs) {
|
||||
var info = (someArgs.info ? someArgs.info : Clipperz.PM.DataModel.Record.defaultCardInfo);
|
||||
var searchField = (someArgs.searchField ? someArgs.searchField : Clipperz.PM.DataModel.Record.defaultSearchField);
|
||||
var includeArchived = (someArgs.includeArchived ? someArgs.includeArchived : false);
|
||||
var regExp = (someArgs.regExp ? someArgs.regExp : Clipperz.PM.DataModel.Record.regExpForSearch(''));
|
||||
|
||||
if (someArgs.regExp) {
|
||||
regExp = regExp;
|
||||
} else if (someArgs.search) {
|
||||
regExp = Clipperz.PM.DataModel.Record.regExpForSearch(someArgs.search);
|
||||
} else if (someArgs.tag) {
|
||||
regExp = Clipperz.PM.DataModel.Record.regExpForTag(someArgs.tag);
|
||||
} else {
|
||||
regExp = Clipperz.PM.DataModel.Record.regExpForSearch('');
|
||||
};
|
||||
|
||||
return Clipperz.Async.callbacks("User.filterRecordsInfo", [
|
||||
MochiKit.Base.method(this, 'getRecordsInfo', info, includeArchived),
|
||||
MochiKit.Base.partial(MochiKit.Base.filter, function (aCardInfo) { regExp.lastIndex = 0; return regExp.test(aCardInfo[searchField]);})
|
||||
], {trace:false});
|
||||
},
|
||||
*/
|
||||
'recordWithLabel': function (aLabel) {
|
||||
return Clipperz.Async.callbacks("User.recordWithLabel", [
|
||||
MochiKit.Base.method(this, 'getRecords'),
|
||||
|
||||
@@ -152,7 +152,7 @@ Clipperz.PM.Proxy.prototype = MochiKit.Base.update(null, {
|
||||
'sendMessage': function (aFunctionName, someParameters) {
|
||||
var deferredResult;
|
||||
|
||||
console.log("PROXY.sendMessage", aFunctionName, someParameters);
|
||||
//console.log("PROXY.sendMessage", aFunctionName, someParameters);
|
||||
// TODO: read actual application version for a property set at build time
|
||||
deferredResult = new Clipperz.Async.Deferred("Proxy.sendMessage", {trace:false});
|
||||
deferredResult.addMethod(this, '_sendMessage', aFunctionName, 'fake-app-version');
|
||||
|
||||
@@ -57,7 +57,7 @@ Clipperz.Base.extend(Clipperz.PM.Proxy.JSON, Clipperz.PM.Proxy, {
|
||||
version: aVersion,
|
||||
parameters: Clipperz.Base.serializeJSON(someParameters)
|
||||
};
|
||||
console.log("PROXY.JSON._sendMessage", parameters);
|
||||
//console.log("PROXY.JSON._sendMessage", parameters);
|
||||
deferredResult = new Clipperz.Async.Deferred("Proxy.JSON._sendMessage", {trace:false});
|
||||
deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'remoteRequestSent');
|
||||
deferredResult.addCallback(MochiKit.Async.doXHR, this.url(), {
|
||||
|
||||
@@ -36,7 +36,7 @@ Clipperz.PM.Proxy.Offline.DataStore = function(args) {
|
||||
|
||||
this._tolls = {};
|
||||
this._currentStaticConnection = null;
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ Clipperz.Base.extend(Clipperz.PM.Proxy.Offline.DataStore, Object, {
|
||||
'isReadOnly': function () {
|
||||
return this._isReadOnly;
|
||||
},
|
||||
|
||||
|
||||
'canRegisterNewUsers': function () {
|
||||
return false;
|
||||
},
|
||||
@@ -296,14 +296,14 @@ Clipperz.Base.extend(Clipperz.PM.Proxy.Offline.DataStore, Object, {
|
||||
throw "user already exists";
|
||||
}
|
||||
} else {
|
||||
throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly;
|
||||
throw Clipperz.PM.Proxy.Offline.DataStore.exception.ReadOnly;
|
||||
}
|
||||
|
||||
result = {
|
||||
result: {
|
||||
'lock': this.data()['users'][someParameters['credentials']['C']]['lock'],
|
||||
'result': 'done'
|
||||
},
|
||||
},
|
||||
toll: this.getTollForRequestType('CONNECT')
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@ Clipperz.Base.extend(Clipperz.PM.Proxy.Offline.DataStore, Object, {
|
||||
randomBytes = Clipperz.Crypto.Base.generateRandomSeed();
|
||||
aConnection['b'] = new Clipperz.Crypto.BigInt(randomBytes, 16);
|
||||
v = new Clipperz.Crypto.BigInt(aConnection['userData']['v'], 16);
|
||||
aConnection['B'] = v.add(Clipperz.Crypto.SRP.g().powerModule(aConnection['b'], Clipperz.Crypto.SRP.n()));
|
||||
aConnection['B'] = (Clipperz.Crypto.SRP.k().multiply(v)).add(Clipperz.Crypto.SRP.g().powerModule(aConnection['b'], Clipperz.Crypto.SRP.n()));
|
||||
|
||||
aConnection['A'] = someParameters.parameters.A;
|
||||
|
||||
@@ -343,21 +343,65 @@ Clipperz.Base.extend(Clipperz.PM.Proxy.Offline.DataStore, Object, {
|
||||
|
||||
nextTollRequestType = 'CONNECT';
|
||||
} else if (someParameters.message == "credentialCheck") {
|
||||
var v, u, S, A, K, M1;
|
||||
|
||||
var v, u, s, S, A, K, M1;
|
||||
var stringHash = function (aValue) {
|
||||
return Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(aValue)).toHexString().substring(2);
|
||||
};
|
||||
|
||||
v = new Clipperz.Crypto.BigInt(aConnection['userData']['v'], 16);
|
||||
u = new Clipperz.Crypto.BigInt(Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(aConnection['B'].asString(10))).toHexString(), 16);
|
||||
A = new Clipperz.Crypto.BigInt(aConnection['A'], 16);
|
||||
u = new Clipperz.Crypto.BigInt(Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(A.asString(10) + aConnection['B'].asString(10))).toHexString(), 16);
|
||||
s = new Clipperz.Crypto.BigInt(aConnection['userData']['s'], 16);
|
||||
S = (A.multiply(v.powerModule(u, Clipperz.Crypto.SRP.n()))).powerModule(aConnection['b'], Clipperz.Crypto.SRP.n());
|
||||
|
||||
K = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(S.asString(10))).toHexString().slice(2);
|
||||
K = stringHash(S.asString(10));
|
||||
|
||||
M1 = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(A.asString(10) + aConnection['B'].asString(10) + K)).toHexString().slice(2);
|
||||
M1 = stringHash(
|
||||
"597626870978286801440197562148588907434001483655788865609375806439877501869636875571920406529" +
|
||||
stringHash(aConnection['C']) +
|
||||
s.asString(10) +
|
||||
A.asString(10) +
|
||||
aConnection['B'].asString(10) +
|
||||
K
|
||||
);
|
||||
if (someParameters.parameters.M1 == M1) {
|
||||
var M2;
|
||||
|
||||
M2 = Clipperz.PM.Crypto.encryptingFunctions.versions[someParameters.version].hash(new Clipperz.ByteArray(A.asString(10) + someParameters.parameters.M1 + K)).toHexString().slice(2);
|
||||
M2 = stringHash(
|
||||
A.asString(10) +
|
||||
someParameters.parameters.M1 +
|
||||
K
|
||||
);
|
||||
result['M2'] = M2;
|
||||
result['accountInfo'] = {
|
||||
'currentSubscriptionType': "FAN",
|
||||
'expirationDate': "Tue, 21 April 2015 11:59:12 UTC",
|
||||
'featureSet': "FULL",
|
||||
'features': [
|
||||
'UPDATE_CREDENTIALS',
|
||||
'EDIT_CARD',
|
||||
'CARD_DETAILS',
|
||||
'ADD_CARD',
|
||||
'DELETE_CARD',
|
||||
'OFFLINE_COPY',
|
||||
'LIST_CARDS'
|
||||
],
|
||||
'isExpired': false,
|
||||
'isExpiring': false,
|
||||
'latestActiveLevel': "PAYING",
|
||||
'latestActiveThreshold': "5.00000000",
|
||||
'paymentVerificationPending': false,
|
||||
'payments': [
|
||||
{
|
||||
'amount': "0.08500000",
|
||||
'currency': "BTC",
|
||||
'date': "Mon, 21 April 2014 12:11:12 UTC",
|
||||
'reference': "cad577106f8747ae1b0fad3f139f4b4644301a0608dd931f758ad18c1766cabe",
|
||||
'value': "5.23730000"
|
||||
}
|
||||
],
|
||||
'referenceDate': "Tue, 22 July 2014 15:47:08 UTC"
|
||||
};
|
||||
} else {
|
||||
throw new Error("Client checksum verification failed! Expected <" + M1 + ">, received <" + someParameters.parameters.M1 + ">.", "Error");
|
||||
}
|
||||
@@ -426,6 +470,7 @@ Clipperz.Base.extend(Clipperz.PM.Proxy.Offline.DataStore, Object, {
|
||||
recordsStats = {};
|
||||
for (recordReference in aConnection['userData']['records']) {
|
||||
recordsStats[recordReference] = {
|
||||
'accessDate': aConnection['userData']['records'][recordReference]['accessDate'],
|
||||
'updateDate': aConnection['userData']['records'][recordReference]['updateDate']
|
||||
}
|
||||
}
|
||||
|
||||
56
frontend/delta/js/Clipperz/PM/UI/Components/AccountStatus.js
Normal file
56
frontend/delta/js/Clipperz/PM/UI/Components/AccountStatus.js
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components');
|
||||
|
||||
Clipperz.PM.UI.Components.AccountStatus = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
'currentSubscriptionType': React.PropTypes.oneOf(['EARLY_ADOPTER', 'FRIEND', 'FAN', 'DEVOTEE', 'PATRON', 'TRIAL', 'TRIAL_EXPIRED', 'PAYMENT_FAILED_2', 'EXPIRED', 'PAYMENT_FAILED', 'VERIFYING_PAYMENT', 'VERIFYING_PAYMENT_2']).isRequired,
|
||||
'expirationDate': React.PropTypes.string.isRequired,
|
||||
'featureSet': React.PropTypes.oneOf(['TRIAL', 'EXPIRED', 'FULL']).isRequired,
|
||||
'isExpired': React.PropTypes.bool.isRequired,
|
||||
'isExpiring': React.PropTypes.bool.isRequired,
|
||||
'paymentVerificationPending': React.PropTypes.bool.isRequired,
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
render: function () {
|
||||
//console.log("AccountStatus props", this.props);
|
||||
var classes = {
|
||||
'accountStatus': true,
|
||||
'isExpiring': this.props['isExpiring'],
|
||||
'isExpired': this.props['isExpired'],
|
||||
};
|
||||
|
||||
classes[this.props['featureSet']] = true;
|
||||
|
||||
return React.DOM.div({'className':React.addons.classSet(classes)}, [
|
||||
React.DOM.span({'className': 'level'}, this.props['featureSet']),
|
||||
React.DOM.span({'className': 'expirationDate'}, this.props['expirationDate'])
|
||||
]);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
53
frontend/delta/js/Clipperz/PM/UI/Components/Button.js
Normal file
53
frontend/delta/js/Clipperz/PM/UI/Components/Button.js
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components');
|
||||
|
||||
Clipperz.PM.UI.Components.Button = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
'eventName': React.PropTypes.string.isRequired,
|
||||
'label': React.PropTypes.string.isRequired,
|
||||
'handler': React.PropTypes.func.isRequired,
|
||||
'className': React.PropTypes.string
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
render: function () {
|
||||
var classes = {
|
||||
'button': true
|
||||
};
|
||||
if (typeof(this.props['className']) != 'undefined') {
|
||||
classes[this.props['className']] = true;
|
||||
};
|
||||
|
||||
return React.DOM.div({className:React.addons.classSet(classes), onClick:this.props['handler']}, [
|
||||
React.DOM.div({className:this.props['eventName']}, [
|
||||
React.DOM.h3({className:'label'}, this.props['label'])
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
@@ -1,195 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.PM.UI.Components.CardDetail = React.createClass({
|
||||
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
// searchDelay: 0.3
|
||||
}
|
||||
},
|
||||
|
||||
propTypes: {
|
||||
card: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
getInitialState: function () {
|
||||
return {
|
||||
// showSearch: false,
|
||||
// searchTimer: null,
|
||||
unmaskedFields: new Clipperz.Set(),
|
||||
starred: false
|
||||
};
|
||||
},
|
||||
|
||||
handleDirectLoginClick: function (aDirectLoginReference, anEvent) {
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'runDirectLogin', {record:this.props.card['reference'], directLogin:aDirectLoginReference});
|
||||
},
|
||||
|
||||
toggleFieldVisibility: function (aField, anEvent) {
|
||||
var unmaskedFields;
|
||||
var fieldReference;
|
||||
|
||||
unmaskedFields = this.state['unmaskedFields'];
|
||||
fieldReference = aField['reference']
|
||||
if (unmaskedFields.contains(fieldReference)) {
|
||||
unmaskedFields.remove(fieldReference)
|
||||
} else {
|
||||
unmaskedFields.add(fieldReference)
|
||||
}
|
||||
|
||||
this.setState({'unmaskedFields': unmaskedFields});
|
||||
},
|
||||
|
||||
handleGoAction: function (aField, anEvent) {
|
||||
var newWindow;
|
||||
|
||||
newWindow = MochiKit.DOM.currentWindow().open(aField['value'], '_blank');
|
||||
newWindow.focus();
|
||||
},
|
||||
|
||||
handleEmailAction: function (aField, anEvent) {
|
||||
MochiKit.DOM.currentWindow().location = 'mailto:' + aField['value'];
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
normalizeFieldValue: function (aValue) {
|
||||
var result = [];
|
||||
var rows = aValue.split('\n');
|
||||
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
if (i > 0) {
|
||||
result.push(React.DOM.br());
|
||||
}
|
||||
result.push(rows[i].replace(/[\s]/g, '\u00A0'));
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
renderFieldActionButton: function (aField) {
|
||||
// var actionLabel;
|
||||
var result;
|
||||
|
||||
if (aField['actionType'] == 'URL') {
|
||||
result = React.DOM.div({className:'actionWrapper', onClick:MochiKit.Base.method(this, 'handleGoAction', aField)}, [
|
||||
React.DOM.a({className:aField['actionType']}, "go")
|
||||
]);
|
||||
} else if (aField['actionType'] == 'PASSWORD') {
|
||||
var icon;
|
||||
|
||||
if (this.state['unmaskedFields'].contains(aField['reference'])) {
|
||||
icon = "unlocked";
|
||||
} else {
|
||||
icon = "locked";
|
||||
}
|
||||
result = React.DOM.div({className:'actionWrapper', onClick:MochiKit.Base.method(this, 'toggleFieldVisibility', aField)}, [
|
||||
React.DOM.a({className:aField['actionType']}, icon)
|
||||
]);
|
||||
} else if (aField['actionType'] == 'EMAIL') {
|
||||
result = React.DOM.div({className:'actionWrapper', onClick:MochiKit.Base.method(this, 'handleEmailAction', aField)}, [
|
||||
React.DOM.a({className:aField['actionType']}, "email")
|
||||
]);
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
renderField: function (aField) {
|
||||
//console.log("FIELD", aField);
|
||||
var fieldExtraClass;
|
||||
|
||||
fieldExtraClass = aField['actionType'];
|
||||
if (this.state['unmaskedFields'].contains(aField['reference'])) {
|
||||
fieldExtraClass = fieldExtraClass + ' unlocked';
|
||||
}
|
||||
|
||||
return React.DOM.div({className:'listItem ' + fieldExtraClass, key:aField['reference']}, [
|
||||
React.DOM.div({className:'fieldWrapper'}, [
|
||||
React.DOM.div({className:'fieldInnerWrapper'}, [
|
||||
React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aField['label'])),
|
||||
React.DOM.div({className:'valueWrapper'}, React.DOM.span({className:'value ' + fieldExtraClass}, this.normalizeFieldValue(aField['value'])))
|
||||
])
|
||||
]),
|
||||
this.renderFieldActionButton(aField)
|
||||
// React.DOM.div({className:'actionWrapper'}, [
|
||||
// React.DOM.div({className:aField['actionType']}, actionLabel)
|
||||
// ])
|
||||
]);
|
||||
},
|
||||
|
||||
renderDirectLogin: function (aDirectLogin) {
|
||||
//console.log("DIRECT LOGIN", aDirectLogin);
|
||||
return React.DOM.div({className:'listItem', onClick:MochiKit.Base.method(this, 'handleDirectLoginClick', aDirectLogin['reference'])}, [
|
||||
React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aDirectLogin['label'])),
|
||||
React.DOM.div({className:'faviconWrapper'}, React.DOM.img({className:'favicon', src:aDirectLogin['favicon']})),
|
||||
React.DOM.div({className:'directLoginLinkWrapper'}, React.DOM.span({className:'directLoginLink'}, "go"))
|
||||
]);
|
||||
},
|
||||
|
||||
handleBackClick: function (anEvent) {
|
||||
// window.history.back();
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'goBack');
|
||||
},
|
||||
|
||||
handleStarClick: function (anEvent) {
|
||||
this.setState({starred: !this.state['starred']});
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
render: function () {
|
||||
var card = this.props.card;
|
||||
// var starredStatus = (this.state['starred'] ? "starred" : "unstarred");
|
||||
|
||||
if ((typeof(card['fields']) != 'undefined') && (card['notes'] != '')) {
|
||||
card['fields'].push({ 'actionType': 'NOTES', 'isHidden': false, 'label': "notes", 'reference': "notes", 'value': card['notes'] })
|
||||
}
|
||||
|
||||
return React.DOM.div({className:'cardDetail'}, [
|
||||
React.DOM.div({className:'header'}, [
|
||||
React.DOM.div({className:'titleWrapper'}, React.DOM.div({className:'title'}, card.title)),
|
||||
React.DOM.div({className:'backWrapper'}, React.DOM.a({className:'button back', onClick:this.handleBackClick}, "back")),
|
||||
// React.DOM.div({className:'starWrapper'}, React.DOM.a({className:'star', onClick:this.handleStarClick}, starredStatus))
|
||||
]),
|
||||
React.DOM.div({className:'content'}, [
|
||||
card.fields ? React.DOM.div({className:'fields'}, MochiKit.Base.map(this.renderField, card.fields)) : null,
|
||||
card.directLogins ? React.DOM.div({className:'directLogins'}, MochiKit.Base.map(this.renderDirectLogin, card.directLogins)): null
|
||||
]),
|
||||
React.DOM.div({className:'footer'}, [
|
||||
/*
|
||||
// React.DOM.a({className:'cancel'}, "cancel"),
|
||||
// React.DOM.a({className:'save'}, "save")
|
||||
|
||||
React.DOM.a({className:'cancel button'}, "failed"),
|
||||
React.DOM.a({className:'save button'}, "done")
|
||||
*/
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.PM.UI.Components.CardList = React.createClass({
|
||||
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
selectedCard: null,
|
||||
searchDelay: 0.3
|
||||
}
|
||||
},
|
||||
|
||||
propTypes: {
|
||||
searchDelay: React.PropTypes.number
|
||||
},
|
||||
|
||||
getInitialState: function () {
|
||||
return {
|
||||
showSearch: false,
|
||||
searchTimer: null,
|
||||
searchText: '',
|
||||
// passphrase: '',
|
||||
// pin: ''
|
||||
};
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
toggleSearch: function (anEvent) {
|
||||
var showSearchBox;
|
||||
|
||||
showSearchBox = !this.state.showSearch;
|
||||
|
||||
this.setState({showSearch: showSearchBox});
|
||||
|
||||
if (showSearchBox) {
|
||||
MochiKit.Async.callLater(0.1, MochiKit.Base.method(this, 'focusOnSearchField'));
|
||||
}
|
||||
},
|
||||
|
||||
updateSearchText: function (anEvent) {
|
||||
var searchText;
|
||||
|
||||
searchText = anEvent.target.value;
|
||||
//console.log(">>> updateSearchText", searchText);
|
||||
|
||||
if ((this.state['searchTimer'] != null) && (searchText != this.state['searchText'])) {
|
||||
this.state['searchTimer'].cancel();
|
||||
}
|
||||
|
||||
if (searchText != this.state['searchText']) {
|
||||
this.state['searchText'] = searchText;
|
||||
this.state['searchTimer'] = MochiKit.Async.callLater(this.props['searchDelay'], MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'searchCards', searchText);
|
||||
}
|
||||
},
|
||||
|
||||
focusOnSearchField: function () {
|
||||
console.log("focusOnSearchField", this.refs['searchField']);
|
||||
this.refs['searchField'].getDOMNode.focus();
|
||||
},
|
||||
|
||||
searchBox: function () {
|
||||
var result;
|
||||
|
||||
if (this.state.showSearch) {
|
||||
result = React.DOM.div({className:'searchBox'}, [
|
||||
React.DOM.div(null, [
|
||||
React.DOM.input({type:'search', placeholder:"search", ref:'searchField', onChange:this.updateSearchText})
|
||||
])
|
||||
]);
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
showPreferences: function (anEvent) {
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'showPreferences', anEvent);
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
cardItem: function (aRecordReference) {
|
||||
var reference = aRecordReference['_reference'];
|
||||
var selectedCard = (reference == this.props.selectedCard);
|
||||
|
||||
// TODO: verify if it is possible to put the onClick handler on the container 'div', instead of adding it to each 'div' item.
|
||||
return React.DOM.div({className:'listItem', key:reference, onClick:MochiKit.Base.method(this, 'handleClickOnCardDetail', reference)}, [
|
||||
React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aRecordReference.label)),
|
||||
// React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label)),
|
||||
React.DOM.div({className:'faviconWrapper'}, aRecordReference.favicon ? React.DOM.img({className:'favicon', src:aRecordReference.favicon}) : React.DOM.div({className:'favicon'}, '\u00A0')),
|
||||
React.DOM.div({className:'detailLinkWrapper'}, React.DOM.span({className:'detailLink ' + (selectedCard ? 'icon-spin' : '')}, (selectedCard ? "loading" : "detail")))
|
||||
]);
|
||||
},
|
||||
|
||||
handleClickOnCardDetail: function (aRecordReference, anEvent) {
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'showRecord', aRecordReference);
|
||||
},
|
||||
|
||||
cardListItems: function () {
|
||||
var list;
|
||||
var result;
|
||||
|
||||
list = this.props['cardList'];
|
||||
|
||||
if (typeof(list) != 'undefined') {
|
||||
result = MochiKit.Base.map(MochiKit.Base.method(this, 'cardItem'), list);
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
handleChange: function (anEvent) {
|
||||
// var refs = this.refs;
|
||||
// var refName = MochiKit.Base.filter(function (aRefName) { return refs[aRefName].getDOMNode() == anEvent.target}, MochiKit.Base.keys(this.refs))[0];
|
||||
// var newState = {};
|
||||
//
|
||||
// newState[refName] = event.target.value;
|
||||
// this.setState(newState);
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
render: function() {
|
||||
return React.DOM.div(null, [
|
||||
React.DOM.div({className:'header'}, [
|
||||
React.DOM.a({className:'account'}, 'clipperz'),
|
||||
React.DOM.div({className:'features'}, [
|
||||
// React.DOM.a({className:'addCard'}, 'add'),
|
||||
React.DOM.a({className:'search ' + (this.state.showSearch ? 'selected' : ''), onClick:this.toggleSearch}, 'search'),
|
||||
React.DOM.a({className:'settings', onClick:this.showPreferences}, 'settings')
|
||||
]),
|
||||
// this.searchBox()
|
||||
]),
|
||||
this.searchBox(),
|
||||
React.DOM.div({className:'content cardList'}, this.cardListItems()),
|
||||
]);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
101
frontend/delta/js/Clipperz/PM/UI/Components/CardToolbar.js
Normal file
101
frontend/delta/js/Clipperz/PM/UI/Components/CardToolbar.js
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components');
|
||||
|
||||
Clipperz.PM.UI.Components.CardToolbar = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
// 'style': React.PropTypes.oneOf(['extra-short', 'narrow', 'wide', 'extra-wide']).isRequired,
|
||||
'style': React.PropTypes.oneOf(Clipperz_PM_UI_availableStyles).isRequired,
|
||||
'enableSidePanels': React.PropTypes.bool.isRequired,
|
||||
'accountStatus': React.PropTypes.object.isRequired,
|
||||
'messageBox': React.PropTypes.object.isRequired,
|
||||
'filter': React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
selectionToggleHandler: function (anEvent) {
|
||||
//console.log("selectionToggleHandler");
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'toggleSelectionPanel');
|
||||
|
||||
},
|
||||
|
||||
settingsToggleHandler: function (anEvent) {
|
||||
//console.log("settingsToggleHandler");
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'toggleSettingsPanel');
|
||||
},
|
||||
|
||||
//============================================================================
|
||||
|
||||
renderWithSidePanels: function () {
|
||||
return [
|
||||
React.DOM.div({className:'selectionToggle'}, [
|
||||
Clipperz.PM.UI.Components.Button({eventName:'selectionToggleButton', label:"tags", handler:this.selectionToggleHandler})
|
||||
]),
|
||||
this.renderWithoutSidePanels(),
|
||||
React.DOM.div({className:'settingsToggle'}, [
|
||||
Clipperz.PM.UI.Components.Button({eventName:'settingsToggleButton', label:"menu", handler:this.settingsToggleHandler})
|
||||
])
|
||||
];
|
||||
},
|
||||
|
||||
renderWithoutSidePanels: function () {
|
||||
var result;
|
||||
|
||||
if (this.props['filter']) {
|
||||
if (this.props['filter']['type'] == 'RECENT') {
|
||||
result = [React.DOM.div({className:'clipperz'}, [React.DOM.span({className:'logo recent'}, "recent")])];
|
||||
} else if (this.props['filter']['type'] == 'TAG') {
|
||||
result = [React.DOM.div({className:'clipperz'}, [
|
||||
React.DOM.span({className:'logo tag'}, "tag"),
|
||||
React.DOM.span({className:'value'}, this.props['filter']['value'])
|
||||
])];
|
||||
} else if (this.props['filter']['type'] == 'SEARCH') {
|
||||
result = [React.DOM.div({className:'clipperz'}, [
|
||||
React.DOM.span({className:'logo search'}, "search"),
|
||||
React.DOM.span({className:'value'}, this.props['filter']['value'])
|
||||
])];
|
||||
} else {
|
||||
result = [React.DOM.div({className:'clipperz'}, [React.DOM.span({className:'logo clipperz'}, "clipperz")])];
|
||||
}
|
||||
} else {
|
||||
result = [React.DOM.div({className:'clipperz'}, [React.DOM.span({className:'logo clipperz'}, "clipperz")])];
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
render: function () {
|
||||
//console.log("CardToolbar props", this.props);
|
||||
return React.DOM.div({className:'cardToolbar ' + this.props['style']}, [
|
||||
// React.DOM.div({className:'header'}, this.props['enableSidePanels'] ? this.renderWithSidePanels() : this.renderWithoutSidePanels()),
|
||||
React.DOM.header({}, this.props['enableSidePanels'] ? this.renderWithSidePanels() : this.renderWithoutSidePanels()),
|
||||
Clipperz.PM.UI.Components.AccountStatus(this.props['accountStatus']),
|
||||
Clipperz.PM.UI.Components.MessageBox(this.props['messageBox']),
|
||||
]);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
});
|
||||
66
frontend/delta/js/Clipperz/PM/UI/Components/Cards/List.js
Normal file
66
frontend/delta/js/Clipperz/PM/UI/Components/Cards/List.js
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components.Cards');
|
||||
|
||||
Clipperz.PM.UI.Components.Cards.List = React.createClass({
|
||||
|
||||
//=========================================================================
|
||||
|
||||
propTypes: {
|
||||
'cards': React.PropTypes.array,
|
||||
'selectedCard': React.PropTypes.string
|
||||
},
|
||||
|
||||
handleClick: function (anEvent) {
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'cardSelected', {'reference':anEvent.currentTarget.dataset.reference, 'label':anEvent.currentTarget.dataset.label});
|
||||
},
|
||||
|
||||
renderItem: function (anItem) {
|
||||
var classes = {
|
||||
'selected': this.props['selectedCard'] ? this.props['selectedCard']['_reference'] == anItem['_reference'] : false
|
||||
};
|
||||
|
||||
return React.DOM.li({'className':React.addons.classSet(classes), 'onClick': this.handleClick, 'key':anItem['_reference'], 'data-reference':anItem['_reference'], 'data-label':anItem['label']}, [
|
||||
React.DOM.span({'className':'favicon'}, [ React.DOM.img({src:anItem['favicon']})]),
|
||||
React.DOM.span({'className':'label'}, anItem['label']),
|
||||
// React.DOM.span({'className':'action'}, 'show detail')
|
||||
]);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
var cards = this.props['cards'] ? this.props['cards'] : [];
|
||||
var classes = {
|
||||
'cardList': true,
|
||||
'loadingCard': this.props['selectedCard'] && this.props['selectedCard']['_reference'] && this.props['selectedCard']['loading']
|
||||
};
|
||||
classes[this.props['style']] = true;
|
||||
|
||||
return React.DOM.div({'key':'cardList', 'className':React.addons.classSet(classes)}, [
|
||||
React.DOM.ul({}, MochiKit.Base.map(this.renderItem, cards))
|
||||
]);
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
133
frontend/delta/js/Clipperz/PM/UI/Components/Cards/Toolbar.js
Normal file
133
frontend/delta/js/Clipperz/PM/UI/Components/Cards/Toolbar.js
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components.Cards');
|
||||
|
||||
Clipperz.PM.UI.Components.Cards.Toolbar = React.createClass({
|
||||
|
||||
//============================================================================
|
||||
|
||||
propTypes: {
|
||||
// 'label': React.PropTypes.string.isRequired,
|
||||
// 'loading': React.PropTypes.bool,
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
getInitialState: function() {
|
||||
return {'showCommandMenu': false };
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
commands: function () {
|
||||
return {
|
||||
'delete': {
|
||||
'label': "delete",
|
||||
'broadcastEvent': 'deleteCard'
|
||||
},
|
||||
'archive': {
|
||||
'label': "archive",
|
||||
'broadcastEvent': 'archiveCard'
|
||||
},
|
||||
// 'share': {
|
||||
// 'label': "share",
|
||||
// 'broadcastEvent': 'shareCard'
|
||||
// },
|
||||
'edit': {
|
||||
'label': "edit",
|
||||
'broadcastEvent': 'editCard'
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
exit: function (anEvent) {
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'goBackToMainPage', {'reference':this.props['_reference']});
|
||||
},
|
||||
|
||||
toggleMenu: function (anEvent) {
|
||||
this.setState({'showCommandMenu': !this.state['showCommandMenu'] });
|
||||
},
|
||||
|
||||
selectCommandItem: function (anEvent) {
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, anEvent.target.dataset['broadcastEvent'], {'reference':this.props['_reference']});
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
renderCommands: function () {
|
||||
var commandHandler = this.selectCommandItem;
|
||||
|
||||
return React.DOM.ul({}, MochiKit.Base.map(function (aCommand) {
|
||||
return React.DOM.li({}, [React.DOM.span({'onClick':commandHandler, 'data-broadcast-event':aCommand['broadcastEvent']}, aCommand['label'])]);
|
||||
}, MochiKit.Base.values(this.commands())));
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
renderNarrow: function () {
|
||||
return [
|
||||
React.DOM.div({}, [
|
||||
React.DOM.div({'className':'back', 'onClick': this.exit}, 'back'),
|
||||
React.DOM.div({'className':'cardMenuOptions', 'onClick':this.toggleMenu}, 'commands'),
|
||||
React.DOM.div({'className':React.addons.classSet({'commandMenu':true, 'show':this.state['showCommandMenu']})}, [
|
||||
React.DOM.div({'className':'commandMenuMask', 'onClick':this.toggleMenu}),
|
||||
React.DOM.div({'className':'commandMenu'}, this.renderCommands())
|
||||
])
|
||||
])
|
||||
]
|
||||
},
|
||||
|
||||
renderOther: function () {
|
||||
return [this.renderCommands()];
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
renderLayout: function (aLayout) {
|
||||
var result;
|
||||
|
||||
if (aLayout == 'narrow') {
|
||||
result = this.renderNarrow();
|
||||
} else {
|
||||
result = this.renderOther();
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
render: function () {
|
||||
var style = this.props['style'];
|
||||
var classes = {
|
||||
'cardDetailToolbar': true,
|
||||
};
|
||||
classes[style] = true;
|
||||
|
||||
return React.DOM.div({'className':React.addons.classSet(classes)}, this.renderLayout(style));
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
161
frontend/delta/js/Clipperz/PM/UI/Components/Cards/View.js
Normal file
161
frontend/delta/js/Clipperz/PM/UI/Components/Cards/View.js
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components.Cards');
|
||||
|
||||
Clipperz.PM.UI.Components.Cards.View = React.createClass({
|
||||
|
||||
//============================================================================
|
||||
|
||||
propTypes: {
|
||||
'label': React.PropTypes.string.isRequired,
|
||||
'loading': React.PropTypes.bool,
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
renderEmpty: function () {
|
||||
return React.DOM.h4({}, "EMPTY");
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
renderLoading: function () {
|
||||
return React.DOM.div({className:'loading'},[
|
||||
this.renderLabel(),
|
||||
React.DOM.h5({className:'message'}, "loading")
|
||||
/*
|
||||
React.DOM.div({className:'overlay'}, [
|
||||
React.DOM.div({className:'spinner'}, [
|
||||
React.DOM.div({className:'bar01'}),
|
||||
React.DOM.div({className:'bar02'}),
|
||||
React.DOM.div({className:'bar03'}),
|
||||
React.DOM.div({className:'bar04'}),
|
||||
React.DOM.div({className:'bar05'}),
|
||||
React.DOM.div({className:'bar06'}),
|
||||
React.DOM.div({className:'bar07'}),
|
||||
React.DOM.div({className:'bar08'}),
|
||||
React.DOM.div({className:'bar09'}),
|
||||
React.DOM.div({className:'bar10'}),
|
||||
React.DOM.div({className:'bar11'}),
|
||||
React.DOM.div({className:'bar12'})
|
||||
])
|
||||
])
|
||||
*/
|
||||
]);
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
renderLabel: function (aLabel) {
|
||||
return React.DOM.h3({'className':'cardLabel'}, aLabel);
|
||||
},
|
||||
|
||||
renderNotes: function (someNotes) {
|
||||
return React.DOM.div({'className':'cardNotes'}, someNotes);
|
||||
},
|
||||
|
||||
//............................................................................
|
||||
|
||||
renderTag: function (aTag) {
|
||||
return React.DOM.div({'className':'cardTag'}, aTag);
|
||||
},
|
||||
|
||||
renderTags: function (someTags) {
|
||||
return React.DOM.div({'className':'cardTags'}, MochiKit.Base.map(this.renderTag, someTags));
|
||||
},
|
||||
|
||||
//............................................................................
|
||||
|
||||
renderField: function (aField) {
|
||||
var cardFieldClasses = {};
|
||||
var cardFieldValueClasses = {};
|
||||
|
||||
cardFieldClasses['cardField'] = true;
|
||||
cardFieldClasses[aField['actionType']] = true;
|
||||
cardFieldClasses['hidden'] = aField['isHidden'];
|
||||
|
||||
cardFieldValueClasses['fieldValue'] = true;
|
||||
cardFieldValueClasses[aField['actionType']] = true;
|
||||
cardFieldValueClasses['hidden'] = aField['isHidden'];
|
||||
|
||||
return React.DOM.div({'className':React.addons.classSet(cardFieldClasses)}, [
|
||||
React.DOM.div({'className':'fieldValues'}, [
|
||||
React.DOM.div({'className':'fieldLabel'}, aField['label']),
|
||||
React.DOM.div({'className':React.addons.classSet(cardFieldValueClasses)}, aField['value']),
|
||||
]),
|
||||
React.DOM.div({'className':'fieldAction action'}, aField['actionType'].toLowerCase())
|
||||
]);
|
||||
},
|
||||
|
||||
renderFields: function (someFields) {
|
||||
return React.DOM.div({'className':'cardFields'}, MochiKit.Base.map(this.renderField, someFields));
|
||||
},
|
||||
|
||||
//............................................................................
|
||||
|
||||
renderDirectLogin: function (aDirectLogin) {
|
||||
return React.DOM.div({'className':'cardDirectLogin'}, [
|
||||
React.DOM.span({'className':'directLoginLabel'}, aDirectLogin['label']),
|
||||
React.DOM.div({'className':'directLoginAction action'}, 'DIRECT LOGIN')
|
||||
]);
|
||||
},
|
||||
|
||||
renderDirectLogins: function (someDirectLogins) {
|
||||
return React.DOM.div({'className':'cardDirectLogins'}, MochiKit.Base.map(this.renderDirectLogin, someDirectLogins));
|
||||
},
|
||||
|
||||
//............................................................................
|
||||
|
||||
renderCard: function () {
|
||||
return React.DOM.div({'className':'view'},[
|
||||
Clipperz.PM.UI.Components.Cards.Toolbar(this.props),
|
||||
React.DOM.div({'className':'content'}, [
|
||||
this.renderLabel(this.props['label']),
|
||||
this.renderTags(this.props['tags']),
|
||||
this.renderNotes(this.props['notes']),
|
||||
this.renderFields(this.props['fields']),
|
||||
this.renderDirectLogins(this.props['directLogins'])
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
render: function () {
|
||||
var result;
|
||||
|
||||
if (this.props['loading'] == true) {
|
||||
result = this.renderLoading();
|
||||
} else if (this.props['label']) {
|
||||
result = this.renderCard();
|
||||
} else {
|
||||
result = this.renderEmpty();
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
@@ -21,6 +21,8 @@ refer to http://www.clipperz.com.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components');
|
||||
|
||||
Clipperz.PM.UI.Components.Checkbox = React.createClass({
|
||||
// http://development.tobypitman.com/iphoneCheckboxes/iphoneCheckboxes2.html
|
||||
|
||||
|
||||
40
frontend/delta/js/Clipperz/PM/UI/Components/ExpiredPanel.js
Normal file
40
frontend/delta/js/Clipperz/PM/UI/Components/ExpiredPanel.js
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components');
|
||||
|
||||
Clipperz.PM.UI.Components.ExpiredPanel = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
// featureSet: React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL']).isRequired,
|
||||
// 'level': React.PropTypes.oneOf(['hide', 'info', 'warning', 'error']).isRequired
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
render: function () {
|
||||
return React.DOM.div({className:'expiredPanel'}, "EXPIRED PANEL");
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
47
frontend/delta/js/Clipperz/PM/UI/Components/MessageBox.js
Normal file
47
frontend/delta/js/Clipperz/PM/UI/Components/MessageBox.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components');
|
||||
|
||||
Clipperz.PM.UI.Components.MessageBox = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
'level': React.PropTypes.oneOf(['HIDE', 'INFO', 'WARNING', 'ERROR']).isRequired,
|
||||
'message': React.PropTypes.string.isRequired
|
||||
},
|
||||
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
level: 'HIDE',
|
||||
message: ''
|
||||
};
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
render: function () {
|
||||
return React.DOM.div({className:'messageBox ' + this.props['level']}, this.props['message']);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
@@ -21,13 +21,13 @@ refer to http://www.clipperz.com.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.PM.UI.Components.PageTemplate = React.createClass({
|
||||
render: function() {
|
||||
return React.DOM.div(null, [
|
||||
React.DOM.div({'className': 'header'}, [
|
||||
React.DOM.h1(null, "clipperz")
|
||||
]),
|
||||
React.DOM.div({'className': 'content'}, this.props.innerComponent)
|
||||
])
|
||||
}
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components.Pages');
|
||||
|
||||
Clipperz.PM.UI.Components.Pages.CardDetailPage = React.createClass({
|
||||
|
||||
render: function () {
|
||||
// return React.DOM.header({'className':''})
|
||||
return Clipperz.PM.UI.Components.Cards.View(this.props['selectedCard']);
|
||||
|
||||
},
|
||||
});
|
||||
@@ -21,11 +21,13 @@ refer to http://www.clipperz.com.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.PM.UI.Components.ErrorPage = React.createClass({
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components.Pages');
|
||||
|
||||
Clipperz.PM.UI.Components.Pages.ErrorPage = React.createClass({
|
||||
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
template: Clipperz.PM.UI.Components.PageTemplate
|
||||
// template: Clipperz.PM.UI.Components.PageTemplate
|
||||
}
|
||||
},
|
||||
|
||||
@@ -36,11 +38,11 @@ Clipperz.PM.UI.Components.ErrorPage = React.createClass({
|
||||
},
|
||||
|
||||
|
||||
_render: function () {
|
||||
render: function () {
|
||||
return React.DOM.div({className:'error-message'}, this.props.message);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
return new this.props.template({'innerComponent': this._render()});
|
||||
}
|
||||
// render: function () {
|
||||
// return new this.props.template({'innerComponent': this._render()});
|
||||
// }
|
||||
});
|
||||
@@ -21,24 +21,26 @@ refer to http://www.clipperz.com.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.PM.UI.Components.LoginForm = React.createClass({
|
||||
"use strict";
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components.Pages');
|
||||
|
||||
Clipperz.PM.UI.Components.Pages.LoginPage = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
mode: React.PropTypes.oneOf(['CREDENTIALS','PIN']).isRequired,
|
||||
isNewUserRegistrationAvailable: React.PropTypes.bool.isRequired,
|
||||
disabled: React.PropTypes.bool.isRequired
|
||||
},
|
||||
/*
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
mode: 'CREDENTIALS',
|
||||
isNewUserRegistrationAvailable: false,
|
||||
disabled: false,
|
||||
template: Clipperz.PM.UI.Components.PageTemplate
|
||||
// template: Clipperz.PM.UI.Components.PageTemplate
|
||||
}
|
||||
},
|
||||
|
||||
propTypes: {
|
||||
mode: React.PropTypes.oneOf(['CREDENTIALS','PIN']),
|
||||
isNewUserRegistrationAvailable: React.PropTypes.bool,
|
||||
disabled: React.PropTypes.bool,
|
||||
template: React.PropTypes.func
|
||||
},
|
||||
|
||||
*/
|
||||
getInitialState: function () {
|
||||
return {
|
||||
username: '',
|
||||
@@ -54,7 +56,7 @@ Clipperz.PM.UI.Components.LoginForm = React.createClass({
|
||||
var refName = MochiKit.Base.filter(function (aRefName) { return refs[aRefName].getDOMNode() == anEvent.target}, MochiKit.Base.keys(this.refs))[0];
|
||||
var newState = {};
|
||||
|
||||
newState[refName] = event.target.value;
|
||||
newState[refName] = anEvent.target.value;
|
||||
this.setState(newState);
|
||||
},
|
||||
|
||||
@@ -86,25 +88,21 @@ Clipperz.PM.UI.Components.LoginForm = React.createClass({
|
||||
((this.state['username'] != '') && (this.state['passphrase'] != ''))
|
||||
||
|
||||
(this.state['pin'] != '')
|
||||
) && !this.props['disabled'];
|
||||
)
|
||||
&&
|
||||
!this.props['disabled'];
|
||||
},
|
||||
|
||||
|
||||
loginForm: function () {
|
||||
registrationLink = React.DOM.div({'className':'registrationLink'}, [
|
||||
React.DOM.a({'onClick':this.handleRegistrationLinkClick}, "Sign up")
|
||||
]);
|
||||
return React.DOM.div({'className':'loginForm credentials'},[
|
||||
React.DOM.form({onChange: this.handleChange, onSubmit:this.handleCredentialSubmit}, [
|
||||
React.DOM.div(null,[
|
||||
React.DOM.label({'for' :'name'}, "username"),
|
||||
React.DOM.input({'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'key':'username', 'autoCapitalize':'none'}),
|
||||
React.DOM.label({'for' :'passphrase'}, "passphrase"),
|
||||
React.DOM.input({'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase", 'key':'passphrase'})
|
||||
]),
|
||||
React.DOM.button({'type':'submit', 'disabled':!this.shouldEnableLoginButton(), 'className':'button'}, "login")
|
||||
return React.DOM.form({'className':'loginForm credentials', 'onChange':this.handleChange, 'onSubmit':this.handleCredentialSubmit}, [
|
||||
React.DOM.div(null,[
|
||||
React.DOM.label({'htmlFor' :'name'}, "username"),
|
||||
React.DOM.input({'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'key':'username', 'autoCapitalize':'none'}),
|
||||
React.DOM.label({'htmlFor' :'passphrase'}, "passphrase"),
|
||||
React.DOM.input({'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase", 'key':'passphrase'})
|
||||
]),
|
||||
this.props.isNewUserRegistrationAvailable ? registrationLink : null
|
||||
React.DOM.button({'type':'submit', 'disabled':!this.shouldEnableLoginButton(), 'className':'button'}, "login")
|
||||
]);
|
||||
},
|
||||
|
||||
@@ -121,14 +119,12 @@ Clipperz.PM.UI.Components.LoginForm = React.createClass({
|
||||
},
|
||||
|
||||
pinForm: function () {
|
||||
return React.DOM.div({'className':'loginForm pin'},[
|
||||
React.DOM.form({onChange: this.handleChange, onSubmit:this.handlePINSubmit}, [
|
||||
React.DOM.div(null,[
|
||||
React.DOM.label({'for':'pin'}, "pin"),
|
||||
React.DOM.input({'type':'text', 'name':'pin', 'ref':'pin', placeholder:"PIN", 'key':'pin', 'autocapitalize':'none'})
|
||||
]),
|
||||
React.DOM.button({'type':'submit', 'disabled':this.props.disabled, 'className':'button'}, "login")
|
||||
])
|
||||
return React.DOM.form({'className':'loginForm pin', 'onChange':this.handleChange, 'onSubmit':this.handlePINSubmit}, [
|
||||
React.DOM.div(null,[
|
||||
React.DOM.label({'for':'pin'}, "pin"),
|
||||
React.DOM.input({'type':'text', 'name':'pin', 'ref':'pin', placeholder:"PIN", 'key':'pin', 'autocapitalize':'none'})
|
||||
]),
|
||||
React.DOM.button({'type':'submit', 'disabled':this.props.disabled, 'className':'button'}, "login")
|
||||
]);
|
||||
},
|
||||
|
||||
@@ -145,6 +141,16 @@ Clipperz.PM.UI.Components.LoginForm = React.createClass({
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return new this.props.template({'innerComponent': this.props.mode == 'PIN' ? this.pinForm() : this.loginForm()});
|
||||
var registrationLink = React.DOM.div({'className':'registrationLink'}, [
|
||||
React.DOM.a({'onClick':this.handleRegistrationLinkClick}, "Sign up")
|
||||
]);
|
||||
|
||||
return React.DOM.div({'className':'loginForm ' + this.props['style']}, [
|
||||
React.DOM.header({}, 'clipperz'),
|
||||
React.DOM.div({'className':'form'}, [
|
||||
this.props.mode == 'PIN' ? this.pinForm() : this.loginForm(),
|
||||
]),
|
||||
this.props.isNewUserRegistrationAvailable ? registrationLink : null
|
||||
]);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components.Pages');
|
||||
|
||||
Clipperz.PM.UI.Components.Pages.MainPage = React.createClass({
|
||||
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
|
||||
propTypes: {
|
||||
'messageBox': React.PropTypes.object.isRequired,
|
||||
// 'featureSet': React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL']),
|
||||
'accountStatus': React.PropTypes.object.isRequired,
|
||||
// 'mediaQueryStyle': React.PropTypes.oneOf(['extra-short', 'narrow', 'wide', 'extra-wide']).isRequired,
|
||||
'style': React.PropTypes.oneOf(Clipperz_PM_UI_availableStyles).isRequired,
|
||||
// 'cards': React.PropTypes.deferred.isRequired
|
||||
},
|
||||
|
||||
getInitialState: function () {
|
||||
return {
|
||||
// shouldStoreDataLocally: false
|
||||
};
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
render: function () {
|
||||
var classes = {
|
||||
'mainPage': true
|
||||
};
|
||||
classes[this.props['style']] = true;
|
||||
//console.log("MainPage.cards", this.props['cards'], this.props['cards'].state());
|
||||
|
||||
return React.DOM.div({className:React.addons.classSet(classes)}, [
|
||||
this.props['style'] != 'extra-wide' ? Clipperz.PM.UI.Components.Panels.SelectionPanel(this.props) : null,
|
||||
Clipperz.PM.UI.Components.Panels.MainPanel(this.props),
|
||||
Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanel(this.props)
|
||||
]);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
@@ -21,7 +21,9 @@ refer to http://www.clipperz.com.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.PM.UI.Components.RegistrationWizard = React.createClass({
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components.Pages');
|
||||
|
||||
Clipperz.PM.UI.Components.Pages.RegistrationPage = React.createClass({
|
||||
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
@@ -31,7 +33,7 @@ Clipperz.PM.UI.Components.RegistrationWizard = React.createClass({
|
||||
{name:'TERMS_OF_SERVICE', label:'registration', _label:'terms', description:"Check our terms of service"}
|
||||
],
|
||||
disabled: false,
|
||||
template: Clipperz.PM.UI.Components.PageTemplate
|
||||
// template: Clipperz.PM.UI.Components.PageTemplate
|
||||
}
|
||||
},
|
||||
|
||||
@@ -166,16 +168,16 @@ Clipperz.PM.UI.Components.RegistrationWizard = React.createClass({
|
||||
|
||||
render_CREDENTIALS: function () {
|
||||
return React.DOM.div(null,[
|
||||
React.DOM.label({'for':'name'}, "username"),
|
||||
React.DOM.label({'htmlFor':'name'}, "username"),
|
||||
React.DOM.input({'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'key':'username', 'autoCapitalize':'none'/*, value:this.state.username*/}),
|
||||
React.DOM.label({'for':'passphrase'}, "passphrase"),
|
||||
React.DOM.label({'htmlFor':'passphrase'}, "passphrase"),
|
||||
React.DOM.input({'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase", 'key':'passphrase'/*, value:this.state.passphrase*/})
|
||||
]);
|
||||
},
|
||||
|
||||
render_PASSWORD_VERIFICATION: function () {
|
||||
return React.DOM.div(null,[
|
||||
React.DOM.label({'for':'verify_passphrase'}, "passphrase"),
|
||||
React.DOM.label({'htmlFor':'verify_passphrase'}, "passphrase"),
|
||||
React.DOM.input({'type':'password', 'name':'verify_passphrase', 'ref':'verify_passphrase', 'placeholder':"verify passphrase", 'key':'verify_passphrase'})
|
||||
]);
|
||||
},
|
||||
@@ -183,12 +185,12 @@ Clipperz.PM.UI.Components.RegistrationWizard = React.createClass({
|
||||
render_TERMS_OF_SERVICE: function () {
|
||||
return React.DOM.div(null, [
|
||||
React.DOM.div({className:'checkboxBlock'}, [
|
||||
React.DOM.label({'for':'no_password_recovery'}, "I understand that Clipperz will not be able to recover a lost passphrase."),
|
||||
React.DOM.label({'htmlFor':'no_password_recovery'}, "I understand that Clipperz will not be able to recover a lost passphrase."),
|
||||
React.DOM.input({'type':'checkbox', 'name':'no_password_recovery', 'ref':'no_password_recovery', 'key':'no_password_recovery'}),
|
||||
React.DOM.p(null, "I understand that Clipperz will not be able to recover a lost passphrase.")
|
||||
]),
|
||||
React.DOM.div({className:'checkboxBlock'}, [
|
||||
React.DOM.label({'for':'agree_terms_of_service'}, "I have read and agreed to the Terms of Service."),
|
||||
React.DOM.label({'htmlFor':'agree_terms_of_service'}, "I have read and agreed to the Terms of Service."),
|
||||
React.DOM.input({'type':'checkbox', 'name':'agree_terms_of_service', 'ref':'agree_terms_of_service', 'key':'agree_terms_of_service'}),
|
||||
React.DOM.p(null, [
|
||||
"I have read and agreed to the ",
|
||||
@@ -208,7 +210,7 @@ Clipperz.PM.UI.Components.RegistrationWizard = React.createClass({
|
||||
]);
|
||||
},
|
||||
|
||||
_render: function () {
|
||||
render: function () {
|
||||
return React.DOM.div({'className':'registrationForm'},[
|
||||
React.DOM.form({onChange: this.handleChange}, [
|
||||
React.DOM.div({'className':'steps'}, MochiKit.Base.map(this.renderStep, this.props['steps']))
|
||||
@@ -216,9 +218,9 @@ Clipperz.PM.UI.Components.RegistrationWizard = React.createClass({
|
||||
]);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
return new this.props.template({'innerComponent': this._render()});
|
||||
},
|
||||
// render: function () {
|
||||
// return new this.props.template({'innerComponent': this._render()});
|
||||
// },
|
||||
|
||||
//=========================================================================
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components.Panels');
|
||||
|
||||
Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanel = React.createClass({
|
||||
|
||||
settingsToggleHandler: function (anEvent) {
|
||||
//console.log("settingsToggleHandler");
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'toggleSettingsPanel');
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
render: function () {
|
||||
var classes = {
|
||||
'panel': true,
|
||||
'right': true,
|
||||
'open': this.props['settingsPanelStatus'] == 'OPEN'
|
||||
}
|
||||
|
||||
return React.DOM.div({key:'extraFeaturesPanel', id:'extraFeaturesPanel', className:React.addons.classSet(classes)}, [
|
||||
React.DOM.header({}, [
|
||||
React.DOM.div({className:'settingsToggle'}, [
|
||||
Clipperz.PM.UI.Components.Button({eventName:'settingsToggleButton', label:"menu", handler:this.settingsToggleHandler})
|
||||
])
|
||||
]),
|
||||
React.DOM.h2({}, "Extra features")
|
||||
]);
|
||||
/*
|
||||
<div id="extraFeaturesPanel" class="panel extraFeatures">
|
||||
|
||||
<div class="warnings">
|
||||
<ul>
|
||||
<li>Synchronize local data</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
<li>Account</li>
|
||||
<li>Subscription</li>
|
||||
</ul>
|
||||
|
||||
<ul>
|
||||
<li>Local Data</li>
|
||||
<li>OTP</li>
|
||||
</ul>
|
||||
|
||||
<div class="donation">
|
||||
<a>Make a donation</a>
|
||||
</div>
|
||||
</div>
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
193
frontend/delta/js/Clipperz/PM/UI/Components/Panels/MainPanel.js
Normal file
193
frontend/delta/js/Clipperz/PM/UI/Components/Panels/MainPanel.js
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components.Panels');
|
||||
|
||||
Clipperz.PM.UI.Components.Panels.MainPanel = React.createClass({
|
||||
|
||||
//=========================================================================
|
||||
|
||||
propTypes: {
|
||||
'messageBox': React.PropTypes.object.isRequired,
|
||||
'featureSet': React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL']).isRequired,
|
||||
'style': React.PropTypes.oneOf(Clipperz_PM_UI_availableStyles).isRequired,
|
||||
},
|
||||
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
featureSet: 'FULL'
|
||||
};
|
||||
},
|
||||
|
||||
style: function () {
|
||||
return this.props['style'];
|
||||
},
|
||||
|
||||
featureSet: function () {
|
||||
return this.props['featureSet'];
|
||||
},
|
||||
|
||||
handleMaskClick: function () {
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'maskClick');
|
||||
},
|
||||
|
||||
handleAddCardClick: function () {
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'addCardClick');
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
renderToolbarFrame: function (anInnerComponent) {
|
||||
return React.DOM.div({'className':'cardToolbarFrame'}, [
|
||||
this.renderToolbar(),
|
||||
anInnerComponent
|
||||
]);
|
||||
},
|
||||
|
||||
renderCardFrame: function (firstColumnComponents, secondColumnComponents) {
|
||||
var addCardButton = React.DOM.div({'className': 'addCardButton', 'onClick':this.handleAddCardClick}, 'add card');
|
||||
|
||||
return React.DOM.div({'key':'cardContent', 'className':'cardContent'}, [
|
||||
React.DOM.div({'className':'cardListColumn column'}, [addCardButton, firstColumnComponents]),
|
||||
React.DOM.div({'className':'cardDetail column right'}, secondColumnComponents)
|
||||
])
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
renderToolbar: function () {
|
||||
var cardToolbarProps;
|
||||
|
||||
cardToolbarProps = MochiKit.Base.merge(this.props, {
|
||||
'key': 'toolbar',
|
||||
'style': this.style(),
|
||||
'enableSidePanels': (this.props['featureSet'] != 'EXPIRED')
|
||||
});
|
||||
|
||||
return Clipperz.PM.UI.Components.CardToolbar(cardToolbarProps);
|
||||
},
|
||||
|
||||
renderExpiredPanel: function () {
|
||||
return this.featureSet() == 'EXPIRED' ? Clipperz.PM.UI.Components.ExpiredPanel(this.props) : null;
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
viewComponentProps: function () {
|
||||
var result;
|
||||
|
||||
result = this.props['selectedCard'];
|
||||
if (result) {
|
||||
result['style'] = this.props['style'];
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
renderExtraWide: function () {
|
||||
return [
|
||||
React.DOM.div({'className':'selection subpanel'}, [Clipperz.PM.UI.Components.Selections(this.props)]),
|
||||
React.DOM.div({'className':'cardContent subpanel'}, [
|
||||
this.renderToolbarFrame(
|
||||
this.renderCardFrame(
|
||||
[Clipperz.PM.UI.Components.Cards.List(this.props)],
|
||||
[
|
||||
this.renderExpiredPanel(),
|
||||
Clipperz.PM.UI.Components.Cards.View(this.viewComponentProps())
|
||||
]
|
||||
)
|
||||
)
|
||||
])
|
||||
]
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
renderWide: function () {
|
||||
return [
|
||||
this.renderToolbarFrame(
|
||||
this.renderCardFrame(
|
||||
[Clipperz.PM.UI.Components.Cards.List(this.props)],
|
||||
[
|
||||
this.renderExpiredPanel(),
|
||||
Clipperz.PM.UI.Components.Cards.View(this.viewComponentProps())
|
||||
]
|
||||
)
|
||||
)
|
||||
];
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
renderNarrow: function () {
|
||||
return this.renderCardFrame(
|
||||
this.renderToolbarFrame([
|
||||
this.renderExpiredPanel(),
|
||||
Clipperz.PM.UI.Components.Cards.List(this.props),
|
||||
]),
|
||||
[Clipperz.PM.UI.Components.Cards.View(this.viewComponentProps())]
|
||||
);
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
renderLayout: function (aLayout) {
|
||||
var result;
|
||||
|
||||
if (aLayout == 'extra-wide') {
|
||||
result = this.renderExtraWide();
|
||||
} else if (aLayout == 'wide') {
|
||||
result = this.renderWide();
|
||||
} else if (aLayout == 'narrow') {
|
||||
result = this.renderNarrow();
|
||||
} else if (aLayout == 'extra-short') {
|
||||
result = this.renderNarrow();
|
||||
} else {
|
||||
Clipperz.Base.exception.raise('UnknownType');
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
render: function () {
|
||||
//console.log("MainPanel.cards", this.props['cards']);
|
||||
var classes = {
|
||||
'panel': true,
|
||||
'left': this.props['selectionPanelStatus'] == 'OPEN',
|
||||
'right': this.props['settingsPanelStatus'] == 'OPEN',
|
||||
'open': this.props['selectionPanelStatus'] == 'OPEN' || this.props['settingsPanelStatus'] == 'OPEN'
|
||||
};
|
||||
classes[this.style()] = true;
|
||||
|
||||
return React.DOM.div({'key':'mainPanel', 'id':'mainPanel', 'className':React.addons.classSet(classes)}, [
|
||||
React.DOM.div({'className':'mask', 'onClick': this.handleMaskClick}),
|
||||
React.DOM.div({'className':'container'},
|
||||
// this.style() == 'extra-wide' ? this.renderExtraWide() : this.renderOther()
|
||||
this.renderLayout(this.style())
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components.Panels');
|
||||
|
||||
Clipperz.PM.UI.Components.Panels.SelectionPanel = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
selectionPanelStatus: React.PropTypes.oneOf(['OPEN', 'CLOSED']).isRequired
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
render: function () {
|
||||
//console.log("SelectionPanel", this.props);
|
||||
var classes = React.addons.classSet({
|
||||
'panel': true,
|
||||
'left': true,
|
||||
'open': this.props['selectionPanelStatus'] == 'OPEN'
|
||||
});
|
||||
|
||||
return React.DOM.div({'key':'selectionPanel', 'id':'selectionPanel', 'className':classes}, [
|
||||
Clipperz.PM.UI.Components.Selections(this.props),
|
||||
]);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
Clipperz.PM.UI.Components.PreferencePage = React.createClass({
|
||||
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
|
||||
propTypes: {
|
||||
// card: React.PropTypes.object.isRequired
|
||||
// checked: React.PropTypes.boolean.isRequired
|
||||
},
|
||||
|
||||
getInitialState: function () {
|
||||
// return {
|
||||
// shouldStoreDataLocally: false
|
||||
// };
|
||||
},
|
||||
|
||||
handleBackClick: function (anEvent) {
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'goBack');
|
||||
},
|
||||
|
||||
toggleShouldStoreDataLocally: function (anEvent) {
|
||||
// this.setState({shouldStoreDataLocally: !this.state['shouldStoreDataLocally']});
|
||||
Clipperz.PM.DataModel.devicePreferences.setShouldStoreDataLocally(!Clipperz.PM.DataModel.devicePreferences.shouldStoreDataLocally());
|
||||
this.setState({});
|
||||
},
|
||||
|
||||
shouldStoreDataLocally: function () {
|
||||
return Clipperz.PM.DataModel.devicePreferences.shouldStoreDataLocally();
|
||||
},
|
||||
|
||||
syncNow: function (anEvent) {
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'synchronizeLocalData');
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
render: function () {
|
||||
return React.DOM.div({className:'preferences'}, [
|
||||
React.DOM.div({className:'header'}, [
|
||||
React.DOM.div({className:'titleWrapper'}, React.DOM.div({className:'title'}, "Preferences")),
|
||||
React.DOM.div({className:'backWrapper'}, React.DOM.a({className:'button back', onClick:this.handleBackClick}, "back")),
|
||||
]),
|
||||
React.DOM.div({className:'content'}, [
|
||||
React.DOM.form(null, [
|
||||
React.DOM.div({className:'section'}, [
|
||||
React.DOM.h4(null, "Local storage"),
|
||||
React.DOM.p(null, "Store you account data locally for offline viewing"),
|
||||
new Clipperz.PM.UI.Components.Checkbox({'id':'shouldStoreLocally_checkbox', 'checked':this.shouldStoreDataLocally(), 'eventHandler':this.toggleShouldStoreDataLocally}),
|
||||
this.shouldStoreDataLocally() ? React.DOM.div({className:'syncInfo'}, [
|
||||
// React.DOM.h5(null, "data were never synchronized before"),
|
||||
React.DOM.a({className:'button', onClick:this.syncNow}, "Sync now")
|
||||
]) : null
|
||||
])
|
||||
])
|
||||
]),
|
||||
React.DOM.div({className:'footer'}, [
|
||||
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
57
frontend/delta/js/Clipperz/PM/UI/Components/Selections.js
Normal file
57
frontend/delta/js/Clipperz/PM/UI/Components/Selections.js
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components');
|
||||
|
||||
Clipperz.PM.UI.Components.Selections = React.createClass({
|
||||
|
||||
//=========================================================================
|
||||
|
||||
selectAll: function (anEvent) {
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectAllCards');
|
||||
},
|
||||
|
||||
selectRecent: function (anEvent) {
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectRecentCards');
|
||||
},
|
||||
|
||||
render: function () {
|
||||
//console.log("Selections", this.props);
|
||||
return React.DOM.div({'key':'selections', 'id':'selections'}, [
|
||||
React.DOM.ul({'className':'defaultSet'}, [
|
||||
React.DOM.li({'className':'allCards', onClick: this.selectAll}, "All"),
|
||||
React.DOM.li({'className':'recentCards', onClick: this.selectRecent}, "Recent")
|
||||
]),
|
||||
React.DOM.div({'className':'search'}, [
|
||||
React.DOM.form({'className':'searchForm'}, [
|
||||
React.DOM.label({'htmlFor':'searchValue'}, 'search'),
|
||||
React.DOM.input({'type':'text', 'id':'searchValue', 'name':'search'})
|
||||
])
|
||||
]),
|
||||
React.DOM.ul({'className':'tagList'}, MochiKit.Base.map(function (aTag) { return Clipperz.PM.UI.Components.TagIndexItem({'label':aTag}); }, this.props['tags'] ? this.props['tags'] : []))
|
||||
]);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
45
frontend/delta/js/Clipperz/PM/UI/Components/TagIndexItem.js
Normal file
45
frontend/delta/js/Clipperz/PM/UI/Components/TagIndexItem.js
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
|
||||
Copyright 2008-2013 Clipperz Srl
|
||||
|
||||
This file is part of Clipperz, the online password manager.
|
||||
For further information about its features and functionalities please
|
||||
refer to http://www.clipperz.com.
|
||||
|
||||
* Clipperz is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* Clipperz is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
Clipperz.Base.module('Clipperz.PM.UI.Components');
|
||||
|
||||
Clipperz.PM.UI.Components.TagIndexItem = React.createClass({
|
||||
|
||||
//=========================================================================
|
||||
|
||||
propTypes: {
|
||||
'label': React.PropTypes.string.isRequired,
|
||||
},
|
||||
|
||||
handleClick: function (anEvent) {
|
||||
//console.log("TAG INDEX ITEM - handle click TAG", anEvent.target.dataset.tag);
|
||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'tagSelected', anEvent.target.dataset.tag);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
return React.DOM.li({onClick: this.handleClick, 'data-tag':this.props['label']}, this.props['label']);
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
});
|
||||
@@ -23,17 +23,17 @@ refer to http://www.clipperz.com.
|
||||
|
||||
Clipperz.Base.module('Clipperz.PM.UI');
|
||||
|
||||
Clipperz.PM.UI.DirectLoginRunner = function(args) {
|
||||
Clipperz.PM.UI.DirectLoginController = function(args) {
|
||||
this._directLogin = args['directLogin'] || Clipperz.Base.exception.raise('MandatoryParameter');
|
||||
this._target = Clipperz.PM.Crypto.randomKey();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
MochiKit.Base.update(Clipperz.PM.UI.DirectLoginRunner.prototype, {
|
||||
MochiKit.Base.update(Clipperz.PM.UI.DirectLoginController.prototype, {
|
||||
|
||||
'toString': function() {
|
||||
return "Clipperz.PM.UI.DirectLoginRunner";
|
||||
return "Clipperz.PM.UI.DirectLoginController";
|
||||
},
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -237,19 +237,19 @@ MochiKit.Base.update(Clipperz.PM.UI.DirectLoginRunner.prototype, {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
Clipperz.PM.UI.DirectLoginRunner.openDirectLogin = function (aDirectLogin) {
|
||||
Clipperz.PM.UI.DirectLoginController.openDirectLogin = function (aDirectLogin) {
|
||||
var runner;
|
||||
|
||||
runner = new Clipperz.PM.UI.DirectLoginRunner({directLogin:aDirectLogin});
|
||||
runner = new Clipperz.PM.UI.DirectLoginController({directLogin:aDirectLogin});
|
||||
return runner.run();
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
Clipperz.PM.UI.DirectLoginRunner.testDirectLogin = function (aDirectLogin) {
|
||||
Clipperz.PM.UI.DirectLoginController.testDirectLogin = function (aDirectLogin) {
|
||||
var runner;
|
||||
|
||||
runner = new Clipperz.PM.UI.DirectLoginRunner({directLogin:aDirectLogin});
|
||||
runner = new Clipperz.PM.UI.DirectLoginController({directLogin:aDirectLogin});
|
||||
return runner.test();
|
||||
};
|
||||
|
||||
|
||||
@@ -21,31 +21,65 @@ refer to http://www.clipperz.com.
|
||||
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
Clipperz.Base.module('Clipperz.PM.UI');
|
||||
|
||||
Clipperz.PM.UI.MainController = function() {
|
||||
var pages;
|
||||
var genericPageProperties;
|
||||
|
||||
// this._proxy = null;
|
||||
this._mediaQueryStyle = "narrow";
|
||||
this._user = null;
|
||||
this._filter = '';
|
||||
|
||||
// this._currentPage = 'loadingPage';
|
||||
this._filter = {'type':'ALL'};
|
||||
|
||||
this._isSelectionPanelOpen = false;
|
||||
this._isSettingsPanelOpen = false;
|
||||
|
||||
this._pageStack = ['loadingPage'];
|
||||
this._overlay = new Clipperz.PM.UI.Components.Overlay();
|
||||
pages = {
|
||||
'loginPage': new Clipperz.PM.UI.Components.LoginForm(),
|
||||
'registrationPage': new Clipperz.PM.UI.Components.RegistrationWizard(),
|
||||
'cardListPage': new Clipperz.PM.UI.Components.CardList(),
|
||||
'cardDetailPage': new Clipperz.PM.UI.Components.CardDetail({card: {}}),
|
||||
'preferencePage': new Clipperz.PM.UI.Components.PreferencePage(),
|
||||
'errorPage': new Clipperz.PM.UI.Components.ErrorPage({message:''})
|
||||
};
|
||||
|
||||
MochiKit.Base.map(function (anId) {React.renderComponent(pages[anId], MochiKit.DOM.getElement(anId))}, MochiKit.Base.keys(pages));
|
||||
this._pages = pages;
|
||||
this.registerForNotificationCenterEvents();
|
||||
this._isTouchDevice = ('ontouchstart' in window || 'onmsgesturechange' in window);
|
||||
this._isDesktop = window.screenX != 0 && !this._isTouchDevice;
|
||||
this._hasKeyboard = this._isDesktop;
|
||||
|
||||
this._closeMaskAction = null;
|
||||
|
||||
this._pages = {};
|
||||
this.renderPages([
|
||||
'loginPage',
|
||||
'registrationPage',
|
||||
'mainPage',
|
||||
'cardDetailPage',
|
||||
'errorPage',
|
||||
]);
|
||||
|
||||
this.registerForNotificationCenterEvents([
|
||||
'doLogin',
|
||||
'registerNewUser',
|
||||
'showRegistrationForm',
|
||||
'goBack',
|
||||
|
||||
'toggleSelectionPanel',
|
||||
'toggleSettingsPanel',
|
||||
|
||||
'matchMediaQuery',
|
||||
'unmatchMediaQuery',
|
||||
|
||||
'selectAllCards',
|
||||
'selectRecentCards',
|
||||
'tagSelected',
|
||||
|
||||
'cardSelected',
|
||||
|
||||
'addCardClick',
|
||||
'deleteCard',
|
||||
'archiveCard',
|
||||
'editCard',
|
||||
|
||||
'goBackToMainPage',
|
||||
'maskClick',
|
||||
]);
|
||||
|
||||
MochiKit.Signal.connect(MochiKit.DOM.currentDocument(), 'onselectionchange', this, 'selectionChangeHandler');
|
||||
|
||||
return this;
|
||||
@@ -125,26 +159,30 @@ console.log("THE BROWSER IS OFFLINE");
|
||||
|
||||
//=========================================================================
|
||||
|
||||
registerForNotificationCenterEvents: function () {
|
||||
var events = [
|
||||
'doLogin',
|
||||
'registerNewUser',
|
||||
'showRegistrationForm',
|
||||
'goBack',
|
||||
'showRecord',
|
||||
'searchCards',
|
||||
'showPreferences',
|
||||
'runDirectLogin',
|
||||
'synchronizeLocalData'
|
||||
];
|
||||
var self = this;
|
||||
capitaliseFirstLetter: function (aValue) {
|
||||
return aValue.charAt(0).toUpperCase() + aValue.slice(1);
|
||||
},
|
||||
|
||||
renderPages: function (pages) {
|
||||
var self = this;
|
||||
MochiKit.Iter.forEach(pages, function (aPageName) {
|
||||
//console.log("RENDERING", aPageName);
|
||||
self._pages[aPageName] = React.renderComponent(
|
||||
Clipperz.PM.UI.Components.Pages[self.capitaliseFirstLetter(aPageName)](self.pageProperties(aPageName)),
|
||||
MochiKit.DOM.getElement(aPageName)
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
MochiKit.Base.map(function (anEvent) {
|
||||
MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, anEvent, MochiKit.Base.method(self, anEvent));
|
||||
}, events);
|
||||
registerForNotificationCenterEvents: function (events) {
|
||||
var self = this;
|
||||
|
||||
MochiKit.Iter.forEach(events, function (anEvent) {
|
||||
MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, anEvent, MochiKit.Base.method(self, anEvent + '_handler'));
|
||||
});
|
||||
|
||||
// MochiKit.Signal.connect(window, 'onpopstate', MochiKit.Base.method(this, 'historyGoBack'));
|
||||
MochiKit.Signal.connect(window, 'onbeforeunload', MochiKit.Base.method(this, 'shouldExitApp'));
|
||||
// MochiKit.Signal.connect(window, 'onbeforeunload', MochiKit.Base.method(this, 'shouldExitApp'));
|
||||
},
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -198,11 +236,13 @@ console.log("THE BROWSER IS OFFLINE");
|
||||
this.pages()['loginPage'].setProps({'mode':this.loginMode(), 'isNewUserRegistrationAvailable':canRegisterNewUsers});
|
||||
|
||||
if (shouldShowRegistrationForm) {
|
||||
this.showRegistrationForm();
|
||||
this.showRegistrationForm_handler();
|
||||
} else {
|
||||
this.showLoginForm();
|
||||
}
|
||||
this.overlay().done("", 0.5);
|
||||
|
||||
// this.overlay().done("", 0.5);
|
||||
this.overlay().hide();
|
||||
},
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -216,7 +256,7 @@ console.log("THE BROWSER IS OFFLINE");
|
||||
MochiKit.Async.callLater(0.5, MochiKit.Base.method(loginFormPage, 'setInitialFocus'));
|
||||
},
|
||||
|
||||
showRegistrationForm: function () {
|
||||
showRegistrationForm_handler: function () {
|
||||
var currentPage;
|
||||
var registrationPage;
|
||||
|
||||
@@ -230,7 +270,12 @@ console.log("THE BROWSER IS OFFLINE");
|
||||
|
||||
//=========================================================================
|
||||
|
||||
doLogin: function (event) {
|
||||
doLogin_handler: function (event) {
|
||||
return this.doLogin(event);
|
||||
},
|
||||
|
||||
doLogin: function (someCredentials) {
|
||||
var deferredResult;
|
||||
var credentials;
|
||||
var getPassphraseDelegate;
|
||||
var user;
|
||||
@@ -240,10 +285,10 @@ console.log("THE BROWSER IS OFFLINE");
|
||||
this.overlay().show("logging in");
|
||||
this.pages()['loginPage'].setProps({disabled:true});
|
||||
|
||||
if ('pin' in event) {
|
||||
credentials = Clipperz.PM.PIN.credentialsWithPIN(event['pin']);
|
||||
if ('pin' in someCredentials) {
|
||||
credentials = Clipperz.PM.PIN.credentialsWithPIN(someCredentials['pin']);
|
||||
} else {
|
||||
credentials = event;
|
||||
credentials = someCredentials;
|
||||
}
|
||||
getPassphraseDelegate = MochiKit.Base.partial(MochiKit.Async.succeed, credentials.passphrase);
|
||||
user = new Clipperz.PM.DataModel.User({'username':credentials.username, 'getPassphraseFunction':getPassphraseDelegate});
|
||||
@@ -254,18 +299,16 @@ console.log("THE BROWSER IS OFFLINE");
|
||||
deferredResult.addMethod(user, 'login');
|
||||
deferredResult.addMethod(Clipperz.PM.PIN, 'resetFailedAttemptCount');
|
||||
deferredResult.addMethod(this, 'setUser', user);
|
||||
|
||||
// deferredResult.addMethod(this, 'setupApplication');
|
||||
deferredResult.addMethod(this, 'runApplication');
|
||||
deferredResult.addMethod(this.overlay(), 'done', "", 1);
|
||||
deferredResult.addErrback(MochiKit.Base.method(this, 'genericErrorHandler', event));
|
||||
deferredResult.addErrback(MochiKit.Base.method(this, 'genericErrorHandler', someCredentials));
|
||||
deferredResult.addErrback(MochiKit.Base.bind(function (anEvent, anError) {
|
||||
if (anError['isPermanent'] != true) {
|
||||
this.pages()['loginPage'].setProps({disabled:false, 'mode':this.loginMode()});
|
||||
this.pages()['loginPage'].setInitialFocus();
|
||||
}
|
||||
return anError;
|
||||
}, this, event))
|
||||
}, this, someCredentials))
|
||||
deferredResult.callback();
|
||||
|
||||
return deferredResult;
|
||||
@@ -273,19 +316,19 @@ console.log("THE BROWSER IS OFFLINE");
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
registerNewUser: function (credentials) {
|
||||
registerNewUser_handler: function (credentials) {
|
||||
var deferredResult;
|
||||
|
||||
this.overlay().show("creating user");
|
||||
|
||||
this.pages()['registrationPage'].setProps({disabled:true});
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.registerNewUser', {trace:false});
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.registerNewUser', {trace:true});
|
||||
deferredResult.addCallback(Clipperz.PM.DataModel.User.registerNewAccount,
|
||||
credentials['username'],
|
||||
MochiKit.Base.partial(MochiKit.Async.succeed, credentials['passphrase'])
|
||||
);
|
||||
deferredResult.addMethod(this, 'doLogin', credentials);
|
||||
deferredResult.addErrback(MochiKit.Base.method(this, 'genericErrorHandler', event));
|
||||
deferredResult.addErrback(MochiKit.Base.method(this, 'genericErrorHandler', credentials));
|
||||
deferredResult.addErrback(MochiKit.Base.bind(function (anError) {
|
||||
if (anError['isPermanent'] != true) {
|
||||
this.pages()['registrationPage'].setProps({disabled:false});
|
||||
@@ -307,109 +350,222 @@ console.log("THE BROWSER IS OFFLINE");
|
||||
},
|
||||
|
||||
setUser: function (aUser) {
|
||||
console.log("SET USER", aUser);
|
||||
this._user = aUser;
|
||||
return this._user;
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
|
||||
allCardInfo: function () {
|
||||
var deferredResult;
|
||||
var cardInfo;
|
||||
|
||||
cardInfo = {
|
||||
'_rowObject': MochiKit.Async.succeed,
|
||||
'_reference': MochiKit.Base.methodcaller('reference'),
|
||||
'_searchableContent': MochiKit.Base.methodcaller('searchableContent'),
|
||||
'label': MochiKit.Base.methodcaller('label'),
|
||||
'favicon': MochiKit.Base.methodcaller('favicon')
|
||||
};
|
||||
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.allCardInfo', {trace:false});
|
||||
deferredResult.addMethod(this.user(), 'getRecords');
|
||||
deferredResult.addCallback(MochiKit.Base.map, Clipperz.Async.collectResults("CardList.value - collectResults", cardInfo, {trace:false}));
|
||||
deferredResult.addCallback(Clipperz.Async.collectAll);
|
||||
deferredResult.callback();
|
||||
|
||||
return deferredResult;
|
||||
},
|
||||
|
||||
filterCards: function (someCardInfo) {
|
||||
var filter;
|
||||
var filterRegExp;
|
||||
var result;
|
||||
|
||||
filter = this.filter().replace(/[^A-Za-z0-9]/g, "\\$&");
|
||||
filterRegExp = new RegExp(filter, "i");
|
||||
result = MochiKit.Base.filter(function (aCardInfo) { return filterRegExp.test(aCardInfo['_searchableContent'])}, someCardInfo);
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
sortCards: function (someCardInfo) {
|
||||
return someCardInfo.sort(Clipperz.Base.caseInsensitiveKeyComparator('label'));
|
||||
},
|
||||
|
||||
showRecordList: function () {
|
||||
var deferredResult;
|
||||
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.showRecordList', {trace:false});
|
||||
deferredResult.addMethod(this, 'allCardInfo');
|
||||
deferredResult.addMethod(this, 'filterCards');
|
||||
deferredResult.addMethod(this, 'sortCards');
|
||||
deferredResult.addCallback(MochiKit.Base.bind(function (someRecordInfo) {
|
||||
this.pages()['cardListPage'].setProps({cardList: someRecordInfo});
|
||||
}, this));
|
||||
deferredResult.callback();
|
||||
|
||||
return deferredResult;
|
||||
},
|
||||
|
||||
filter: function () {
|
||||
return this._filter;
|
||||
},
|
||||
|
||||
setFilter: function (aValue) {
|
||||
this._filter = aValue;
|
||||
setFilter: function (aType, aValue) {
|
||||
this._filter = {'type':aType, 'value':aValue};
|
||||
return this._filter;
|
||||
},
|
||||
|
||||
searchCards: function (someParameters) {
|
||||
//console.log("SEARCH CARDS", someParameters);
|
||||
this.setFilter(someParameters);
|
||||
this.showRecordList();
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
collectFieldInfo: function (aField) {
|
||||
var deferredResult;
|
||||
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.collectFieldInfo', {trace:false});
|
||||
deferredResult.addMethod(aField, 'reference');
|
||||
deferredResult.setValue('_reference');
|
||||
deferredResult.addMethod(aField, 'label');
|
||||
deferredResult.setValue('label');
|
||||
deferredResult.addMethod(aField, 'value');
|
||||
deferredResult.setValue('value');
|
||||
deferredResult.addMethod(aField, 'actionType');
|
||||
deferredResult.setValue('actionType');
|
||||
deferredResult.addMethod(aField, 'isHidden');
|
||||
deferredResult.setValue('isHidden');
|
||||
deferredResult.values();
|
||||
|
||||
deferredResult.callback();
|
||||
|
||||
return deferredResult;
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
collectDirectLoginInfo: function (aDirectLogin) {
|
||||
var deferredResult;
|
||||
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.collectDirectLoginInfo', {trace:false});
|
||||
deferredResult.addMethod(aDirectLogin, 'reference');
|
||||
deferredResult.setValue('_reference');
|
||||
deferredResult.addMethod(aDirectLogin, 'label');
|
||||
deferredResult.setValue('label');
|
||||
deferredResult.addMethod(aDirectLogin, 'favicon');
|
||||
deferredResult.setValue('favicon');
|
||||
deferredResult.values();
|
||||
|
||||
runApplication: function () {
|
||||
MochiKit.Signal.connect(window, 'onpopstate', MochiKit.Base.method(this, 'historyGoBack'));
|
||||
/// TODO: remove this TEST HACK
|
||||
this.moveInPage(this.currentPage(), 'cardListPage');
|
||||
return this.showRecordList();
|
||||
deferredResult.callback();
|
||||
|
||||
return deferredResult;
|
||||
},
|
||||
|
||||
collectRecordInfo: function (aRecord) {
|
||||
var deferredResult;
|
||||
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.collectRecordInfo', {trace:false});
|
||||
deferredResult.addMethod(aRecord, 'reference');
|
||||
deferredResult.setValue('_reference');
|
||||
deferredResult.addMethod(aRecord, 'label');
|
||||
deferredResult.setValue('label');
|
||||
deferredResult.addMethod(aRecord, 'notes');
|
||||
deferredResult.setValue('notes');
|
||||
deferredResult.addMethod(aRecord, 'tags');
|
||||
deferredResult.setValue('tags');
|
||||
|
||||
// this.moveInPage(this.currentPage(), 'preferencePage');
|
||||
deferredResult.addMethod(aRecord, 'fields');
|
||||
deferredResult.addCallback(MochiKit.Base.values);
|
||||
deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.method(this, 'collectFieldInfo'));
|
||||
deferredResult.addCallback(Clipperz.Async.collectAll);
|
||||
deferredResult.setValue('fields');
|
||||
|
||||
deferredResult.addMethod(aRecord, 'directLogins');
|
||||
deferredResult.addCallback(MochiKit.Base.values);
|
||||
deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.method(this, 'collectDirectLoginInfo'));
|
||||
deferredResult.addCallback(Clipperz.Async.collectAll);
|
||||
deferredResult.setValue('directLogins');
|
||||
|
||||
deferredResult.values();
|
||||
|
||||
deferredResult.callback();
|
||||
|
||||
return deferredResult;
|
||||
},
|
||||
|
||||
showRecord: function (aRecordReference) {
|
||||
//console.log("Show Record", aRecordReference);
|
||||
var deferredResult;
|
||||
updateSelectedCard: function (someInfo) {
|
||||
var deferredResult;
|
||||
|
||||
this.pages()['cardListPage'].setProps({selectedCard:aRecordReference});
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.runApplication', {trace:false});
|
||||
deferredResult.addMethod(this.user(), 'getRecord', aRecordReference);
|
||||
deferredResult.addMethodcaller('content');
|
||||
deferredResult.addCallback(MochiKit.Base.bind(function (aCard) {
|
||||
//console.log("CARD DETAILS", aCard);
|
||||
this.pages()['cardDetailPage'].setProps({card: aCard});
|
||||
this.pages()['cardListPage'].setProps({selectedCard: null});
|
||||
if (someInfo == null) {
|
||||
this.setPageProperties('mainPage', 'selectedCard', {});
|
||||
deferredResult = MochiKit.Async.succeed();
|
||||
} else {
|
||||
this.setPageProperties('mainPage', 'selectedCard', {'loading':true, 'label':someInfo['label'], '_reference':someInfo['reference']});
|
||||
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.updateSelectedCard', {trace:false});
|
||||
deferredResult.addMethod(this.user(), 'getRecord', someInfo['reference']);
|
||||
deferredResult.addMethod(this, 'collectRecordInfo');
|
||||
|
||||
//console.log("MEDIA QUERY STYLE", this.mediaQueryStyle());
|
||||
deferredResult.addMethod(this, 'setPageProperties', 'mainPage', 'selectedCard');
|
||||
if (this.mediaQueryStyle() == 'narrow') {
|
||||
deferredResult.addMethod(this, 'setPageProperties', 'cardDetailPage', 'selectedCard');
|
||||
deferredResult.addMethod(this, 'moveInPage', this.currentPage(), 'cardDetailPage');
|
||||
// deferredResult.addCallback(function (aValue) { console.log("SHOULD SLIDE IN PAGE DETAIL"); return aValue; });
|
||||
//console.log("SHOULD SLIDE IN PAGE DETAIL");
|
||||
}
|
||||
|
||||
MochiKit.Async.callLater(0.1, MochiKit.Base.method(deferredResult, 'callback'));
|
||||
}
|
||||
|
||||
return deferredResult;
|
||||
},
|
||||
|
||||
//............................................................................
|
||||
|
||||
regExpFilterGenerator: function (aRegExp, aSearchField) {
|
||||
var searchField = aSearchField ? aSearchField : Clipperz.PM.DataModel.Record.defaultSearchField;
|
||||
|
||||
return function (aCardInfo) {
|
||||
aRegExp.lastIndex = 0;
|
||||
return aRegExp.test(aCardInfo[searchField]);
|
||||
}
|
||||
},
|
||||
|
||||
selectedCardReference: function () {
|
||||
return this.pages()['mainPage'].props &&
|
||||
this.pages()['mainPage'].props['selectedCard'] &&
|
||||
this.pages()['mainPage'].props['selectedCard'] &&
|
||||
this.pages()['mainPage'].props['selectedCard']['_reference']
|
||||
? this.pages()['mainPage'].props['selectedCard']['_reference']
|
||||
: '';
|
||||
},
|
||||
|
||||
isSelectedCardStillVisible: function (someCards) {
|
||||
var result;
|
||||
var reference;
|
||||
|
||||
reference = this.selectedCardReference();
|
||||
result = MochiKit.Iter.some(someCards, function (aCardInfo) {
|
||||
return aCardInfo['_reference'] == reference;
|
||||
});
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
updateSelectedCards: function (shouldIncludeArchivedCards, aFilter) {
|
||||
var deferredResult;
|
||||
var sortCriteria;
|
||||
|
||||
sortCriteria = Clipperz.Base.caseInsensitiveKeyComparator('label');
|
||||
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.setFilter', {trace:false});
|
||||
deferredResult.addMethod(this.user(), 'getRecordsInfo', Clipperz.PM.DataModel.Record.defaultCardInfo, shouldIncludeArchivedCards);
|
||||
|
||||
if (aFilter['type'] == 'ALL') {
|
||||
deferredResult.addMethodcaller('sort', sortCriteria);
|
||||
} else if (aFilter['type'] == 'RECENT') {
|
||||
deferredResult.addMethodcaller('sort', Clipperz.Base.reverseComparator(MochiKit.Base.keyComparator('accessDate')));
|
||||
deferredResult.addCallback(function (someCards) { return someCards.slice(0, 9)});
|
||||
} else if (aFilter['type'] == 'SEARCH') {
|
||||
deferredResult.addCallback(MochiKit.Base.filter, this.regExpFilterGenerator(Clipperz.PM.DataModel.Record.regExpForSearch(aFilter['value'])));
|
||||
deferredResult.addMethodcaller('sort', sortCriteria);
|
||||
} else if (aFilter['type'] == 'TAG') {
|
||||
deferredResult.addCallback(MochiKit.Base.filter, this.regExpFilterGenerator(Clipperz.PM.DataModel.Record.regExpForTag(aFilter['value'])));
|
||||
deferredResult.addMethodcaller('sort', sortCriteria);
|
||||
}
|
||||
|
||||
deferredResult.addMethod(this, 'setPageProperties', 'mainPage', 'cards');
|
||||
deferredResult.addCallback(MochiKit.Base.bind(function (someCards) {
|
||||
if (!this.isSelectedCardStillVisible(someCards)) {
|
||||
this.updateSelectedCard(null);
|
||||
};
|
||||
}, this));
|
||||
deferredResult.addMethod(this, 'moveInPage', this.currentPage(), 'cardDetailPage', true);
|
||||
deferredResult.addMethod(this, 'setPageProperties', 'mainPage', 'filter', this.filter());
|
||||
|
||||
deferredResult.callback();
|
||||
|
||||
return deferredResult;
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
setPageProperties: function (aPageName, aKey, aValue) {
|
||||
var props = {};
|
||||
props[aKey] = aValue;
|
||||
this.pages()[aPageName].setProps(props);
|
||||
|
||||
return aValue;
|
||||
},
|
||||
|
||||
renderAccountData: function () {
|
||||
var deferredResult;
|
||||
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.renderAccountData', {trace:false});
|
||||
deferredResult.addMethod(this, 'setFilter', 'ALL');
|
||||
deferredResult.addMethod(this, 'updateSelectedCards', false);
|
||||
|
||||
deferredResult.addMethod(this.user(), 'getTags');
|
||||
deferredResult.addMethodcaller('sort', Clipperz.Base.caseInsensitiveCompare);
|
||||
deferredResult.addMethod(this, 'setPageProperties', 'mainPage', 'tags');
|
||||
deferredResult.callback();
|
||||
|
||||
return deferredResult;
|
||||
},
|
||||
|
||||
runDirectLogin: function (someParameters) {
|
||||
//=========================================================================
|
||||
|
||||
runApplication: function (anUser) {
|
||||
this.moveInPage(this.currentPage(), 'mainPage');
|
||||
return this.renderAccountData();
|
||||
},
|
||||
/*
|
||||
runDirectLogin_handler: function (someParameters) {
|
||||
//console.log("RUN DIRECT LOGIN", someParameters);
|
||||
var deferredResult;
|
||||
|
||||
@@ -427,10 +583,18 @@ console.log("THE BROWSER IS OFFLINE");
|
||||
anEvent.preventDefault();
|
||||
anEvent.stopPropagation();
|
||||
},
|
||||
|
||||
*/
|
||||
//=========================================================================
|
||||
|
||||
showPreferences: function (anEvent) {
|
||||
/*
|
||||
searchCards_handler: function (someParameters) {
|
||||
//console.log("SEARCH CARDS", someParameters);
|
||||
this.setFilter(someParameters);
|
||||
this.renderAccountData();
|
||||
},
|
||||
*/
|
||||
//=========================================================================
|
||||
/*
|
||||
showPreferences_handler: function (anEvent) {
|
||||
var deferredResult;
|
||||
|
||||
this.pages()['preferencePage'].setProps({});
|
||||
@@ -440,7 +604,7 @@ console.log("THE BROWSER IS OFFLINE");
|
||||
|
||||
return deferredResult;
|
||||
},
|
||||
|
||||
*/
|
||||
//=========================================================================
|
||||
|
||||
genericErrorHandler: function (anEvent, anError) {
|
||||
@@ -471,39 +635,35 @@ console.log("THE BROWSER IS OFFLINE");
|
||||
|
||||
slidePage: function (fromPage, toPage, direction) {
|
||||
var fromPosition;
|
||||
var toPosition;
|
||||
var toPosition;
|
||||
var itemToTransition;
|
||||
|
||||
if (direction == "LEFT") {
|
||||
fromPosition = 'right';
|
||||
toPosition = 'left'
|
||||
toPosition = 'left';
|
||||
itemToTransition = toPage;
|
||||
} else {
|
||||
fromPosition = 'left';
|
||||
toPosition = 'right'
|
||||
toPosition = 'right';
|
||||
itemToTransition = fromPage;
|
||||
}
|
||||
|
||||
MochiKit.DOM.addElementClass(fromPage, toPosition + ' transition');
|
||||
MochiKit.DOM.addElementClass(itemToTransition, 'transition');
|
||||
|
||||
MochiKit.DOM.addElementClass(toPage, fromPosition);
|
||||
MochiKit.DOM.removeElementClass(toPage, toPosition);
|
||||
MochiKit.DOM.addElementClass(toPage, 'transition');
|
||||
MochiKit.Async.callLater(0.1, function () {
|
||||
MochiKit.Async.callLater(0, function () {
|
||||
MochiKit.DOM.addElementClass(fromPage, toPosition);
|
||||
MochiKit.DOM.removeElementClass(toPage, fromPosition);
|
||||
})
|
||||
|
||||
MochiKit.Async.callLater(0.5, function () {
|
||||
MochiKit.DOM.removeElementClass(fromPage, 'transition');
|
||||
MochiKit.DOM.removeElementClass(toPage, 'transition');
|
||||
MochiKit.DOM.removeElementClass(itemToTransition, 'transition');
|
||||
})
|
||||
},
|
||||
|
||||
rotateInPage: function (fromPage, toPage) {
|
||||
// Broken! :(
|
||||
MochiKit.DOM.addElementClass(MochiKit.DOM.getElement('mainDiv'), 'show-right');
|
||||
},
|
||||
|
||||
//.........................................................................
|
||||
|
||||
goBack: function () {
|
||||
goBack_handler: function () {
|
||||
var fromPage;
|
||||
var toPage;
|
||||
|
||||
@@ -525,6 +685,7 @@ console.log("THE BROWSER IS OFFLINE");
|
||||
|
||||
setCurrentPage: function (aPage) {
|
||||
this.pageStack().unshift(aPage);
|
||||
this.refreshCurrentPage();
|
||||
},
|
||||
|
||||
moveInPage: function (fromPage, toPage, addToHistory) {
|
||||
@@ -552,12 +713,108 @@ console.log("THE BROWSER IS OFFLINE");
|
||||
this.setCurrentPage(toPage);
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
synchronizeLocalData: function (anEvent) {
|
||||
messageBoxContent: function () {
|
||||
var message;
|
||||
var level;
|
||||
|
||||
message = "";
|
||||
level = 'HIDE';
|
||||
|
||||
//console.log("messageBox - this.user()", this.user());
|
||||
if (this.user() != null && this.user().accountInfo() != null && this.user().accountInfo().featureSet() == 'EXPIRED') {
|
||||
message = "Exprired subscription";
|
||||
level = 'ERROR';
|
||||
}
|
||||
|
||||
return {
|
||||
'message': message,
|
||||
'level': level
|
||||
};
|
||||
},
|
||||
|
||||
userAccountInfo: function () {
|
||||
var result;
|
||||
|
||||
result = {};
|
||||
|
||||
if (this.user() != null) {
|
||||
var usefulFields = [
|
||||
'currentSubscriptionType',
|
||||
'expirationDate',
|
||||
'featureSet',
|
||||
'isExpired',
|
||||
'isExpiring',
|
||||
'paymentVerificationPending'
|
||||
];
|
||||
|
||||
var attributes = this.user().accountInfo()._attributes;
|
||||
MochiKit.Iter.forEach(usefulFields, function (aFieldName) {
|
||||
result[aFieldName] = attributes[aFieldName];
|
||||
})
|
||||
};
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
genericPageProperties: function () {
|
||||
return {
|
||||
'style': this.mediaQueryStyle(),
|
||||
'isTouchDevice': this.isTouchDevice(),
|
||||
'isDesktop': this.isDesktop(),
|
||||
'hasKeyboard': this.hasKeyboard()
|
||||
};
|
||||
},
|
||||
|
||||
pageProperties: function (aPageName) {
|
||||
var result;
|
||||
var extraProperties = null;
|
||||
|
||||
result = this.genericPageProperties();
|
||||
|
||||
if (aPageName == 'loginPage') {
|
||||
extraProperties = {
|
||||
'mode': 'CREDENTIALS',
|
||||
'isNewUserRegistrationAvailable': true,
|
||||
'disabled': false,
|
||||
};
|
||||
} else if (aPageName == 'registrationPage') {
|
||||
} else if (aPageName == 'mainPage') {
|
||||
extraProperties = {
|
||||
'messageBox': this.messageBoxContent(),
|
||||
'accountStatus': this.userAccountInfo(),
|
||||
'selectionPanelStatus': this.isSelectionPanelOpen() ? 'OPEN' : 'CLOSED',
|
||||
'settingsPanelStatus': this.isSettingsPanelOpen() ? 'OPEN' : 'CLOSED',
|
||||
// 'cards': …,
|
||||
// 'tags': …,
|
||||
// 'selectedCard': …,
|
||||
};
|
||||
} else if (aPageName == 'errorPage') {
|
||||
extraProperties = {
|
||||
'message': ''
|
||||
};
|
||||
}
|
||||
|
||||
if (extraProperties != null) {
|
||||
result = MochiKit.Base.update(result, extraProperties);
|
||||
}
|
||||
//console.log("MainController.pageProperties", result);
|
||||
return result;
|
||||
},
|
||||
|
||||
refreshCurrentPage: function () {
|
||||
if (this.pages()[this.currentPage()] != null) {
|
||||
this.pages()[this.currentPage()].setProps(this.pageProperties(this.currentPage()));
|
||||
}
|
||||
},
|
||||
|
||||
//=========================================================================
|
||||
/*
|
||||
synchronizeLocalData_handler: function (anEvent) {
|
||||
var deferredResult;
|
||||
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.synchronizeLocalData', {trace:true});
|
||||
deferredResult = new Clipperz.Async.Deferred('MainController.synchronizeLocalData', {trace:false});
|
||||
// deferredResult.addMethod(this.proxy(), 'message', 'downloadAccountData', {});
|
||||
deferredResult.addMethod(this.user().connection(), 'message', 'downloadAccountData', {});
|
||||
deferredResult.addCallback(function (aResult) {
|
||||
@@ -570,8 +827,126 @@ console.log("THE BROWSER IS OFFLINE");
|
||||
|
||||
return deferredResult;
|
||||
},
|
||||
|
||||
*/
|
||||
|
||||
//=========================================================================
|
||||
|
||||
resetPanels: function () {
|
||||
this._isSelectionPanelOpen = false;
|
||||
this._isSettingsPanelOpen = false;
|
||||
},
|
||||
|
||||
isSelectionPanelOpen: function () {
|
||||
return this._isSelectionPanelOpen;
|
||||
},
|
||||
|
||||
|
||||
toggleSelectionPanel_handler: function (anEvent) {
|
||||
this._isSelectionPanelOpen = !this._isSelectionPanelOpen;
|
||||
this.setCloseMaskAction(MochiKit.Base.method(this, 'toggleSelectionPanel_handler'));
|
||||
this.refreshCurrentPage();
|
||||
},
|
||||
|
||||
|
||||
isSettingsPanelOpen: function () {
|
||||
return this._isSettingsPanelOpen;
|
||||
},
|
||||
|
||||
toggleSettingsPanel_handler: function (anEvent) {
|
||||
this._isSettingsPanelOpen = !this._isSettingsPanelOpen;
|
||||
this.setCloseMaskAction(MochiKit.Base.method(this, 'toggleSettingsPanel_handler'));
|
||||
this.refreshCurrentPage();
|
||||
},
|
||||
|
||||
cardSelected_handler: function (aReference) {
|
||||
this.updateSelectedCard(aReference);
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
addCardClick_handler: function () {
|
||||
console.log("ADD CARD CLICK");
|
||||
},
|
||||
|
||||
deleteCard_handler: function (anEvent) {
|
||||
console.log("DELETE CARD", anEvent['reference']);
|
||||
},
|
||||
|
||||
archiveCard_handler: function (anEvent) {
|
||||
console.log("ARCHIVE CARD", anEvent['reference']);
|
||||
},
|
||||
|
||||
editCard_handler: function (anEvent) {
|
||||
console.log("EDIT CARD", anEvent['reference']);
|
||||
},
|
||||
|
||||
goBackToMainPage_handler: function (anEvent) {
|
||||
this.updateSelectedCard();
|
||||
this.moveOutPage(this.currentPage(), 'mainPage');
|
||||
},
|
||||
|
||||
//============================================================================
|
||||
|
||||
selectAllCards_handler: function () {
|
||||
this.setFilter('ALL');
|
||||
this.updateSelectedCards(false, this.filter());
|
||||
},
|
||||
|
||||
selectRecentCards_handler: function () {
|
||||
this.setFilter('RECENT');
|
||||
this.updateSelectedCards(false, this.filter());
|
||||
},
|
||||
|
||||
tagSelected_handler: function (aTag) {
|
||||
this.setFilter('TAG', aTag);
|
||||
this.updateSelectedCards(false, this.filter());
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
setCloseMaskAction: function (aFunction) {
|
||||
this._closeMaskAction = aFunction;
|
||||
},
|
||||
|
||||
maskClick_handler: function () {
|
||||
this._closeMaskAction.apply(this);
|
||||
this._closeMaskAction = null;
|
||||
},
|
||||
|
||||
//============================================================================
|
||||
|
||||
matchMediaQuery_handler: function (newQueryStyle) {
|
||||
this._mediaQueryStyle = newQueryStyle;
|
||||
|
||||
if (this.currentPage() == 'cardDetailPage') {
|
||||
this.moveOutPage(this.currentPage(), 'mainPage');
|
||||
}
|
||||
this.resetPanels();
|
||||
this.refreshCurrentPage();
|
||||
},
|
||||
|
||||
unmatchMediaQuery_handler: function (queryStyle) {
|
||||
},
|
||||
|
||||
mediaQueryStyle: function () {
|
||||
return this._mediaQueryStyle;
|
||||
},
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
isTouchDevice: function () {
|
||||
return this._isTouchDevice;
|
||||
},
|
||||
|
||||
isDesktop: function () {
|
||||
return this._isDesktop;
|
||||
},
|
||||
|
||||
hasKeyboard: function () {
|
||||
return this._hasKeyboard;
|
||||
},
|
||||
|
||||
//============================================================================
|
||||
/*
|
||||
wrongAppVersion: function (anError) {
|
||||
// this.pages()['errorPage'].setProps({message:anError.message});
|
||||
|
||||
Reference in New Issue
Block a user