Interim synchronization with internal repository

This is an intermir commit to share what is going on with the development of the new /delta version.
master-GE
Giulio Cesare Solaroli 2014-07-28 18:07:48 +02:00
parent 6dd16d9359
commit f8da092f3d
111 changed files with 34049 additions and 28666 deletions

View File

@ -117,4 +117,4 @@ Once the index.html files have been built (one for each frontend) and a backend
This application has not been fully tested, so there may be still problems due to the new build script or to the new repository structure. So, for the moment, **use it at your own risk!**
[pog]: http://www.phpobjectgenerator.com/
[pog]: http://www.phpobjectgenerator.com/

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,431 @@
{
"IcoMoonType": "selection",
"icons": [
{
"icon": {
"paths": [
"M2.259 734.824h279.462v286.917h-279.462v-286.917z",
"M2.259 2.259h279.462v286.917h-279.462v-286.917z",
"M2.259 368.519h279.462v286.917h-279.462v-286.917z"
],
"width": 284,
"grid": 0,
"tags": [
"commands"
]
},
"properties": {
"order": 22,
"id": 0,
"prevSize": 32,
"code": 58894,
"name": "commands",
"ligatures": "commands"
},
"setIdx": 0,
"iconIdx": 0
},
{
"icon": {
"paths": [
"M667.586 345.635v-338.544h-268.055v338.544l-299.967-121.263-90.486 257.986 310.037 104.527-198.134 262.808 224.514 164.237 184.802-279.685 203.382 279.685 221.11-164.237-203.382-262.808 319.397-107.080-90.486-257.986zM1220.574 2319.317z"
],
"width": 1080,
"grid": 0,
"tags": [
"logo"
]
},
"properties": {
"order": 4,
"id": 0,
"prevSize": 32,
"code": 58884,
"name": "logo",
"ligatures": "clipperz"
},
"setIdx": 1,
"iconIdx": 0
},
{
"icon": {
"paths": [
"M96.188 0h288.562c52.906 0 126.796 30.606 164.204 68.014l446.99 446.99c37.408 37.408 37.408 98.624 0 136.032l-344.91 344.906c-37.408 37.41-98.622 37.41-136.030 0l-446.99-446.988c-37.408-37.41-68.014-111.302-68.014-164.204v-288.562c0-52.904 43.286-96.188 96.188-96.188zM224 320c53.020 0 96-42.98 96-96s-42.98-96-96-96-96 42.98-96 96 42.98 96 96 96z"
],
"tags": [
"tag",
"price"
],
"grid": 16
},
"properties": {
"id": 48,
"order": 6,
"prevSize": 32,
"code": 58885,
"name": "tag",
"ligatures": "tag"
},
"setIdx": 2,
"iconIdx": 49
},
{
"icon": {
"paths": [
"M96 64h224c52.8 0 126.546 30.546 163.882 67.882l376.236 376.236c37.334 37.334 37.334 98.428 0 135.764l-280.236 280.234c-37.334 37.336-98.428 37.336-135.764 0l-376.234-376.234c-37.338-37.336-67.884-111.082-67.884-163.882v-224c0-52.8 43.2-96 96-96zM224 384c53.020 0 96-42.98 96-96s-42.98-96-96-96-96 42.98-96 96 42.98 96 96 96zM1001.374 598.626l-342.378 342.378c36.264 19.16 82.462 13.538 112.886-16.888l280.236-280.234c37.334-37.336 37.334-98.43 0-135.764l-376.236-376.236c-37.336-37.336-111.082-67.882-163.882-67.882l489.374 489.372c12.444 12.446 12.444 32.808 0 45.254z"
],
"width": 1088,
"tags": [
"tags",
"prices"
],
"grid": 16
},
"properties": {
"id": 49,
"order": 1,
"prevSize": 32,
"code": 58880,
"name": "tags",
"ligatures": "tags"
},
"setIdx": 2,
"iconIdx": 50
},
{
"icon": {
"paths": [
"M928 128h-832c-52.8 0-96 43.2-96 96v640c0 52.8 43.2 96 96 96h832c52.8 0 96-43.2 96-96v-640c0-52.8-43.2-96-96-96zM398.74 550.372l-270.74 210.892v-501.642l270.74 290.75zM176.38 256h671.24l-335.62 252-335.62-252zM409.288 561.698l102.712 110.302 102.71-110.302 210.554 270.302h-626.528l210.552-270.302zM625.26 550.372l270.74-290.75v501.642l-270.74-210.892z"
],
"tags": [
"envelope",
"mail",
"email",
"contact",
"letter"
],
"grid": 16
},
"properties": {
"id": 64,
"order": 8,
"prevSize": 32,
"code": 58888,
"name": "envelope",
"ligatures": "email"
},
"setIdx": 2,
"iconIdx": 65
},
{
"icon": {
"paths": [
"M658.744 749.256l-210.744-210.746v-282.51h128v229.49l173.256 173.254zM512 0c-282.77 0-512 229.23-512 512s229.23 512 512 512 512-229.23 512-512-229.23-512-512-512zM512 896c-212.078 0-384-171.922-384-384s171.922-384 384-384c212.078 0 384 171.922 384 384 0 212.078-171.922 384-384 384z"
],
"tags": [
"clock",
"time",
"schedule"
],
"grid": 16
},
"properties": {
"id": 72,
"order": 7,
"prevSize": 32,
"code": 58887,
"name": "clock",
"ligatures": "recent"
},
"setIdx": 2,
"iconIdx": 73
},
{
"icon": {
"paths": [
"M384 128c0-70.692 57.308-128 128-128 70.692 0 128 57.308 128 128 0 70.692-57.308 128-128 128-70.692 0-128-57.308-128-128zM655.53 240.47c0-70.692 57.308-128 128-128s128 57.308 128 128c0 70.692-57.308 128-128 128-70.692 0-128-57.308-128-128zM832 512c0-35.346 28.654-64 64-64s64 28.654 64 64c0 35.346-28.654 64-64 64-35.346 0-64-28.654-64-64zM719.53 783.53c0-35.346 28.654-64 64-64s64 28.654 64 64c0 35.346-28.654 64-64 64-35.346 0-64-28.654-64-64zM448.002 896c-0-0-0-0-0-0 0-35.346 28.654-64 64-64 35.346 0 64 28.654 64 64 0 0 0 0 0 0 0 35.346-28.654 64-64 64-35.346 0-64-28.654-64-64zM176.472 783.53c-0-0-0-0-0-0 0-35.346 28.654-64 64-64 35.346 0 64 28.654 64 64 0 0 0 0 0 0 0 35.346-28.654 64-64 64-35.346 0-64-28.654-64-64zM144.472 240.47c-0-0-0-0-0-0 0-53.019 42.981-96 96-96 53.019 0 96 42.981 96 96 0 0 0 0 0 0 0 53.019-42.981 96-96 96-53.019 0-96-42.981-96-96zM56 512c0-39.765 32.235-72 72-72s72 32.235 72 72c0 39.765-32.235 72-72 72-39.765 0-72-32.235-72-72z"
],
"tags": [
"spinner",
"loading",
"busy",
"wait",
"wheel"
],
"grid": 16
},
"properties": {
"id": 120,
"order": 11,
"prevSize": 32,
"code": 58891,
"name": "spinner",
"ligatures": "loading"
},
"setIdx": 2,
"iconIdx": 121
},
{
"icon": {
"paths": [
"M992.262 871.396l-242.552-206.294c-25.074-22.566-51.89-32.926-73.552-31.926 57.256-67.068 91.842-154.078 91.842-249.176 0-212.078-171.922-384-384-384-212.076 0-384 171.922-384 384 0 212.078 171.922 384 384 384 95.098 0 182.108-34.586 249.176-91.844-1 21.662 9.36 48.478 31.926 73.552l206.294 242.552c35.322 39.246 93.022 42.554 128.22 7.356s31.892-92.898-7.354-128.22zM384 640c-141.384 0-256-114.616-256-256s114.616-256 256-256 256 114.616 256 256-114.614 256-256 256z"
],
"tags": [
"search",
"magnifier",
"lookup",
"find"
],
"grid": 16
},
"properties": {
"id": 127,
"order": 5,
"prevSize": 32,
"code": 58886,
"name": "search",
"ligatures": "search"
},
"setIdx": 2,
"iconIdx": 128
},
{
"icon": {
"paths": [
"M832 448h-64v-192c0-141.384-114.616-256-256-256s-256 114.616-256 256v192h-64c-35.2 0-64 28.8-64 64v448c0 35.2 28.8 64 64 64h640c35.2 0 64-28.8 64-64v-448c0-35.2-28.8-64-64-64zM512 832c-35.346 0-64-28.654-64-64s28.654-64 64-64 64 28.654 64 64-28.654 64-64 64zM640 448h-256v-192c0-70.58 57.42-128 128-128s128 57.42 128 128v192z"
],
"tags": [
"lock",
"secure",
"private",
"encrypted"
],
"grid": 16
},
"properties": {
"id": 136,
"order": 9,
"prevSize": 32,
"code": 58889,
"name": "lock",
"ligatures": "password"
},
"setIdx": 2,
"iconIdx": 137
},
{
"icon": {
"paths": [
"M64 192h896v192h-896zM64 448h896v192h-896zM64 704h896v192h-896z"
],
"tags": [
"menu",
"list",
"items",
"lines",
"options"
],
"grid": 16
},
"properties": {
"id": 184,
"order": 14,
"prevSize": 32,
"code": 58881,
"name": "menu2",
"ligatures": "menu"
},
"setIdx": 2,
"iconIdx": 185
},
{
"icon": {
"paths": [
"M1014.662 822.66c-0.004-0.004-0.008-0.008-0.012-0.010l-310.644-310.65 310.644-310.65c0.004-0.004 0.008-0.006 0.012-0.010 3.344-3.346 5.762-7.254 7.312-11.416 4.246-11.376 1.824-24.682-7.324-33.83l-146.746-146.746c-9.148-9.146-22.45-11.566-33.828-7.32-4.16 1.55-8.070 3.968-11.418 7.31 0 0.004-0.004 0.006-0.008 0.010l-310.648 310.652-310.648-310.65c-0.004-0.004-0.006-0.006-0.010-0.010-3.346-3.342-7.254-5.76-11.414-7.31-11.38-4.248-24.682-1.826-33.83 7.32l-146.748 146.748c-9.148 9.148-11.568 22.452-7.322 33.828 1.552 4.16 3.97 8.072 7.312 11.416 0.004 0.002 0.006 0.006 0.010 0.010l310.65 310.648-310.65 310.652c-0.002 0.004-0.006 0.006-0.008 0.010-3.342 3.346-5.76 7.254-7.314 11.414-4.248 11.376-1.826 24.682 7.322 33.83l146.748 146.746c9.15 9.148 22.452 11.568 33.83 7.322 4.16-1.552 8.070-3.97 11.416-7.312 0.002-0.004 0.006-0.006 0.010-0.010l310.648-310.65 310.648 310.65c0.004 0.002 0.008 0.006 0.012 0.008 3.348 3.344 7.254 5.762 11.414 7.314 11.378 4.246 24.684 1.826 33.828-7.322l146.746-146.748c9.148-9.148 11.57-22.454 7.324-33.83-1.552-4.16-3.97-8.068-7.314-11.414z"
],
"tags": [
"close",
"cancel",
"quit",
"remove",
"cross"
],
"grid": 16
},
"properties": {
"id": 253,
"order": 3,
"prevSize": 32,
"code": 58882,
"name": "close",
"ligatures": "failure, failed"
},
"setIdx": 2,
"iconIdx": 254
},
{
"icon": {
"paths": [
"M864 128l-480 480-224-224-160 160 384 384 640-640z"
],
"tags": [
"checkmark",
"tick",
"correct",
"accept",
"ok"
],
"grid": 16
},
"properties": {
"id": 254,
"order": 2,
"prevSize": 32,
"code": 58883,
"name": "checkmark",
"ligatures": "done, ok"
},
"setIdx": 2,
"iconIdx": 255
},
{
"icon": {
"paths": [
"M819.2 102.4h-410.624c-56.32 0-101.376 45.056-101.376 101.376v410.624c0 56.32 46.080 102.4 102.4 102.4h409.6c56.32 0 102.4-46.080 102.4-102.4v-409.6c0-56.32-46.080-102.4-102.4-102.4zM819.2 614.4h-409.6v-409.6h409.6v409.6zM204.8 512h-102.4v307.2c0 56.32 46.080 102.4 102.4 102.4h307.2v-102.4h-307.2v-307.2z"
],
"tags": [
"popup",
"popout",
"new window"
],
"grid": 20
},
"properties": {
"id": 35,
"order": 10,
"prevSize": 32,
"code": 58890,
"name": "popup",
"ligatures": "url"
},
"setIdx": 5,
"iconIdx": 35
},
{
"icon": {
"paths": [
"M512 81.92c-237.568 0-430.080 192.614-430.080 430.080 0 237.568 192.563 430.080 430.080 430.080 237.517 0 430.080-192.563 430.080-430.080 0-237.517-192.563-430.080-430.080-430.080zM564.326 564.326v206.182h-104.653v-206.182h-206.234v-104.653h206.182v-206.234h104.704v206.182h206.182v104.704h-206.182z"
],
"tags": [
"plus",
"add",
"sum"
],
"grid": 20
},
"properties": {
"id": 125,
"order": 16,
"prevSize": 32,
"code": 58895,
"name": "plus",
"ligatures": "add card"
},
"setIdx": 5,
"iconIdx": 125
},
{
"icon": {
"paths": [
"M585.574 231.219c-21.402 20.89-230.502 240.435-230.502 240.435-11.418 11.162-17.101 25.754-17.101 40.346s5.683 29.184 17.101 40.346c0 0 209.101 219.546 230.502 240.384 21.402 20.89 59.904 22.323 82.739 0 22.784-22.272 24.576-53.35-0.051-80.64l-191.846-200.090 191.846-200.090c24.627-27.341 22.835-58.419 0.051-80.691-22.886-22.272-61.389-20.89-82.739-0z"
],
"tags": [
"arrow-left",
"left",
"previous"
],
"grid": 20
},
"properties": {
"id": 205,
"order": 12,
"prevSize": 32,
"code": 58892,
"name": "arrow-left",
"ligatures": "back"
},
"setIdx": 5,
"iconIdx": 205
},
{
"icon": {
"paths": [
"M438.426 231.219c21.402 20.89 230.502 240.435 230.502 240.435 11.469 11.162 17.152 25.754 17.152 40.346s-5.683 29.184-17.152 40.346c0 0-209.101 219.546-230.502 240.384-21.402 20.89-59.853 22.323-82.739 0-22.835-22.272-24.627-53.35 0-80.64l191.898-200.090-191.846-200.090c-24.627-27.341-22.835-58.419 0-80.691 22.835-22.272 61.338-20.89 82.688-0z"
],
"tags": [
"arrow-right",
"right",
"next"
],
"grid": 20
},
"properties": {
"id": 208,
"order": 13,
"prevSize": 32,
"code": 58893,
"name": "arrow-right",
"ligatures": "show detail"
},
"setIdx": 5,
"iconIdx": 208
}
],
"height": 1024,
"metadata": {
"name": "clipperz-icons"
},
"preferences": {
"fontPref": {
"prefix": "icon-",
"metadata": {
"fontFamily": "clipperz-icons",
"majorVersion": 1,
"minorVersion": 0
},
"showGlyphs": true,
"metrics": {
"emSize": 512,
"baseline": 6.25,
"whitespace": 50
},
"resetPoint": 58880,
"showQuickUse": true,
"quickUsageToken": false,
"showMetrics": true,
"showMetadata": false,
"autoHost": false,
"embed": true,
"showVersion": true
},
"imagePref": {
"color": 0,
"height": 32,
"columns": 16,
"margin": 16,
"png": false,
"sprites": true
},
"historySize": 100,
"showCodes": false,
"gridSize": 16,
"showLiga": true,
"showGrid": true,
"showGlyphs": true,
"showQuickUse": true,
"search": "",
"quickUsageToken": {
"UntitledProject1": "YzBlN2I0ZDQ5YTQyY2NjYjgwNGRkYzNhYzU4NDZhMDcjMiMxNDAzMTA2OTk5IyMj"
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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;

View File

@ -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) {

View File

@ -21,6 +21,7 @@ refer to http://www.clipperz.com.
*/
"use strict";
if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
//=============================================================================

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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";

View File

@ -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";

View File

@ -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');
};

View File

@ -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']
};
},

View File

@ -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'),

View File

@ -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),

View File

@ -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'),

View File

@ -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');

View File

@ -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(), {

View File

@ -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']
}
}

View 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'])
]);
}
//=========================================================================
});

View 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'])
])
]);
}
//=========================================================================
});

View File

@ -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")
*/
])
]);
}
//=========================================================================
});

View File

@ -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()),
]);
}
//=========================================================================
});

View 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']),
]);
}
//============================================================================
});

View 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))
]);
},
//=========================================================================
});

View 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));
},
//=========================================================================
});

View 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;
},
//=========================================================================
});

View File

@ -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

View 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");
},
//=========================================================================
});

View 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']);
}
//=========================================================================
});

View File

@ -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']);
},
});

View File

@ -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()});
// }
});

View File

@ -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
]);
}
});

View 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.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)
]);
}
//=========================================================================
});

View File

@ -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()});
// },
//=========================================================================

View File

@ -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>
*/
}
//=========================================================================
});

View 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())
)
]);
}
//=========================================================================
});

View File

@ -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),
]);
}
//=========================================================================
});

View File

@ -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'}, [
])
]);
}
//=========================================================================
});

View 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'] : []))
]);
}
//=========================================================================
});

View 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']);
},
//=========================================================================
});

View File

@ -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();
};

View File

@ -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});

View File

@ -0,0 +1,261 @@
/*
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/.
*/
/*
* onMediaQuery
* http://springload.co.nz/love-the-web/
*
* Copyright 2012, Springload
* Released under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*
* Date: Fri 24 October, 2012
*/
;(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(function () {
// Also create a global in case some scripts
// that are loaded still are looking for
// a global even when an AMD loader is in use.
return (root.MQ = factory(root, root.MQ || {}));
});
} else {
// Browser globals
root.MQ = factory(root, root.MQ || {});
}
}(this, function(mq) {
/**
* Initialises the MQ object and sets the initial media query callbacks
* @returns Void(0)
*/
mq.init = function(query_array) {
// Container for all callbacks registered with the plugin
this.callbacks = [];
this.context = ''; //current active query
this.new_context = ''; //current active query to be read inside callbacks, as this.context won't be set when they're called!
if (typeof(query_array) !== 'undefined' ) {
for (i = 0; i < query_array.length; i++) {
var r = this.addQuery(query_array[i]);
}
}
// Add a listener to the window.resize event, pass mq/self as the scope.
this.addEvent(window, 'resize', mq.listenForChange, mq);
// Figure out which query is active on load.
this.listenForChange();
};
/**
* Binds to the window.onResize and checks for media query changes
* @returns Void(0)
*/
mq.listenForChange = function() {
var query_string;
// Get the value of html { font-family } from the element style.
if (document.documentElement.currentStyle) {
query_string = document.documentElement.currentStyle["fontFamily"];
}
if (window.getComputedStyle) {
query_string = window.getComputedStyle(document.documentElement,null).getPropertyValue('font-family');
}
// No support for CSS enumeration? Return and avoid errors.
if (query_string === null) return;
// Android browsers place a "," after an item in the font family list.
// Most browsers either single or double quote the string.
query_string = query_string.replace(/['",]/g, '');
if (query_string !== this.context) {
this.new_context = query_string;
this.triggerCallbacks(this.context, 'unmatch');
this.triggerCallbacks(this.new_context, 'match');
}
this.context = this.new_context;
};
/**
* Attach a new query to test.
* @param query_object {
* context: ['some_media_query','some_other_media_query'],
* call_for_each_context: true,
* callback: function() {
* //something awesome
* }
* }
* @returns A reference to the query_object that was added
*/
mq.addQuery = function(query_object) {
if (query_object === null || query_object === undefined) return;
this.callbacks.push(query_object);
// If the context is passed as a string, turn it into an array (for unified approach elsewhere in the code)
if (typeof(query_object.context) == "string") {
query_object.context = [query_object.context];
}
// See if "call_for_each_context" is set, if not, set a default (for unified approach elsewhere in the code)
if (typeof(query_object.call_for_each_context) !== "boolean") {
query_object.call_for_each_context = true; // Default
}
// Fire the added callback if it matches the current context
if (this.context !== '' && this._inArray(this.context, query_object.context)) {
query_object.match();
}
return this.callbacks[ this.callbacks.length - 1];
};
/**
* Remove a query_object by reference.
* @returns Void(0)
*/
mq.removeQuery = function(query_object) {
if (query_object === null || query_object === undefined) return;
var match = -1;
while ((match = mq._indexOf(query_object,this.callbacks)) > -1) {
this.callbacks.splice(match, 1);
}
};
/**
* Loop through the stored callbacks and execute
* the ones that are bound to the current context.
* @returns Void(0)
*/
mq.triggerCallbacks = function(size, key) {
var i, callback_function, call_for_each_context;
for (i = 0; i < this.callbacks.length; i++) {
// Don't call for each context?
if(this.callbacks[i].call_for_each_context === false) {
if ((key === 'match' && this._inArray(this.context, this.callbacks[i].context)) ||
(key === 'unmatch' && this._inArray(this.new_context, this.callbacks[i].context))) {
// Was previously called, and we don't want to call it for each context
continue;
}
}
callback_function = this.callbacks[i][key];
if (this._inArray(size, this.callbacks[i].context) && callback_function !== undefined) {
callback_function();
}
}
};
/**
* Swiss Army Knife event binding, in lieu of jQuery.
* @returns Void(0)
*/
mq.addEvent = function(elem, type, eventHandle, eventContext) {
if (elem === null || elem === undefined) return;
// If the browser supports event listeners, use them.
if (elem.addEventListener) {
elem.addEventListener(type, function() { eventHandle.call(eventContext); }, false);
} else if (elem.attachEvent ) {
elem.attachEvent("on" + type, function() { eventHandle.call(eventContext); });
// Otherwise, replace the current thing bound to on[whatever]! Consider refactoring.
} else {
elem["on" + type] = function() { eventHandle.call(eventContext); };
}
};
/**
* Function to return the mediaquery's previous context
* @returns String returns the current mediaquery's context
*/
mq.getPreviousContext = function()
{
return this.context;
};
/**
* Function to return the mediaquery's current context
* @returns String returns the current mediaquery's context
*/
mq.getContext = function()
{
return this.new_context;
};
/**
* Internal helper function that checks wether "needle" occurs in "haystack"
* @param needle Mixed Value to look for in haystack array
* @param haystack Array Haystack array to search in
* @returns Boolan True if the needle occurs, false otherwise
*/
mq._inArray = function(needle, haystack)
{
var length = haystack.length;
for(var i = 0; i < length; i++) {
if(haystack[i] == needle) return true;
}
return false;
};
/**
* IE8 do not supports Array.properties.indexOf
* copy from jQuery.
* in lieu of jQuery.
* @returns int
*/
mq._indexOf = function( elem, arr, i )
{
var len;
if ( arr ) {
if ( arr.indexOf ) {
return arr.indexOf( elem, i );
}
len = arr.length;
i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
for ( ; i < len; i++ ) {
// Skip accessing in sparse arrays
if ( i in arr && arr[ i ] === elem ) {
return i;
}
}
}
return -1;
}
// Expose the functions.
return mq;
}));

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -44,12 +44,27 @@ MochiKit.Logging.logError("## MainController - GENERIC ERROR" + "\n" + "==>> " +
React.initializeTouchEvents(true);
Clipperz.PM.RunTime = {};
function run() {
function initOnMediaQuery () {
MQ.init(MochiKit.Base.map(function (queryStyle) {
return {
context: queryStyle,
match: function () {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'matchMediaQuery', queryStyle);
},
unmatch: function () {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'unmatchMediaQuery', queryStyle);
},
}
// }, ['extra-short', 'narrow', 'wide', 'extra-wide']));
}, Clipperz_PM_UI_availableStyles));
}
function run () {
var parameters = {};
Clipperz.PM.Strings.Languages.initSetup();
if ((window.location.search.indexOf('registration') != -1) || (window.location.hash.indexOf('registration') != -1)) {
parameters['shouldShowRegistrationForm'] = true;
} else {
@ -59,7 +74,29 @@ function run() {
Clipperz.PM.DataModel.devicePreferences = new Clipperz.PM.DataModel.DevicePreferences({});
Clipperz.PM.RunTime.mainController = new Clipperz.PM.UI.MainController();
initOnMediaQuery();
Clipperz.PM.RunTime.mainController.run(parameters);
}
MochiKit.DOM.addLoadEvent(run);
/* * /
MochiKit.DOM.addLoadEvent(simulateLogin);
function simulateLogin () {
var getURLParameter = function (name) {
return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g, '%20'))||null;
}
Clipperz.Crypto.PRNG.defaultRandomGenerator().fastEntropyAccumulationForTestingPurpose();
// MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', {username:'joe', passphrase:'clipperz'}); // FULL
// http://localhost:8888/delta/index.html?username=joe&passphrase=clipperz
// MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', {username:';', passphrase:';'}); // EXPIRED
// http://localhost:8888/delta/index.html?username=%3B&passphrase=%3B
if ((getURLParameter('u') != null) && (getURLParameter('p'))) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', {username:getURLParameter('u'), passphrase:getURLParameter('p')});
}
}
/ * */

View File

@ -7,7 +7,7 @@
# MochiKit (http://www.mochikit.com)
- repository: @mochikit.repository@ (version: @mochikit.version@ - commit: @mochikit.commit@)
* Software licence: https://github.com/mochi/mochikit/blob/master/LICENSE.txt
* Software license: https://github.com/mochi/mochikit/blob/master/LICENSE.txt
| MochiKit is dual-licensed software. It is available under the terms of the
| MIT License, or the Academic Free License version 2.1. The full text of
@ -207,7 +207,7 @@
# React.js (http://facebook.github.io/react/)
- repository: @reactjs.repository@ (version: @reactjs.version@ - commit: @reactjs.commit@)
* Software licence: https://github.com/facebook/react/blob/master/LICENSE
* Software license: https://github.com/facebook/react/blob/master/LICENSE
| Apache License
| Version 2.0, January 2004
@ -413,10 +413,61 @@
# Modernizr (http://modernizr.com)
- repository: @modernizr.repository@ (version: @modernizr.version@ - commit: @modernizr.commit@)
* Software license: http://modernizr.com/license/
| Copyright (c) 20092013
| Permission is hereby granted, free of charge, to any person obtaining a copy
| of this software and associated documentation files (the "Software"), to deal
| in the Software without restriction, including without limitation the rights
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
| copies of the Software, and to permit persons to whom the Software is
| furnished to do so, subject to the following conditions:
| The above copyright notice and this permission notice shall be included in
| all copies or substantial portions of the Software.
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
| THE SOFTWARE.
# OnMediaQuery (https://github.com/JoshBarr/on-media-query)
- repository: @onmediaquery.repository@ (version: @onmediaquery.version@ - commit: @onmediaquery.commit@)
* Software license: http://opensource.org/licenses/mit-license.php
| The MIT License (MIT)
|
| Copyright (c) <year> <copyright holders>
|
| Permission is hereby granted, free of charge, to any person obtaining a copy
| of this software and associated documentation files (the "Software"), to deal
| in the Software without restriction, including without limitation the rights
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
| copies of the Software, and to permit persons to whom the Software is
| furnished to do so, subject to the following conditions:
|
| The above copyright notice and this permission notice shall be included in
| all copies or substantial portions of the Software.
|
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
| THE SOFTWARE.
# Add to Home Screen (http://cubiq.org/add-to-home-screen)
- repository: @addtohomescreen.repository@ (version: @addtohomescreen.version@ - commit: @addtohomescreen.commit@)
* Software licence: https://github.com/facebook/react/blob/master/LICENSE
* Software license: https://github.com/facebook/react/blob/master/LICENSE
| This software is released under the MIT License.
|
@ -447,7 +498,7 @@
Copyright © 2005-2006 Yahoo! Inc. All rights reserved
* Copyright notes: http://docs.yahoo.com/info/copyright/copyright.html
* Software licence: http://developer.yahoo.com/yui/license.txt
* Software license: http://developer.yahoo.com/yui/license.txt
| Software License Agreement (BSD License)
|
@ -485,7 +536,7 @@
# YUI-ext (http://www.yui-ext.com)
- repository: http://yui-ext.googlecode.com/svn/trunk/ (revision: 120)
* Software licence: http://yui-ext.googlecode.com/svn/trunk/src/licence.txt
* Software license: http://yui-ext.googlecode.com/svn/trunk/src/licence.txt
| yui-ext
| Copyright (c) 2006, Jack Slocum

View File

@ -5,9 +5,17 @@
"mochikit.commit": "6f26f745d5d915540aa0fc6c34fda24952891a9d",
"reactjs.repository": "https://github.com/facebook/react.git",
"reactjs.version": "0.4.1",
"reactjs.commit": "0cac12d375264a8a232a426d6d6cc8074a94000a",
"reactjs.version": "0.11.0",
"reactjs.commit": "95d82cacd6e9cc6a2fe6366d79510cc9133886cb",
"modernizr.repository": "https://github.com/Modernizr/Modernizr",
"modernizr.version": "2.8.2",
"modernizr.commit": "99c09fa23a83f160a021c98b3644628aaec5e37a",
"onmediaquery.repository": "https://github.com/JoshBarr/on-media-query",
"onmediaquery.version": "0.2.0",
"onmediaquery.commit": "5080914636d392781ac858fb8eca9c0d99e5d35c",
"addtohomescreen.repository": "https://github.com/cubiq/add-to-homescreen.git",
"addtohomescreen.version": "2.0.8",
"addtohomescreen.commit": "4d375840079bcea994cc5795a568802400c7a793"
@ -31,13 +39,14 @@
"MochiKit/Selector.js",
"-- MochiKit/Visual.js",
"-- React/react-0.4.1.js",
"React/react-0.5.0-alpha.js",
"React/react-with-addons-0.11.0.js",
"-- Hammer/hammer-1.0.5.js",
"Cubiq/add2home.js",
"-- Cubiq/add2home.js",
"-- Modernizr/modernizr-2.8.2.js",
"OnMediaQuery/onmediaquery-0.2.0.js",
"-- IT WOULD BE NICE TO BE ABLE TO GET RID OF THESE IMPORTS",
"Clipperz/YUI/Utils.js",
"Clipperz/YUI/DomHelper.js",
@ -45,14 +54,14 @@
"Clipperz/Base.js",
"Clipperz/Async.js",
"Clipperz/CSVProcessor.js",
"Clipperz/KeePassExportProcessor.js",
"-- Clipperz/KeePassExportProcessor.js",
"Clipperz/Date.js",
"Clipperz/DOM.js",
"-- Clipperz/DOM.js",
"Clipperz/Logging.js",
"Clipperz/Signal.js",
"-- Clipperz/Style.js",
"-- Clipperz/Visual.js",
"Clipperz/Set.js",
"-- Clipperz/Set.js",
"-- Clipperz/Profile.js",
"Clipperz/KeyValueObjectStore.js",
@ -104,7 +113,7 @@
"Clipperz/PM/DataModel/User.Header.RecordIndex.js",
"Clipperz/PM/DataModel/User.Header.Preferences.js",
"Clipperz/PM/DataModel/User.Header.OneTimePasswords.js",
"Clipperz/PM/DataModel/User.Subscription.js",
"Clipperz/PM/DataModel/User.AccountInfo.js",
"Clipperz/PM/DataModel/Record.js",
"Clipperz/PM/DataModel/Record.Version.js",
"Clipperz/PM/DataModel/Record.Version.Field.js",
@ -124,21 +133,42 @@
"-- Clipperz/PM/UI/Web/Controllers/MainController.js",
"Clipperz/PM/UI/Components/Overlay.js",
"Clipperz/PM/UI/Components/Button.js",
"Clipperz/PM/UI/Components/Checkbox.js",
"Clipperz/PM/UI/Components/PageTemplate.js",
"Clipperz/PM/UI/Components/LoginForm.js",
"Clipperz/PM/UI/Components/RegistrationWizard.js",
"Clipperz/PM/UI/Components/CardList.js",
"Clipperz/PM/UI/Components/CardDetail.js",
"Clipperz/PM/UI/Components/PreferencePage.js",
"Clipperz/PM/UI/Components/ErrorPage.js",
"Clipperz/PM/UI/Components/CardToolbar.js",
"Clipperz/PM/UI/Components/MessageBox.js",
"Clipperz/PM/UI/Components/Selections.js",
"Clipperz/PM/UI/Components/TagIndexItem.js",
"Clipperz/PM/UI/Components/ExpiredPanel.js",
"Clipperz/PM/UI/Components/Pages/LoginPage.js",
"Clipperz/PM/UI/Components/Pages/RegistrationPage.js",
"Clipperz/PM/UI/Components/Pages/MainPage.js",
"Clipperz/PM/UI/Components/Pages/CardDetailPage.js",
"Clipperz/PM/UI/Components/Pages/ErrorPage.js",
"Clipperz/PM/UI/Components/Panels/SelectionPanel.js",
"Clipperz/PM/UI/Components/Panels/MainPanel.js",
"Clipperz/PM/UI/Components/Panels/ExtraFeaturesPanel.js",
"Clipperz/PM/UI/Components/Cards/List.js",
"Clipperz/PM/UI/Components/Cards/View.js",
"Clipperz/PM/UI/Components/Cards/Toolbar.js",
"Clipperz/PM/UI/Components/AccountStatus.js",
"Clipperz/PM/UI/MainController.js",
"-- Clipperz/PM/UI/MainDesktopController.js",
"Clipperz/PM/UI/DirectLoginController.js",
"main.js"
],
"css": [
"web.css"
"clipperz.css"
],
"scss": [
"clipperz.scss"
]
}

View File

@ -1,9 +1,9 @@
CACHE MANIFEST
# 2013-10-01:v0.0.1
# @application.version@
CACHE:
# - Explicitly cached 'master entries'.
index.html
#index.html
NETWORK:
# - Resources that require the user to be online.

View File

@ -0,0 +1,35 @@
@import "core/reset";
@import "core/palette";
@import "core/parameters";
@import "core/fonts";
@import "core/flex";
@import "core/overlay";
@import "core/behavior";
@import "core/layout";
@import "style/loadingPage";
@import "style/loginPage";
@import "style/registrationPage";
@import "style/selectionPanel";
@import "style/settingsPanel";
@import "style/accountStatus";
@import "style/card";
//----------------------------------------------------------------------------
body {
font-family: "clipperz-font";
margin: 0;
padding: 0;
}
body:after {
display: none;
}
@import "core/sizes";
//@import "sizes/narrow";
//@import "sizes/wide";
//@import "sizes/extra-wide";
//@import "sizes/extra-short";

View File

@ -0,0 +1,205 @@
// https://github.com/h5bp/Effeckt.css
// http://coenraets.org/blog/2013/03/hardware-accelerated-page-transitions-for-mobile-web-apps-phonegap-apps/
$transition-duration: 0.5s;
@mixin pageElement () {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
@include transform3d(0, 0, 0);
@include transition-duration($transition-duration);
&.left {
@include transform3d(-100%, 0, 0);
}
&.right {
@include transform3d(100%, 0, 0);
visibility: hidden;
display: none;
&.transition {
visibility: visible;
display: block;
}
}
}
//=============================================================================
@mixin sliding-panel-left ($size) {
// background-color: yellow;
width: $size;
height: 100%;
top: 0;
left: -$size;
}
@mixin sliding-panel-right ($size) {
// background-color: green;
width: $size;
height: 100%;
top: 0;
right: -$size;
}
@mixin sliding-panel ($side, $size) {
position: fixed;
z-index: 20;
overflow: scroll;
@if $side == left {
@include sliding-panel-left($size);
}
@if $side == right {
@include sliding-panel-right($size);
}
}
//.............................................................................
@mixin sliding-panel-open ($side, $size) {
@if $side == left {
left: 0px;
}
@if $side == right {
right: 0px;
}
}
//.............................................................................
@mixin sliding-panel-wrapper-open-left ($size) {
top: 0;
left: $size;
}
@mixin sliding-panel-wrapper-open-right ($size) {
top: 0;
right: $size;
}
@mixin sliding-panel-wrapper-open ($side, $size) {
@include sliding-panel-wrapper();
@if $side == left {
@include sliding-panel-wrapper-open-left($size);
}
@if $side == right {
@include sliding-panel-wrapper-open-right($size);
}
}
//.............................................................................
@mixin sliding-panel-wrapper () {
width: 100%;
margin: 0 auto;
position: relative;
z-index: 10;
// top: 0;
// left: 0;
// @include transition(all, $transition_time);
}
@mixin sliding-panel-container () {
width: 100%;
height: 100%;
margin: 0 auto;
}
//#############################################################################
/*
.registrationForm {
.steps {
.step {
position: absolute;
// top: 0;
// left: 0;
// width: 100%;
// height: 100%;
.slide();
}
}
}
*/
//----------------------------------------------------------------------
// tentative 3D transformations
/*
.page {
transform: rotateY( 0deg) translateZ( 100px);
&.left {
transform: rotateY( -90deg) translateZ( 100px);
}
&.center {
transform: rotateY( 0deg) translateZ( 100px);
}
&.right {
transform: rotateY( 90deg) translateZ( 100px);
}
}
#mainDiv {
width: 100%;
height: 100%;
position: absolute;
transform-style: preserve-3d;
transition: transform 3s;
&.show-front { transform: translateZ( -100px ) rotateY( 0deg ); }
&.show-back { transform: translateZ( -100px ) rotateX( -180deg ); }
&.show-right { transform: translateZ( -100px ) rotateY( -90deg ); }
&.show-left { transform: translateZ( -100px ) rotateY( 90deg ); }
&.show-top { transform: translateZ( -100px ) rotateX( -90deg ); }
&.show-bottom { transform: translateZ( -100px ) rotateX( 90deg ); }
}
*/
//=======================================================================
//=======================================================================
//=======================================================================

View File

@ -0,0 +1,395 @@
// Downloaded on June 8, 2014 from https://raw.githubusercontent.com/mastastealth/sass-flex-mixin/master/flex.scss
// Flexbox Mixins
// http://philipwalton.github.io/solved-by-flexbox/
// https://github.com/philipwalton/solved-by-flexbox
//
// Copyright (c) 2013 Brian Franco
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// This is a set of mixins for those who want to mess around with flexbox
// using the native support of current browsers. For full support table
// check: http://caniuse.com/flexbox
//
// Basically this will use:
//
// * Fallback, old syntax (IE10, Safari, mobile webkit browsers)
// * Prefixed standard syntax (Chrome)
// * Final standards syntax (FF, IE11, Opera 12.1)
//
// This was inspired by:
//
// * http://dev.opera.com/articles/view/advanced-cross-browser-flexbox/
//
// With help from:
//
// * http://w3.org/tr/css3-flexbox/
// * http://the-echoplex.net/flexyboxes/
// * http://msdn.microsoft.com/en-us/library/ie/hh772069(v=vs.85).aspx
// * http://css-tricks.com/using-flexbox/
// * http://dev.opera.com/articles/view/advanced-cross-browser-flexbox/
// * https://developer.mozilla.org/en-us/docs/web/guide/css/flexible_boxes
//----------------------------------------------------------------------
// Flexbox Containers
//
// The 'flex' value causes an element to generate a block-level flex
// container box.
//
// The 'inline-flex' value causes an element to generate a inline-level
// flex container box.
//
// display: flex | inline-flex
//
// http://w3.org/tr/css3-flexbox/#flex-containers
//
// (Placeholder selectors for each type, for those who rather @extend)
@mixin flexbox {
display: -webkit-box;
display: -webkit-flex;
display: -moz-flex;
display: -ms-flexbox;
display: flex;
}
%flexbox { @include flexbox; }
//----------------------------------
@mixin inline-flex {
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -moz-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
}
%inline-flex { @include inline-flex; }
//----------------------------------------------------------------------
// Flexbox Direction
//
// The 'flex-direction' property specifies how flex items are placed in
// the flex container, by setting the direction of the flex container's
// main axis. This determines the direction that flex items are laid out in.
//
// Values: row | row-reverse | column | column-reverse
// Default: row
//
// http://w3.org/tr/css3-flexbox/#flex-direction-property
@mixin flex-direction($value: row) {
@if $value == row-reverse {
-webkit-box-direction: reverse;
-webkit-box-orient: horizontal;
} @else if $value == column {
-webkit-box-direction: normal;
-webkit-box-orient: vertical;
} @else if $value == column-reverse {
-webkit-box-direction: reverse;
-webkit-box-orient: vertical;
} @else {
-webkit-box-direction: normal;
-webkit-box-orient: horizontal;
}
-webkit-flex-direction: $value;
-moz-flex-direction: $value;
-ms-flex-direction: $value;
flex-direction: $value;
}
// Shorter version:
@mixin flex-dir($value: false) { @include flex-direction($value); }
//----------------------------------------------------------------------
// Flexbox Wrap
//
// The 'flex-wrap' property controls whether the flex container is single-line
// or multi-line, and the direction of the cross-axis, which determines
// the direction new lines are stacked in.
//
// Values: nowrap | wrap | wrap-reverse
// Default: nowrap
//
// http://w3.org/tr/css3-flexbox/#flex-wrap-property
@mixin flex-wrap($value: nowrap) {
// No Webkit Box fallback.
-webkit-flex-wrap: $value;
-moz-flex-wrap: $value;
@if $value == nowrap {
-ms-flex-wrap: none;
} @else {
-ms-flex-wrap: $value;
}
flex-wrap: $value;
}
//----------------------------------------------------------------------
// Flexbox Flow (shorthand)
//
// The 'flex-flow' property is a shorthand for setting the 'flex-direction'
// and 'flex-wrap' properties, which together define the flex container's
// main and cross axes.
//
// Values: <flex-direction> | <flex-wrap>
// Default: row nowrap
//
// http://w3.org/tr/css3-flexbox/#flex-flow-property
@mixin flex-flow($values: (row nowrap)) {
// No Webkit Box fallback.
-webkit-flex-flow: $values;
-moz-flex-flow: $values;
-ms-flex-flow: $values;
flex-flow: $values;
}
//----------------------------------------------------------------------
// Flexbox Order
//
// The 'order' property controls the order in which flex items appear within
// their flex container, by assigning them to ordinal groups.
//
// Default: 0
//
// http://w3.org/tr/css3-flexbox/#order-property
@mixin order($int: 0) {
-webkit-box-ordinal-group: $int + 1;
-webkit-order: $int;
-moz-order: $int;
-ms-flex-order: $int;
order: $int;
}
//----------------------------------------------------------------------
// Flexbox Grow
//
// The 'flex-grow' property sets the flex grow factor. Negative numbers
// are invalid.
//
// Default: 0
//
// http://w3.org/tr/css3-flexbox/#flex-grow-property
@mixin flex-grow($int: 0) {
-webkit-box-flex: $int;
-webkit-flex-grow: $int;
-moz-flex-grow: $int;
-ms-flex-positive: $int;
flex-grow: $int;
}
//----------------------------------------------------------------------
// Flexbox Shrink
//
// The 'flex-shrink' property sets the flex shrink factor. Negative numbers
// are invalid.
//
// Default: 1
//
// http://w3.org/tr/css3-flexbox/#flex-shrink-property
@mixin flex-shrink($int: 1) {
-webkit-flex-shrink: $int;
-moz-flex-shrink: $int;
-ms-flex-negative: $int;
flex-shrink: $int;
}
//----------------------------------------------------------------------
// Flexbox Basis
//
// The 'flex-basis' property sets the flex basis. Negative lengths are invalid.
//
// Values: Like "width"
// Default: auto
//
// http://www.w3.org/TR/css3-flexbox/#flex-basis-property
@mixin flex-basis($value: auto) {
-webkit-flex-basis: $value;
-moz-flex-basis: $value;
-ms-flex-preferred-size: $value;
flex-basis: $value;
}
//----------------------------------------------------------------------
// Flexbox "Flex" (shorthand)
//
// The 'flex' property specifies the components of a flexible length: the
// flex grow factor and flex shrink factor, and the flex basis. When an
// element is a flex item, 'flex' is consulted instead of the main size
// property to determine the main size of the element. If an element is
// not a flex item, 'flex' has no effect.
//
// Values: none | <flex-grow> <flex-shrink> || <flex-basis>
// Default: See individual properties (1 1 0).
//
// http://w3.org/tr/css3-flexbox/#flex-property
@mixin flex($fg: 1, $fs: null, $fb: null) {
// Set a variable to be used by box-flex properties
$fg-boxflex: $fg;
// Box-Flex only supports a flex-grow value so let's grab the
// first item in the list and just return that.
@if type-of($fg) == 'list' {
$fg-boxflex: nth($fg, 1);
}
-webkit-box-flex: $fg-boxflex;
-webkit-flex: $fg $fs $fb;
-moz-box-flex: $fg-boxflex;
-moz-flex: $fg $fs $fb;
-ms-flex: $fg $fs $fb;
flex: $fg $fs $fb;
}
//----------------------------------------------------------------------
// Flexbox Justify Content
//
// The 'justify-content' property aligns flex items along the main axis
// of the current line of the flex container. This is done after any flexible
// lengths and any auto margins have been resolved. Typically it helps distribute
// extra free space leftover when either all the flex items on a line are
// inflexible, or are flexible but have reached their maximum size. It also
// exerts some control over the alignment of items when they overflow the line.
//
// Note: 'space-*' values not supported in older syntaxes.
//
// Values: flex-start | flex-end | center | space-between | space-around
// Default: flex-start
//
// http://w3.org/tr/css3-flexbox/#justify-content-property
@mixin justify-content($value: flex-start) {
@if $value == flex-start {
-webkit-box-pack: start;
-ms-flex-pack: start;
} @else if $value == flex-end {
-webkit-box-pack: end;
-ms-flex-pack: end;
} @else if $value == space-between {
-webkit-box-pack: justify;
-ms-flex-pack: justify;
} @else {
-webkit-box-pack: $value;
-ms-flex-pack: $value;
}
-webkit-justify-content: $value;
-moz-justify-content: $value;
justify-content: $value;
}
// Shorter version:
@mixin flex-just($value: flex-start) { @include justify-content($value); }
//----------------------------------------------------------------------
// Flexbox Align Items
//
// Flex items can be aligned in the cross axis of the current line of the
// flex container, similar to 'justify-content' but in the perpendicular
// direction. 'align-items' sets the default alignment for all of the flex
// container's items, including anonymous flex items. 'align-self' allows
// this default alignment to be overridden for individual flex items. (For
// anonymous flex items, 'align-self' always matches the value of 'align-items'
// on their associated flex container.)
//
// Values: flex-start | flex-end | center | baseline | stretch
// Default: stretch
//
// http://w3.org/tr/css3-flexbox/#align-items-property
@mixin align-items($value: stretch) {
@if $value == flex-start {
-webkit-box-align: start;
-ms-flex-align: start;
} @else if $value == flex-end {
-webkit-box-align: end;
-ms-flex-align: end;
} @else {
-webkit-box-align: $value;
-ms-flex-align: $value;
}
-webkit-align-items: $value;
-moz-align-items: $value;
align-items: $value;
}
//----------------------------------
// Flexbox Align Self
//
// Values: auto | flex-start | flex-end | center | baseline | stretch
// Default: auto
@mixin align-self($value: auto) {
// No Webkit Box Fallback.
-webkit-align-self: $value;
-moz-align-self: $value;
@if $value == flex-start {
-ms-flex-item-align: start;
} @else if $value == flex-end {
-ms-flex-item-align: end;
} @else {
-ms-flex-item-align: $value;
}
align-self: $value;
}
//----------------------------------------------------------------------
// Flexbox Align Content
//
// The 'align-content' property aligns a flex container's lines within the
// flex container when there is extra space in the cross-axis, similar to
// how 'justify-content' aligns individual items within the main-axis. Note,
// this property has no effect when the flexbox has only a single line.
//
// Values: flex-start | flex-end | center | space-between | space-around | stretch
// Default: stretch
//
// http://w3.org/tr/css3-flexbox/#align-content-property
@mixin align-content($value: stretch) {
// No Webkit Box Fallback.
-webkit-align-content: $value;
-moz-align-content: $value;
@if $value == flex-start {
-ms-flex-line-pack: start;
} @else if $value == flex-end {
-ms-flex-line-pack: end;
} @else {
-ms-flex-line-pack: $value;
}
align-content: $value;
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,289 @@
@import "parameters";
.page {
@include pageElement();
}
.mainPage {
// background-color: yellow;
}
.mainPage > #selectionPanel {
@include sliding-panel(left, $selectionPanelWidth);
&.open {
@include sliding-panel-open(left, $selectionPanelWidth);
}
}
#mainPanel {
// background-color: $yellow;
&.extra-wide {
@include sliding-panel-container();
.container {
@include flexbox;
}
.subpanel {
&.selection {
@include flex($selectionPanelWidth, 0);
// height: 100%;
overflow-y: scroll;
}
&.cardContent {
@include flex($cardContentPanelWidth);
@include flexbox;
@include flex-direction(column);
}
}
.selectionToggle {
.button {
display: none;
visibility: hidden;
}
}
}
&.wide, &.narrow {
.container {
@include sliding-panel-container();
}
}
&.narrow {
.column {
@include pageElement();
}
}
&.open.left {
@include sliding-panel-wrapper-open (left, $selectionPanelWidth);
@include mask();
}
&.open.right {
// @include sliding-panel-wrapper-open (right, $settingsPanelWidth);
@include mask();
}
}
#extraFeaturesPanel {
@include sliding-panel(right, $settingsPanelWidth);
&.open {
@include sliding-panel-open(right, $settingsPanelWidth);
}
}
.container {
height: 100%;
width: 100%;
}
.cardToolbarFrame {
height: 100%;
@include flexbox;
@include flex-direction(column);
.cardToolbar {
@include flex(none);
}
.cardContent {
}
}
div.cardToolbar {
// background-color: $orange;
header {
@include flexbox;
height: $mainCardToolbarHeight;
line-height: $mainCardToolbarHeight;
background-color: $clipperz-orange;
color: white;
font-size: 24pt;
div {
&.clipperz {
span.logo {
@include icon-font();
@include align-self(center);
@include flex(4);
text-align: center;
&.tag, &.search {
font-size: 14pt;
}
}
span.value {
display: inline-block;
padding-left: 5px;
font-size: 18pt;
}
}
&.selectionToggle {
@include flex(1);
.button {
text-align: left;
.label {
padding-left: 8px;
}
}
}
// &.logo {
// @include align-self(center);
// @include flex(4);
// text-align: center;
// }
&.settingsToggle {
@include flex(1);
.button {
text-align: right;
.label {
padding-right: 8px;
}
}
}
.button {
overflow: hidden;
font-size: 24pt;
@include icon-font();
vertical-align: center;
}
}
}
}
div.cardContent {
// @include flex(flex-grow); // ???
@include flexbox();
@include flex-direction(row);
div.cardListColumn.column {
@include flex($cardListWidth, 0);
overflow-y: scroll;
div.cardToolbar.narrow {
}
div.cardList {
overflow-y: scroll;
padding-bottom: 120px;
ul {
}
}
div.addCardButton {
@include icon-font();
@include border-radius(50px);
@include radial-gradient (white, rgba(0, 0, 0, 0));
position: relative;
bottom: 0px;
font-size: 75pt;
color: blue;
width: 100px;
height: 100px;
float: right;
position: absolute;
margin-left: 100px;
margin-bottom: 10px;
cursor: pointer;
}
}
div.cardDetail.column {
@include flex($cardDetailWidth);
@include flexbox();
div.view {
@include flex(auto);
@include flexbox;
@include flex-direction(column);
.cardDetailToolbar {
@include flex(none);
height: $mainCardToolbarHeight;
line-height: $mainCardToolbarHeight;
}
.content {
@include flex(auto);
overflow-y: scroll;
}
}
}
}
#cardDetailPage {
.view {
@include flexbox();
@include flex-direction(column);
height: 100%;
.cardDetailToolbar {
@include flex(none);
height: $mainCardToolbarHeight;
line-height: $mainCardToolbarHeight;
& > div {
@include flexbox();
@include flex-direction(row);
font-size: 24pt;
.back {
@include flex(auto);
cursor: pointer;
}
.cardMenuOptions {
@include flex(auto);
cursor: pointer;
}
}
}
.content {
@include flex(auto);
overflow-y: scroll;
}
}
}
.button {
cursor: pointer;
}

View File

@ -1,10 +1,19 @@
@mixin border-radius ($radius) {
border-radius: $radius;
-moz-border-radius: $radius;
-webkit-border-radius: $radius;
-moz-border-radius: $radius;
border-radius: $radius;
}
@mixin font-feature-settings($foo, $bar) {
@mixin radial-gradient ($inner-color, $outer-color) {
background-image: -ms-radial-gradient(center, circle farthest-corner, $inner-color 0%, $outer-color 100%); /* IE10 */
background-image: -moz-radial-gradient(center, circle farthest-corner, $inner-color 0%, $outer-color 100%); /* Mozilla Firefox */
background-image: -o-radial-gradient(center, circle farthest-corner, $inner-color 0%, $outer-color 100%); /* Opera */
background-image: -webkit-radial-gradient(center, circle farthest-corner, $inner-color 0%, $outer-color 100%); /* Webkit (Chrome 11+) */
background-image: radial-gradient(center, circle farthest-corner, $inner-color 0%, $outer-color 100%); /* Proposed W3C Markup */
background-image: -webkit-gradient(radial, center center, 0, center center, 495, color-stop(0, $inner-color), color-stop(1, $outer-color)); /* Webkit (Safari/Chrome 10) */
}
@mixin font-feature-settings ($foo, $bar) {
-webkit-font-feature-settings:"$foo","$bar";
-moz-font-feature-settings:"$foo=1, $bar=1";
-moz-font-feature-settings:"$foo","$bar";
@ -13,14 +22,14 @@
font-feature-settings:"$foo","$bar";
}
@mixin icon-font() {
@mixin icon-font () {
font-family: 'clipperz-icons';
@include font-feature-settings("liga", "dlig");
-webkit-font-smoothing: antialiased;
text-rendering:optimizeLegibility;
}
@mixin password-font() {
@mixin password-font () {
font-family: 'clipperz-password';
-webkit-font-smoothing: antialiased;
text-rendering:optimizeLegibility;
@ -60,10 +69,10 @@
@mixin transition ($item, $time, $function) {
-webkit-transition: $item $time $function;
-moz-transition: $item $time $function;
-o-transition: $item $time $function;
-ms-transition: $item $time $function;
transition: $item $time $function;
-moz-transition: $item $time $function;
-o-transition: $item $time $function;
-ms-transition: $item $time $function;
transition: $item $time $function;
}
@mixin transform ($rotateAngle, $translateX, $translateY) {
@ -74,6 +83,16 @@
transform: rotate( $rotateAngle) translate($translateX, $translateY);
}
@mixin transform3d ($tx, $ty, $tz) {
-webkit-transform: translate3d($tx, $ty, $tz);
transform: translate3d($tx, $ty, $tz);
}
@mixin transition-duration ($duration) {
-webkit-transition-duration: $duration;
transition-duration: $duration;
}
@mixin animation-delay ($delay) {
-webkit-animation-delay: $delay;
@ -91,7 +110,7 @@
box-shadow: $xOffset $yOffset $size $color;
}
@mixin keyframes($name) {
@mixin keyframes ($name) {
@-webkit-keyframes #{$name} {
@content;
}
@ -104,4 +123,21 @@
@keyframes #{$name} {
@content;
}
}
}
@mixin mask () {
.mask {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;
background-color: rgba(0, 0, 0, 0.5);
}
}
@include keyframes(spin) {
0% { @include transform(0deg, 0, 0); }
100% { @include transform(359deg, 0, 0); }
}

View File

@ -14,7 +14,7 @@ div.overlay {
.title {
color: #FFF;
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
// font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
font-weight: bold;
text-align: center;
display: block;

View File

@ -0,0 +1,44 @@
//
// SOLARIZED palette
// http://ethanschoonover.com/solarized
//
$solarize-Background-15: #002b36;
$solarize-Background-20: #073642;
$solarize-Content-45: #586375;
$solarize-Content-50: #657b83;
$solarize-Content-60: #839496;
$solarize-Content-65: #93a1a1;
$solarize-Background-92: #eee8d5;
$solarize-Background-97: #fdf6e3;
$solarize-Accent-Yellow: #b58900;
$solarize-Accent-Orange: #cb4b16;
$solarize-Accent-Red: #dc322f;
$solarize-Accent-Magenta: #d33682;
$solarize-Accent-Violet: #6c71c4;
$solarize-Accent-Blue: #268bd2;
$solarize-Accent-Cyan: #2aa198;
$solarize-Accent-Green: #859900;
// $yellow: $solarize-Accent-Yellow;
// $orange: $solarize-Accent-Orange;
// $red: $solarize-Accent-Red;
// $magenta: $solarize-Accent-Magenta;
// $violete: $solarize-Accent-Violet;
// $blue: $solarize-Accent-Blue;
// $cyan: $solarize-Accent-Cyan;
// $green: $solarize-Accent-Green;
$clipperz-orange: #ff9900;
$clipperz-blue: #1863a1;
$terminal-green: #23ff18;
$main-color: $clipperz-orange;
$main-text-color: black;
$main-alternate-color: black;
$main-alternate-text-color: white;

View File

@ -0,0 +1,15 @@
//$selectionPanelWidth: 200px;
//$cardListWidth: 200px;
$selectionPanelWidth: 1;
$cardContentPanelWidth: 4;
$mainCardToolbarHeight: 48px;
$cardListWidth: 1;
$cardDetailWidth: 2;
$selectionPanelWidth: 300px;
$settingsPanelWidth: 300px;

View File

@ -0,0 +1,43 @@
// Downloaded on June 11, 2014 from: https://gist.github.com/hcatlin/1027867
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
&:before, &:after, {
content: '';
content: none;
}
}
table {
border-collapse: collapse;
border-spacing: 0;
}

View File

@ -0,0 +1,52 @@
/*
Bootstrap CSS suggests these size breakpoints:
- Extra small devices Phones (<768px)
- Small devices Tablets (768px)
- Medium devices Desktops (992px)
- Large devices Desktops (1200px)
# ATTENTION
When adding a new 'size', remember to update also MQ.init invocation in main.js.
This configuration is now located in the first script included in the index_template.html file.
*/
@media only screen and (min-width: 100px) {
html {
font-family: "narrow";
}
body:after {
content: "narrow";
}
}
@media only screen and (min-width: 700px) {
html {
font-family: "wide";
}
body:after {
content: "wide";
}
}
@media only screen and (min-width: 1100px) {
html {
font-family: "extra-wide";
}
body:after {
content: "extra-wide";
}
}
@media only screen and (min-width: 100px) and (max-height: 450px) {
html {
font-family: "extra-short";
}
body:after {
content: "extra-short";
}
}

View File

@ -0,0 +1,27 @@
.accountStatus {
background-color: green;
&.FULL {
display: none;
visibility: hidden;
&.isExpiring {
display: block;
visibility: visible;
background-color: yellow;
}
}
&.TRIAL {
background-color: orange;
&.isExpiring {
background-color: red;
}
}
&.EXPIRED {
background-color: red;
}
}

View File

@ -0,0 +1,270 @@
$cardListHeight: 48px;
$faviconSize: 32px;
$padding: ($cardListHeight - $faviconSize) / 2;
$cardToolbarBackgroundColor: brown;
div.cardList {
// background-color: $yellow;
&.loadingCard {
li.selected {
background-color: gray;
}
}
ul {
li.selected {
background-color: yellow;
}
li {
cursor: pointer;
border-bottom: 1px solid #eee;
@include flexbox();
@include flex-direction(row);
.favicon {
width: $cardListHeight;
@include flex(none);
img {
width: $faviconSize;
height: $faviconSize;
padding: $padding;
}
}
.label {
@include flex(auto);
font-size: 18pt;
padding-top: 0.5em;
padding-bottom: 0.5em;
padding-left: $padding;
padding-right: $padding;
}
}
}
}
div.cardList.narrow {
&.loadingCard {
li.selected {
// background-color: gray;
&:after {
color: white;
margin-right: 10px;
content: "loading";
@include animation(spin, 1s, linear, infinite);
}
}
}
ul {
li {
&:after {
content: "show detail";
@include flex(none);
@include icon-font();
height: 48px;
font-size: 24pt;
line-height: 48px;
margin-right: 25px;
}
}
}
}
$cardViewBasePadding: 10px;
#cardDetailPage, .cardDetail {
.loading {
// height: 100%;
// width: 100%;
// background-color: rgba(0,0,0,0.5);
}
.view {
.cardDetailToolbar {
ul {
@include flexbox();
@include flex-direction(row);
li {
@include flex(auto);
text-align: center;
span {
cursor: pointer;
}
}
}
&.narrow {
.back {
@include icon-font();
}
.cardMenuOptions {
@include icon-font();
text-align: right;
font-size: 18pt;
padding-right: 10px;
}
.commandMenu {
// display: none;
.commandMenuMask {
display: none;
}
.commandMenu {
display: none;
}
&.show {
.commandMenuMask {
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0);
}
.commandMenu {
display: block;
float: right;
position: absolute;
min-width: 200px;
top: 48px;
right: 5px;
color: black;
background-color: white;
@include box-shadow(0px, 2px, 5px, rgba(50, 50, 50, 0.75));
ul {
@include flex-direction(column);
li {
text-align: left;
font-size: 18pt;
padding: 5px 10px;
border-bottom: 1px solid black;
}
}
}
}
}
}
}
}
}
.cardDetailToolbar {
background-color: $cardToolbarBackgroundColor;
color: white;
&.narrow {
.cardMenuOptions {
margin-right: 5px;
}
}
}
.content {
.cardLabel {
font-size: 24pt;
padding: $cardViewBasePadding;
}
.cardTags {
@include flexbox();
@include flex-direction(row);
@include align-items(flex-start);
padding: $cardViewBasePadding;
.cardTag {
@include flex(none);
font-size: 14pt;
padding-right: 10px;
&:before {
content: 'tag';
@include icon-font();
font-size: 10pt;
padding-right: 4px;
}
}
}
.cardNotes {
padding: $cardViewBasePadding;
}
.cardField {
@include flexbox;
@include flex-direction(row);
.fieldValues {
@include flex(1);
padding: $cardViewBasePadding;
.fieldLabel {
color: gray;
}
.fieldValue {
font-size: 18pt;
&.hidden {
font-family: clipperz-password;
}
}
}
.fieldAction {
@include flex(none);
@include align-self(center);
}
.action {
width: 32px;
height: 32px;
@include icon-font();
font-size: 20pt;
}
}
.cardDirectLogin {
font-size: 18pt;
padding: $cardViewBasePadding;
background-color: pink;
cursor: pointer;
}
}

View File

@ -0,0 +1,32 @@
// $Loading_outer_color: $main-color;
// $Loading_inner-color: lighten($Loading_outer-color, 30%);
//
// $Loading_h1-color: lighten($Loading_inner-color, 70%);
// $Loading_h3-color: darken($Loading_outer-color, 20%);
#loadingPage {
// @include radial-gradient($Loading_inner-color, $Loading_outer-color);
background-color: $main-color;
div {
vertical-align: middle;
width: 100%;
text-align: center;
h1 {
font-size: 40pt;
font-weight: bold;
// color: $Loading_h1-color;
color: $main-alternate-text-color;
margin-top: 10%;
margin-bottom: 5px;
}
h3 {
font-size: 18pt;
// color: $Loading_h3-color;
color: $main-text-color;
margin: 0px;
}
}
}

View File

@ -0,0 +1,151 @@
#loginPage {
overflow: scroll;
div.loginForm {
@include flexbox;
@include flex-direction(column);
@include align-items(stretch);
height: 100%;
text-align: center;
background-color: $main-color;
header {
@include flex(1);
@include icon-font();
font-size: 48pt;
color: $main-alternate-text-color;
}
div.form {
@include flex(4);
margin-left: auto;
margin-right: auto;
form {
position: relative;
background: $main-alternate-text-color;
// @include border-radius(10px);
padding: 20px;
margin-bottom: 50px;
/*
&:after {
content: "";
position: absolute;
top: -15px;
margin-left: 50%;
left: -15px;
border-style: solid;
border-width: 0 15px 15px;
border-color: $main-alternate-text-color transparent;
display: block;
width: 0;
z-index: 1;
}
*/
label {
display: none;
}
input {
font-family: "clipperz-font";
display: block;
// @include border-radius(4px);
padding: 5px;
margin-top: 5px;
margin-bottom: 10px;
font-size: 100%;
// box-shadow:inset 0 0 0;
font-size: 24pt;
width: 100%;
}
button {
font-family: "clipperz-font";
min-height: 48px;
min-width: 48px;
color: white;
font-size: 24pt;
font-weight: 500;
border: 0px;
padding: 10px 25px;
border: 1px solid white;
background-color: $main-color;
@include transition(background-color font-weight, 0.2s, linear);
&:hover {
};
&:disabled {
font-weight: 100;
background-color: #c0c0c0;
cursor: default;
&:hover {
};
}
}
}
}
div.registrationLink {
@include flex(1);
color: $main-alternate-text-color;
background-color: $main-alternate-color;
cursor: pointer;
font-size: 24pt;
&:before {
content: "> ";
};
a {
}
}
}
div.loginForm.extra-short {
header {
// @include flex(1);
font-size: 18pt;
}
div.form {
// @include flex(6);
form {
padding: 10px;
margin-bottom: 20px;
input {
padding: 3px;
margin-top: 3px;
margin-bottom: 5px;
font-size: 16pt;
}
button {
min-height: 20px;
font-size: 12pt;
padding: 3px 10px;
border: 1px solid white;
}
}
}
div.registrationLink {
// @include flex(2);
font-size: 14pt;
}
}
}

View File

@ -0,0 +1,111 @@
#registrationPage {
background-color: $main-alternate-color;
color: $main-alternate-text-color;
label {
display: none;
}
input {
display: block;
border: 1px solid $solarize-Background-92;
@include border-radius(6px);
padding: 5px;
margin-top: 5px;
margin-bottom: 10px;
font-size: 100%;
box-shadow:inset 0 0 0;
}
.steps {
.step {
display: none;
&.center {
display: block;
}
h1 {
color: $solarize-Accent-Blue;
font-size: 24pt;
font-weight: 700;
margin: 0px;
}
p {
color: $solarize-Content-50;
font-size: 14pt;
font-weight: 100;
margin: 0px;
}
&.TERMS_OF_SERVICE {
.checkboxBlock {
margin-top: 10px;
margin-bottom: 10px;
clear: both;
input {
display: block;
float: left;
margin: 5px;
width: 30px;
}
p {
font-size: 12pt;
font-weight: 500;
display: block;
a {
color: $solarize-Accent-Red;
}
}
}
}
.stepIndex {
text-align: center;
.stepIndexItem {
font-weight: 900;
font-size: 28pt;
display: inline;
color: lightgrey;
&.center {
color: gray;
}
}
}
.buttons {
text-align: center;
margin-top: 10px;
.button {
margin: 10px;
text-align: center;
vertical-align: middle;
display: inline-block;
width: 80px;
font-weight: 900;
line-height: 45px;
font-size: 24px;
&.back {
background-color: lightgrey;
// &.step_-1 {
// visibility: hidden;
// }
}
&.disabled {
background-color: #c0c0c0;
cursor: default;
}
}
}
}
}
}

View File

@ -0,0 +1,69 @@
#selections {
background-color: $main-alternate-color;
color: $main-alternate-text-color;
font-size: 18pt;
overflow: scroll;
height: 100%;
$iconColumnWidth: 40px;
ul.defaultSet {
font-weight: bold;
padding-top: 10px;
padding-bottom: 10px;
li {
&.allCards:before {
content: "clipperz";
}
&.recentCards:before {
content: "recent";
}
}
}
.search {
label {
@include icon-font();
font-size: 18pt;
padding-left: 5px;
padding-right:5px;
}
input {
font-family: "clipperz-font";
color: #999;
font-size: 18pt;
width: $selectionPanelWidth - $iconColumnWidth - 10px;
}
}
ul.tagList {
padding-top: 10px;
li {
&:before {
content: "tag";
}
}
}
li {
padding-left: 35px;
text-indent: -35px;
padding-top: 7px;
padding-bottom: 7px;
cursor: pointer;
&:before {
@include icon-font();
font-weight: normal;
padding-left: 8px;
padding-right: 8px;
font-size: 14pt;
}
}
}

View File

@ -0,0 +1,19 @@
#extraFeaturesPanel {
background-color: $main-alternate-color;
color: $main-alternate-text-color;
header {
text-align: right;
height: 48px;
font-size: 24pt;
.button {
@include icon-font();
.label {
padding-top: 8px;
padding-right: 8px;
}
}
}
}

View File

@ -1,10 +0,0 @@
@import "web/fonts";
@import "web/overlay";
@import "web/behavior";
@import "web/style";
@import "web/checkbox";
@import "web/480";
@import "web/768";
@import "web/992";
@import "web/add2home";

View File

@ -1,11 +0,0 @@
@media only screen and (min-width: 480px) {
.loginForm {
font-size: 1.2em;
input {
}
button {
}
}
}

View File

@ -1,3 +0,0 @@
@media only screen and (min-width: 768px) {
}

View File

@ -1,2 +0,0 @@
@media only screen and (min-width: 992px) {
}

View File

@ -1,160 +0,0 @@
/**
*
* Main container
*
*/
#addToHomeScreen {
z-index:9999;
-webkit-user-select:none;
user-select:none;
-webkit-box-sizing:border-box;
box-sizing:border-box;
-webkit-touch-callout:none;
touch-callout:none;
width:240px;
font-size:15px;
padding:12px 14px;
text-align:left;
font-family:helvetica;
background-image:-webkit-gradient(linear,0 0,0 100%,color-stop(0,#fff),color-stop(0.02,#eee),color-stop(0.98,#ccc),color-stop(1,#a3a3a3));
border:1px solid #505050;
-webkit-border-radius:8px;
-webkit-background-clip:padding-box;
color:#333;
text-shadow:0 1px 0 rgba(255,255,255,0.75);
line-height:130%;
-webkit-box-shadow:0 0 4px rgba(0,0,0,0.5);
}
#addToHomeScreen.addToHomeIpad {
width:268px;
font-size:18px;
padding:14px;
}
/**
*
* The 'wide' class is added when the popup contains the touch icon
*
*/
#addToHomeScreen.addToHomeWide {
width:296px;
}
#addToHomeScreen.addToHomeIpad.addToHomeWide {
width:320px;
font-size:18px;
padding:14px;
}
/**
*
* The balloon arrow
*
*/
#addToHomeScreen .addToHomeArrow {
position:absolute;
background-image:-webkit-gradient(linear,0 0,100% 100%,color-stop(0,rgba(204,204,204,0)),color-stop(0.4,rgba(204,204,204,0)),color-stop(0.4,#ccc));
border-width:0 1px 1px 0;
border-style:solid;
border-color:#505050;
width:16px; height:16px;
-webkit-transform:rotateZ(45deg);
bottom:-9px; left:50%;
margin-left:-8px;
-webkit-box-shadow:inset -1px -1px 0 #a9a9a9;
-webkit-border-bottom-right-radius:2px;
}
/**
*
* The balloon arrow for iPad
*
*/
#addToHomeScreen.addToHomeIpad .addToHomeArrow {
-webkit-transform:rotateZ(-135deg);
background-image:-webkit-gradient(linear,0 0,100% 100%,color-stop(0,rgba(238,238,238,0)),color-stop(0.4,rgba(238,238,238,0)),color-stop(0.4,#eee));
-webkit-box-shadow:inset -1px -1px 0 #fff;
top:-9px; bottom:auto; left:50%;
}
/**
*
* Close button
*
*/
#addToHomeScreen .addToHomeClose {
-webkit-box-sizing:border-box;
position:absolute;
right:4px;
top:4px;
width:18px;
height:18px; line-height:14px;
text-align:center;
text-indent:1px;
-webkit-border-radius:9px;
background:rgba(0,0,0,0.12);
color:#707070;
-webkit-box-shadow:0 1px 0 #fff;
font-size:16px;
}
/**
*
* The '+' icon, displayed only on iOS < 4.2
*
*/
#addToHomeScreen .addToHomePlus {
font-weight:bold;
font-size:1.3em;
}
/**
*
* The 'share' icon, displayed only on iOS >= 4.2
*
*/
#addToHomeScreen .addToHomeShare {
display:inline-block;
width:18px;
height:15px;
background-repeat:no-repeat;
background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAeCAQAAADu6HTYAAADPElEQVR4Xq3TX2gcRRzA8e/M7mVv2+TSNpc/TZtrY6jUGqgaSAmEChKLrYK0YH0RFC2CSCkEfCghiKU04J8qNigq6os+iQV98MHWFwVBrQQRWs21lBw5cw3NNb1/udu72RGG5Y77IzXW77D7sAwf5scyYoL6BGXSDKFZwaGpLvIUaeoCkvX1MmsM0Ny6oRSQYOLuIS+YZOpfQdqslpUxcZrzTVAz4qPwW2O3CeIwC/RSzeY6Ow1QhUrkr+YOWfEKDkEP8Rij7CHKJmrFSDHBdwGEE5wiGChPN+PnT8VdRtEIl1d4gRj/1EVe5ZSBKGh8iqQpo/Fo5+3C/gz0MYg4zgwbqday1/Q4B8BGQ45d/Hi54lakCrU5obOcidJpu1+Lg9whjabyaOYLnrIBFFaRD+xe2ybMDWY66GmP/WA9cGfGp0CWhy0wkMN8inepFiH2rV1j0NQSNQbFLRQnS8/8YSDBBpadfv4CYDub2fmeHDNAsL1MBWUel0iA+Xik6eHcyvD3vAMSU1TGuA/YRS+dD7ovCQN43GKRFCU20Kd3V/avDVVyAZ5niTEuLA5/zBGWg9EEEhfJKN200Tat8CmRAQb9+wv7soPlHt2tQorsz1uPbr0HTY4sJwrH47zJZwABBAKLMBoQXepwgTwdHCo+fXMkQ4lrxEmQ5AaXipPqDY9V2vn09tgvTPI71EEGYxM+/uMJLJ4svpgaWGKOi/xKgmqLSUGSUd5f2vIVJ/CgBaTIUsZ7ZBsn0+NzfMOXLFCXQyTcybN6ep5ZZgUOHn7jpfUpsZshdugPGf+E5zjbyHTSRyQ8xfRPPM/s63RHeuknSoT22mjmmnAOIMkUZ6D1xSfPPAfd1WFKM3sO2CMaHx8M1NjnXKHaAGGkOW0C02WeYHUz4qMtx+w5gUDS8NckYe5lHsMYwCZEPyEEmjLDZFmAS7CDviMdxyTkMNVBKEmYLvbiQQBIBBbCQG04bGQvFWz6CfsCQLWCigILFwcfkGYBiOpbYuOizTAyYyDdCtrGaRG1LCkIgMYEFhI0WqQZoSlbGRyHKe4qOx7iv2bVQW9dp4dlM/x6kmwnWQcd/Q3FCqwTEiT5s+6D5v/pb0SSHyg7uhMWAAAAAElFTkSuQmCC);
background-size:18px 15px;
text-indent:-9999em;
overflow:hidden;
}
#addToHomeScreen .addToHomeShare.addToHomeShareOS7 {
width:11px;
background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAAA8CAYAAAAQTCjdAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAASCQAAEgkB80sG3AAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAKjSURBVGiB7dpPiFVVHMDxz7m9NCtMyI2bEJEC25WrEkzHUXCRraIwdNE8ZxfYIlcis1ZEbGEzT1QCF4XgH1CyWhUoJKIWNRGEiCNKmkSiYTzfcfGuOokx77x3ZlS8382959zfn+/invvn3RdijHIRBrwkOINCYXEcdjpb7VyiYdBsLScwt5y6IloYdzqXo36Ro0gY9IKWo+5JwmzBt2HQnBw9ehYNazyn5TBee8Dh+Vq+CWu92GufnkTDR6ab7gDeBNHouMM/l9tXTXM0fGBmL726Fg1Dam74EsvKqR8VNowL2Yzj5f7rnnE4DHq2235diYYhhTGfC94up35T0y+6di/ITU0rKVd+sEi0P7xr2pSJOu8zvF+OzqEv7vDH/WFxt7/cshy/ticsN8sXYUht0kXDOlsF9XJ4UaEvNoz9X3zc5bKaZThbyr5jzJ4wlNY7KTgM+ES0vhz+KeiPw36fKC/ucAF9uFBOrTZm26SJCtaV27+xIo7cXdkTEhvOoh+XyxprU1qnim7CQdGK2HAyKRexYVShT3RItDElN+mkjiP2Ym+S3f01hv2EVal5WW6hU0ElmptaqJuBpXg6MbeFH2LDpU6CQ93zWIKnEvs0cayGU3glMfkOo1jQYewZzOuyz7FC95Jwo5OgUFfgeg993hh/eTqCTxOSm/iuk8DY0Ap1b2GhtHXxsfZN4j/X0fOx4auEIknEhqv4OiUn1L13Z/+xWfWVaG4q0dxUormpRHNTieamEs1NJZqbJ1Q0jHvdiJo5S2cVjSNOCHZhn3/SnuYnIvl3yomIIz7MXZMn9hydRCrR3FSiualEc1OJ5qYSzU0lmptKNDePjWgwcPePT7/g+4cp8wCW4GXaryK3tL+mLdD5x62ppllgu7bso8q/2HIbzGWdNmWnSJwAAAAASUVORK5CYII=);
background-size:11px 15px;
}
/**
*
* The touch icon (if available)
*
*/
#addToHomeScreen .addToHomeTouchIcon {
display:block;
float:left;
-webkit-border-radius:6px;
border-radius:6px;
-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.5),
inset 0 0 2px rgba(255,255,255,0.9);
box-shadow:0 1px 3px rgba(0,0,0,0.5),
inset 0 0 2px rgba(255,255,255,0.9);
background-repeat:no-repeat;
width:57px; height:57px;
-webkit-background-size:57px 57px;
background-size:57px 57px;
margin:0 12px 0 0;
border:1px solid #333;
-webkit-background-clip:padding-box;
background-clip:padding-box;
}

View File

@ -1,111 +0,0 @@
// https://github.com/h5bp/Effeckt.css
@mixin slide () {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
&.left {
-webkit-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
}
&.center {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
&.right {
-webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
visibility: hidden;
display: none;
&.transition {
visibility: visible;
display: block;
}
}
&.transition {
-webkit-transition-duration: .25s;
transition-duration: .25s;
}
}
// http://coenraets.org/blog/2013/03/hardware-accelerated-page-transitions-for-mobile-web-apps-phonegap-apps/
.page {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
@include slide();
}
/*
.registrationForm {
.steps {
.step {
position: absolute;
// top: 0;
// left: 0;
// width: 100%;
// height: 100%;
.slide();
}
}
}
*/
//----------------------------------------------------------------------
// tentative 3D transformations
/*
.page {
transform: rotateY( 0deg) translateZ( 100px);
&.left {
transform: rotateY( -90deg) translateZ( 100px);
}
&.center {
transform: rotateY( 0deg) translateZ( 100px);
}
&.right {
transform: rotateY( 90deg) translateZ( 100px);
}
}
#mainDiv {
width: 100%;
height: 100%;
position: absolute;
transform-style: preserve-3d;
transition: transform 3s;
&.show-front { transform: translateZ( -100px ) rotateY( 0deg ); }
&.show-back { transform: translateZ( -100px ) rotateX( -180deg ); }
&.show-right { transform: translateZ( -100px ) rotateY( -90deg ); }
&.show-left { transform: translateZ( -100px ) rotateY( 90deg ); }
&.show-top { transform: translateZ( -100px ) rotateX( -90deg ); }
&.show-bottom { transform: translateZ( -100px ) rotateX( 90deg ); }
}
*/
//=======================================================================
//=======================================================================
//========================================================

View File

@ -1,96 +0,0 @@
div.checkbox {
display: block;
margin-bottom: 20px;
@include border-radius(4px);
border: 2px solid white;
background-color: white;
width: 80px;
position: relative;
height: 32px;
&:before {
content: "ON";
padding-left: 9px;
line-height: 32px;
color: $solarize-Accent-Cyan;
font-size: 14px;
font-weight: 600;
}
&:after {
content: "OFF";
// padding-left: 12px;
padding-left: 25px;
line-height: 32px;
color: $solarize-Accent-Cyan;
font-size: 14px;
font-weight: 600;
}
label.check {
display: block;
width: 40px;
height: 30px;
@include border-radius(3px);
background-color: $solarize-Accent-Magenta;
border: 1px solid $solarize-Accent-Magenta;
position: absolute;
top: 0px;
left: 0px;
}
input[type=checkbox] {
display: none;
}
input[type=checkbox]:checked + label.check {
top: 0px;
left: 38px;
@include animation(labelON, .2s, ease-in, 1);
}
input[type=checkbox] + label.check {
top: 0px;
left: 0px;
@include animation(labelOFF, .2s, ease-in, 1);
}
label.info {
position: absolute;
color: white;
top: 0px;
left: 100px;
line-height: 32px;
width: 200px;
font-size: 16pt;
}
}
@include keyframes(labelON) {
0% {
top: 0px;
left: 0px;
}
100% {
top: 0px;
left: 38px;
}
}
@include keyframes(labelOFF) {
0% {
top: 0px;
left: 38px;
}
100% {
top: 0px;
left: 0px;
}
}

View File

@ -1,138 +0,0 @@
// --------------------------------------------------
// Flexbox LESS mixins
// The spec: http://www.w3.org/TR/css3-flexbox
//
// Other info:
// - http://philipwalton.github.io/solved-by-flexbox/
// --------------------------------------------------
// Flexbox display
// flex or inline-flex
.flex-display(@display: flex) {
display: ~"-webkit-@{display}";
display: ~"-moz-@{display}";
display: ~"-ms-@{display}box"; // IE10 uses -ms-flexbox
display: ~"-ms-@{display}"; // IE11
display: @display;
}
// The 'flex' shorthand
// - applies to: flex items
// <positive-number>, initial, auto, or none
.flex(@columns: initial) {
-webkit-flex: @columns;
-moz-flex: @columns;
-ms-flex: @columns;
flex: @columns;
}
// Flex Flow Direction
// - applies to: flex containers
// row | row-reverse | column | column-reverse
.flex-direction(@direction: row) {
-webkit-flex-direction: @direction;
-moz-flex-direction: @direction;
-ms-flex-direction: @direction;
flex-direction: @direction;
}
// Flex Line Wrapping
// - applies to: flex containers
// nowrap | wrap | wrap-reverse
.flex-wrap(@wrap: nowrap) {
-webkit-flex-wrap: @wrap;
-moz-flex-wrap: @wrap;
-ms-flex-wrap: @wrap;
flex-wrap: @wrap;
}
// Flex Direction and Wrap
// - applies to: flex containers
// <flex-direction> || <flex-wrap>
.flex-flow(@flow) {
-webkit-flex-flow: @flow;
-moz-flex-flow: @flow;
-ms-flex-flow: @flow;
flex-flow: @flow;
}
// Display Order
// - applies to: flex items
// <integer>
.flex-order(@order: 0) {
-webkit-order: @order;
-moz-order: @order;
-ms-order: @order;
order: @order;
}
// Flex grow factor
// - applies to: flex items
// <number>
.flex-grow(@grow: 0) {
-webkit-flex-grow: @grow;
-moz-flex-grow: @grow;
-ms-flex-grow: @grow;
flex-grow: @grow;
}
// Flex shr
// - applies to: flex itemsink factor
// <number>
.flex-shrink(@shrink: 1) {
-webkit-flex-shrink: @shrink;
-moz-flex-shrink: @shrink;
-ms-flex-shrink: @shrink;
flex-shrink: @shrink;
}
// Flex basis
// - the initial main size of the flex item
// - applies to: flex itemsnitial main size of the flex item
// <width>
.flex-basis(@width: auto) {
-webkit-flex-basis: @width;
-moz-flex-basis: @width;
-ms-flex-basis: @width;
flex-basis: @width;
}
// Axis Alignment
// - applies to: flex containers
// flex-start | flex-end | center | space-between | space-around
.justify-content(@justify: flex-start) {
-webkit-justify-content: @justify;
-moz-justify-content: @justify;
-ms-justify-content: @justify;
justify-content: @justify;
}
// Packing Flex Lines
// - applies to: multi-line flex containers
// flex-start | flex-end | center | space-between | space-around | stretch
.align-content(@align: stretch) {
-webkit-align-content: @align;
-moz-align-content: @align;
-ms-align-content: @align;
align-content: @align;
}
// Cross-axis Alignment
// - applies to: flex containers
// flex-start | flex-end | center | baseline | stretch
.align-items(@align: stretch) {
-webkit-align-items: @align;
-moz-align-items: @align;
-ms-align-items: @align;
align-items: @align;
}
// Cross-axis Alignment
// - applies to: flex items
// auto | flex-start | flex-end | center | baseline | stretch
.align-self(@align: auto) {
-webkit-align-self: @align;
-moz-align-self: @align;
-ms-align-self: @align;
align-self: @align;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,164 @@
/*
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/.
*/
MochiKit.Base.update(Clipperz.Async.Deferred.prototype, {
/*
'_addTest': function(anExpectedValue, aDescription, isDeep, aResult) {
if (isDeep) {
SimpleTest.isDeeply(aResult, anExpectedValue, aDescription);
} else {
SimpleTest.is(aResult, anExpectedValue, aDescription);
}
return aResult;
},
*/
'addTest': function (anExpectedValue, aDescription, isDeep) {
// this.addMethod(this, '_addTest', anExpectedValue, aDescription, isDeep);
// this.addCallback(Clipperz.Async.test, anExpectedValue, aDescription, isDeep);
if (isDeep) {
// SimpleTest.isDeeply(aResult, anExpectedValue, aDescription);
this.addCallback(Clipperz.Async.Test.isDeeply(anExpectedValue, aDescription));
} else {
// SimpleTest.is(aResult, anExpectedValue, aDescription);
this.addCallback(Clipperz.Async.Test.is(anExpectedValue, aDescription));
}
},
//-------------------------------------------------------------------------
'shouldSucceed': function (aDescription) {
this.addCallbackPass(SimpleTest.ok, true, aDescription);
this.addErrbackPass (SimpleTest.ok, false, aDescription);
this.addBoth(MochiKit.Async.succeed, null);
},
'shouldFail': function (aDescription) {
this.addCallbackPass(SimpleTest.ok, false, aDescription);
this.addErrbackPass (SimpleTest.ok, true, aDescription);
this.addBoth(MochiKit.Async.succeed, null);
},
//-------------------------------------------------------------------------
});
Clipperz.Async.Test = {};
MochiKit.Base.update(Clipperz.Async.Test, {
'is': function (anExpectedResult, aDescription) {
return MochiKit.Base.partial(function (anExpectedResult, aDescription, aResult) {
SimpleTest.is(aResult, anExpectedResult, aDescription);
return aResult;
}, anExpectedResult, aDescription);
},
//-------------------------------------------------------------------------
'ok': function (aDescription) {
return MochiKit.Base.partial(function (aDescription, aResult) {
SimpleTest.ok(aResult, aDescription);
return aResult;
}, aDescription);
},
//-------------------------------------------------------------------------
'fail': function(aDescription) {
return MochiKit.Base.partial(function (aDescription, aResult) {
SimpleTest.ok(!aResult, aDescription);
return aResult;
}, aDescription);
},
//-------------------------------------------------------------------------
'isDeeply': function (anExpectedResult, aDescription) {
return MochiKit.Base.partial(function (anExpectedResult, aDescription, aResult) {
SimpleTest.isDeeply(aResult, anExpectedResult, aDescription);
return aResult;
}, anExpectedResult, aDescription);
},
//-------------------------------------------------------------------------
__syntaxFix__: "syntax fix"
});
SimpleTest.runDeferredTests = function (aName, aTestSet, aTestArguments) {
try {
var deferredTests;
var aTestName;
var title;
deferredTests = new Clipperz.Async.Deferred(aName + " <deferred test set>", aTestArguments);
title = aName;
aTestName = window.location.href.match(/#.*/);
if (aTestName && (aTestName != '#')) {
aTestName = aTestName[0].slice(1);
if (aTestName in aTestSet) {
//Clipperz.log("single test execution, via fragment identifier", aTestName);
title += ' [' + aTestName + ']';
deferredTests.addCallback(aTestSet[aTestName], aTestArguments);
deferredTests.addErrback(SimpleTest.ok, false, aTestName);
} else {
title = 'WRONG TEST NAME'
deferredTests.addBoth(is, aTestName, null, "Wrong test name selected to run");
}
} else {
for (aTestName in aTestSet) {
deferredTests.addCallback(aTestSet[aTestName], aTestArguments);
deferredTests.addErrback(SimpleTest.ok, false, aTestName);
deferredTests.addBoth(MochiKit.Async.wait, 0.5);
}
deferredTests.addBoth(is, true, true, "FINISH: completed the full stack of tests");
}
MochiKit.DOM.currentDocument().title = title;
deferredTests.addBoth(SimpleTest.finish);
deferredTests.callback();
SimpleTest.waitForExplicitFinish();
} catch (err) {
var s = "test suite failure!\n";
var o = {};
var k = null;
for (k in err) {
// ensure unique keys?!
if (!o[k]) {
s += k + ": " + err[k] + "\n";
o[k] = err[k];
}
}
ok ( false, s );
}
}

View File

@ -0,0 +1,447 @@
/*
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/.
*/
/**
* SimpleTest, a partial Test.Simple/Test.More API compatible test library.
*
* Why?
*
* Test.Simple doesn't work on IE < 6.
* TODO:
* * Support the Test.Simple API used by MochiKit, to be able to test MochiKit
* itself against IE 5.5
*
**/
if (typeof(SimpleTest) == "undefined") {
var SimpleTest = {};
}
// Check to see if the TestRunner is present and has logging
if (typeof(parent) != "undefined" && parent.TestRunner) {
SimpleTest._logEnabled = parent.TestRunner.logEnabled;
}
SimpleTest._tests = [];
SimpleTest._stopOnLoad = true;
SimpleTest._scopeCopy = {};
/**
* Saves a copy of the specified scope variables.
*/
SimpleTest.saveScope = function (scope) {
SimpleTest._scopeCopy = {};
for (var k in scope) {
SimpleTest._scopeCopy[k] = scope[k];
}
}
/**
* Verifies the specified scope against the stored copy and reports
* any differences as test failures.
*/
SimpleTest.verifyScope = function (scope) {
var filter = ['test', '_firebug','_FirebugConsole','XMLHttpRequest','Audio',
'XSLTProcessor','Option','Image','scrollMaxX','scrollMaxY',
'clipboardData'];
for (var k in scope) {
if (MochiKit.Base.findValue(filter, k) < 0) {
var v = scope[k];
var old = SimpleTest._scopeCopy[k];
if (v !== old && typeof(old) === "undefined") {
SimpleTest.ok(false, "scope modified, variable " + k + " was added");
} else if (v !== old) {
SimpleTest.ok(false, "scope modified, variable " + k + " changed from: " + old + ", to: " + v);
}
}
}
for (var k in SimpleTest._scopeCopy) {
if (!(k in scope)) {
SimpleTest.ok(false, "scope modified, variable " + k + " has been removed");
}
}
}
/**
* Something like assert.
*/
SimpleTest.ok = function (condition, name, diag) {
var test = {'result': !!condition, 'name': name, 'diag': diag || ""};
if (SimpleTest._logEnabled) {
var msg = test.result ? "PASS" : "FAIL";
msg += " | " + test.name;
if (test.result) {
parent.TestRunner.logger.log(msg);
} else {
msg += " | " + test.diag;
parent.TestRunner.logger.error(msg);
}
}
SimpleTest._tests.push(test);
};
/**
* Roughly equivalent to ok(a==b, name)
*/
SimpleTest.is = function (a, b, name) {
var repr = MochiKit.Base.repr;
SimpleTest.ok(a == b, name, "got " + repr(a) + ", expected " + repr(b));
};
/**
* Roughly equivalent to ok(compare(a,b)==0, name)
*/
SimpleTest.eq = function (a, b, name) {
var base = MochiKit.Base;
var repr = base.repr;
try {
SimpleTest.ok(base.compare(a, b) == 0, name, "got " + repr(a) + ", expected " + repr(b));
} catch (e) {
SimpleTest.ok(false, name, "exception in compare: " + repr(e));
}
};
/**
* Makes a test report, returns it as a DIV element.
**/
SimpleTest.report = function () {
var DIV = MochiKit.DOM.DIV;
var passed = 0;
var failed = 0;
var results = MochiKit.Base.map(
function (test) {
var cls, msg;
if (test.result) {
passed++;
cls = "test_ok";
msg = "ok - " + test.name;
} else {
failed++;
cls = "test_not_ok";
msg = "not ok - " + test.name;
if (test.diag != null && test.diag != "") {
msg += ": " + test.diag;
}
}
return DIV({"class": cls}, msg);
},
SimpleTest._tests
);
var summary_class = ((failed == 0) ? 'all_pass' : 'some_fail');
return DIV({'class': 'tests_report'},
DIV({'class': 'tests_summary ' + summary_class},
DIV({'class': 'tests_passed'}, "Passed: " + passed),
DIV({'class': 'tests_failed'}, "Failed: " + failed)),
results
);
};
/**
* Toggle element visibility
**/
SimpleTest.toggle = function(el) {
if (MochiKit.Style.getStyle(el, 'display') == 'block') {
el.style.display = 'none';
} else {
el.style.display = 'block';
}
};
/**
* Toggle visibility for divs with a specific class.
**/
SimpleTest.toggleByClass = function (cls) {
var elems = MochiKit.DOM.getElementsByTagAndClassName('div', cls);
MochiKit.Base.map(SimpleTest.toggle, elems);
return false;
};
/**
* Shows the report in the browser
**/
SimpleTest.showReport = function() {
var base = MochiKit.Base;
var dom = MochiKit.DOM;
var togglePassed = dom.A({'href': '#'}, "Toggle passed tests");
var toggleFailed = dom.A({'href': '#'}, "Toggle failed tests");
togglePassed.onclick = base.partial(SimpleTest.toggleByClass, 'test_ok');
toggleFailed.onclick = base.partial(SimpleTest.toggleByClass, 'test_not_ok');
var body = document.getElementsByTagName("body")[0];
var firstChild = body.childNodes[0];
var addNode;
if (firstChild) {
addNode = function (el) {
body.insertBefore(el, firstChild);
};
} else {
addNode = function (el) {
body.appendChild(el)
};
}
addNode(togglePassed);
addNode(dom.SPAN(null, " "));
addNode(toggleFailed);
addNode(SimpleTest.report());
};
/**
* Tells SimpleTest to don't finish the test when the document is loaded,
* useful for asynchronous tests.
*
* When SimpleTest.waitForExplicitFinish is called,
* explicit SimpleTest.finish() is required.
**/
SimpleTest.waitForExplicitFinish = function () {
SimpleTest._stopOnLoad = false;
};
/**
* Talks to the TestRunner if being ran on a iframe and the parent has a
* TestRunner object.
**/
SimpleTest.talkToRunner = function () {
if (typeof(parent) != "undefined" && parent.TestRunner) {
parent.TestRunner.testFinished(document);
}
};
/**
* Finishes the tests. This is automatically called, except when
* SimpleTest.waitForExplicitFinish() has been invoked.
**/
SimpleTest.finish = function () {
SimpleTest.showReport();
SimpleTest.talkToRunner();
};
MochiKit.DOM.addLoadEvent(function() {
if (SimpleTest._stopOnLoad) {
SimpleTest.finish();
}
});
// --------------- Test.Builder/Test.More isDeeply() -----------------
SimpleTest.DNE = {dne: 'Does not exist'};
SimpleTest.LF = "\r\n";
SimpleTest._isRef = function (object) {
var type = typeof(object);
return type == 'object' || type == 'function';
};
SimpleTest._deepCheck = function (e1, e2, stack, seen) {
var ok = false;
// Either they're both references or both not.
var sameRef = !(!SimpleTest._isRef(e1) ^ !SimpleTest._isRef(e2));
if (e1 == null && e2 == null) {
ok = true;
} else if (e1 != null ^ e2 != null) {
ok = false;
} else if (e1 == SimpleTest.DNE ^ e2 == SimpleTest.DNE) {
ok = false;
} else if (sameRef && e1 == e2) {
// Handles primitives and any variables that reference the same
// object, including functions.
ok = true;
} else if (SimpleTest.isa(e1, 'Array') && SimpleTest.isa(e2, 'Array')) {
ok = SimpleTest._eqArray(e1, e2, stack, seen);
} else if (typeof e1 == "object" && typeof e2 == "object") {
ok = SimpleTest._eqAssoc(e1, e2, stack, seen);
} else {
// If we get here, they're not the same (function references must
// always simply rererence the same function).
stack.push({ vals: [e1, e2] });
ok = false;
}
return ok;
};
SimpleTest._eqArray = function (a1, a2, stack, seen) {
// Return if they're the same object.
if (a1 == a2) return true;
// JavaScript objects have no unique identifiers, so we have to store
// references to them all in an array, and then compare the references
// directly. It's slow, but probably won't be much of an issue in
// practice. Start by making a local copy of the array to as to avoid
// confusing a reference seen more than once (such as [a, a]) for a
// circular reference.
for (var j = 0; j < seen.length; j++) {
if (seen[j][0] == a1) {
return seen[j][1] == a2;
}
}
// If we get here, we haven't seen a1 before, so store it with reference
// to a2.
seen.push([ a1, a2 ]);
var ok = true;
// Only examines enumerable attributes. Only works for numeric arrays!
// Associative arrays return 0. So call _eqAssoc() for them, instead.
var max = a1.length > a2.length ? a1.length : a2.length;
if (max == 0) return SimpleTest._eqAssoc(a1, a2, stack, seen);
for (var i = 0; i < max; i++) {
var e1 = i > a1.length - 1 ? SimpleTest.DNE : a1[i];
var e2 = i > a2.length - 1 ? SimpleTest.DNE : a2[i];
stack.push({ type: 'Array', idx: i, vals: [e1, e2] });
if (ok = SimpleTest._deepCheck(e1, e2, stack, seen)) {
stack.pop();
} else {
break;
}
}
return ok;
};
SimpleTest._eqAssoc = function (o1, o2, stack, seen) {
// Return if they're the same object.
if (o1 == o2) return true;
// JavaScript objects have no unique identifiers, so we have to store
// references to them all in an array, and then compare the references
// directly. It's slow, but probably won't be much of an issue in
// practice. Start by making a local copy of the array to as to avoid
// confusing a reference seen more than once (such as [a, a]) for a
// circular reference.
seen = seen.slice(0);
for (var j = 0; j < seen.length; j++) {
if (seen[j][0] == o1) {
return seen[j][1] == o2;
}
}
// If we get here, we haven't seen o1 before, so store it with reference
// to o2.
seen.push([ o1, o2 ]);
// They should be of the same class.
var ok = true;
// Only examines enumerable attributes.
var o1Size = 0; for (var i in o1) o1Size++;
var o2Size = 0; for (var i in o2) o2Size++;
var bigger = o1Size > o2Size ? o1 : o2;
for (var i in bigger) {
var e1 = o1[i] == undefined ? SimpleTest.DNE : o1[i];
var e2 = o2[i] == undefined ? SimpleTest.DNE : o2[i];
stack.push({ type: 'Object', idx: i, vals: [e1, e2] });
if (ok = SimpleTest._deepCheck(e1, e2, stack, seen)) {
stack.pop();
} else {
break;
}
}
return ok;
};
SimpleTest._formatStack = function (stack) {
var variable = '$Foo';
for (var i = 0; i < stack.length; i++) {
var entry = stack[i];
var type = entry['type'];
var idx = entry['idx'];
if (idx != null) {
if (/^\d+$/.test(idx)) {
// Numeric array index.
variable += '[' + idx + ']';
} else {
// Associative array index.
idx = idx.replace("'", "\\'");
variable += "['" + idx + "']";
}
}
}
var vals = stack[stack.length-1]['vals'].slice(0, 2);
var vars = [
variable.replace('$Foo', 'got'),
variable.replace('$Foo', 'expected')
];
var out = "Structures begin differing at:" + SimpleTest.LF;
for (var i = 0; i < vals.length; i++) {
var val = vals[i];
if (val == null) {
val = 'undefined';
} else {
val == SimpleTest.DNE ? "Does not exist" : "'" + val + "'";
}
}
out += vars[0] + ' = ' + vals[0] + SimpleTest.LF;
out += vars[1] + ' = ' + vals[1] + SimpleTest.LF;
return ' ' + out;
};
SimpleTest.isDeeply = function (it, as, name) {
var ok;
// ^ is the XOR operator.
if (SimpleTest._isRef(it) ^ SimpleTest._isRef(as)) {
// One's a reference, one isn't.
ok = false;
} else if (!SimpleTest._isRef(it) && !SimpleTest._isRef(as)) {
// Neither is an object.
ok = SimpleTest.is(it, as, name);
} else {
// We have two objects. Do a deep comparison.
var stack = [], seen = [];
if ( SimpleTest._deepCheck(it, as, stack, seen)) {
ok = SimpleTest.ok(true, name);
} else {
ok = SimpleTest.ok(false, name, SimpleTest._formatStack(stack));
}
}
return ok;
};
SimpleTest.typeOf = function (object) {
var c = Object.prototype.toString.apply(object);
var name = c.substring(8, c.length - 1);
if (name != 'Object') return name;
// It may be a non-core class. Try to extract the class name from
// the constructor function. This may not work in all implementations.
if (/function ([^(\s]+)/.test(Function.toString.call(object.constructor))) {
return RegExp.$1;
}
// No idea. :-(
return name;
};
SimpleTest.isa = function (object, clas) {
return SimpleTest.typeOf(object) == clas;
};
// Global symbols:
var ok = SimpleTest.ok;
var is = SimpleTest.is;
var isDeeply = SimpleTest.isDeeply;

View File

@ -0,0 +1,256 @@
/*
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/.
*/
/**
* TestRunner: A test runner for SimpleTest
* TODO:
*
* * Avoid moving iframes: That causes reloads on mozilla and opera.
*
*
**/
var TestRunner = {};
TestRunner.logEnabled = false;
TestRunner._iframes = {};
TestRunner._iframeDocuments = {};
TestRunner._iframeRows = {};
TestRunner._currentTest = 0;
TestRunner._urls = [];
TestRunner._testsDiv = DIV();
TestRunner._progressDiv = DIV();
TestRunner._summaryDiv = DIV(null,
H1(null, "Tests Summary"),
TABLE(null,
THEAD(null,
TR(null,
TH(null, "Test"),
TH(null, "Passed"),
TH(null, "Failed")
)
),
TFOOT(/*null, TR(null, TH(null, "-"), TH(null, "--"), TH(null, "---"))*/),
TBODY()
)
);
/**
* This function is called after generating the summary.
**/
TestRunner.onComplete = null;
/**
* If logEnabled is true, this is the logger that will be used.
**/
TestRunner.logger = MochiKit.Logging.logger;
/**
* Toggle element visibility
**/
TestRunner._toggle = function(el) {
if (el.className == "noshow") {
el.className = "";
el.style.cssText = "";
} else {
el.className = "noshow";
el.style.cssText = "width:0px; height:0px; border:0px;";
}
};
/**
* Creates the iframe that contains a test
**/
TestRunner._makeIframe = function (url) {
var iframe = document.createElement('iframe');
iframe.src = url;
iframe.name = url;
iframe.width = "500";
var tbody = TestRunner._summaryDiv.getElementsByTagName("tbody")[0];
var tr = TR(null, TD({'colspan': '3'}, iframe));
iframe._row = tr;
tbody.appendChild(tr);
return iframe;
};
/**
* TestRunner entry point.
*
* The arguments are the URLs of the test to be ran.
*
**/
TestRunner.runTests = function (/*url...*/) {
if (TestRunner.logEnabled)
TestRunner.logger.log("SimpleTest START");
var body = document.getElementsByTagName("body")[0];
appendChildNodes(body,
TestRunner._testsDiv,
TestRunner._progressDiv,
TestRunner._summaryDiv
);
for (var i = 0; i < arguments.length; i++) {
TestRunner._urls.push(arguments[i]);
}
TestRunner.runNextTest();
};
/**
* Run the next test. If no test remains, calls makeSummary
**/
TestRunner.runNextTest = function() {
if (TestRunner._currentTest < TestRunner._urls.length) {
var url = TestRunner._urls[TestRunner._currentTest];
var progress = SPAN(null,
"Running ", A({href:url}, url), "..."
);
if (TestRunner.logEnabled)
TestRunner.logger.log(scrapeText(progress));
TestRunner._progressDiv.appendChild(progress);
TestRunner._iframes[url] = TestRunner._makeIframe(url);
} else {
TestRunner.makeSummary();
if (TestRunner.onComplete) {
TestRunner.onComplete();
}
}
};
/**
* This stub is called by SimpleTest when a test is finished.
**/
TestRunner.testFinished = function (doc) {
appendChildNodes(TestRunner._progressDiv, SPAN(null, "Done"), BR());
var finishedURL = TestRunner._urls[TestRunner._currentTest];
if (TestRunner.logEnabled)
TestRunner.logger.debug("SimpleTest finished " + finishedURL);
TestRunner._iframeDocuments[finishedURL] = doc;
// TestRunner._iframes[finishedURL].style.display = "none";
if (finishedURL != null) {
TestRunner._toggle(TestRunner._iframes[finishedURL]);
TestRunner._currentTest++;
TestRunner.runNextTest();
}
};
/**
* Display the summary in the browser
**/
/*
TestRunner.makeSummary = function() {
if (TestRunner.logEnabled)
TestRunner.logger.log("SimpleTest FINISHED");
var rows = [];
for (var url in TestRunner._iframeDocuments) {
var doc = TestRunner._iframeDocuments[url];
var nOK = withDocument(doc,
partial(getElementsByTagAndClassName, 'div', 'test_ok')
).length;
var nNotOK = withDocument(doc,
partial(getElementsByTagAndClassName, 'div', 'test_not_ok')
).length;
var toggle = partial(TestRunner._toggle, TestRunner._iframes[url]);
var jsurl = "TestRunner._toggle(TestRunner._iframes['" + url + "'])";
var row = TR(
{'style': {'backgroundColor': nNotOK > 0 ? "#f00":"#0f0"}},
TD(null, url),
TD(null, nOK),
TD(null, nNotOK)
);
row.onclick = toggle;
var tbody = TestRunner._summaryDiv.getElementsByTagName("tbody")[0];
tbody.insertBefore(row, TestRunner._iframes[url]._row)
}
};
*/
TestRunner.makeSummary = function() {
var base = MochiKit.Base;
var dom = MochiKit.DOM;
var iter = MochiKit.Iter;
var total_Ok, total_not_Ok;
total_Ok = 0;
total_not_Ok = 0;
if (TestRunner.logEnabled)
TestRunner.logger.log("SimpleTest FINISHED");
var rows = [];
for (var url in TestRunner._iframeDocuments) {
var doc = TestRunner._iframeDocuments[url];
var nOK = withDocument(doc,
partial(getElementsByTagAndClassName, 'div', 'test_ok')
).length;
var nNotOK = withDocument(doc,
partial(getElementsByTagAndClassName, 'div', 'test_not_ok')
).length;
var toggle = partial(TestRunner._toggle, TestRunner._iframes[url]);
var jsurl = "TestRunner._toggle(TestRunner._iframes['" + url + "'])";
var row = TR(
{'style': {'backgroundColor': nNotOK > 0 ? "#f00":"#0f0"}},
TD(null, url),
TD(null, nOK),
TD(null, nNotOK)
);
row.onclick = toggle;
var tbody = TestRunner._summaryDiv.getElementsByTagName("tbody")[0];
tbody.insertBefore(row, TestRunner._iframes[url]._row);
total_Ok += nOK;
total_not_Ok += nNotOK;
}
{
var tfoot = TestRunner._summaryDiv.getElementsByTagName("tfoot")[0];
tfoot.appendChild(TR(null,
TH(null, ""),
TH({'style':"color:green;"}, total_Ok),
TH({'style':"color:" + ((total_not_Ok == 0) ? 'black' : 'red') + ";"}, total_not_Ok)
));
}
var testRunnerResults;
var i, c;
testRunnerResults = dom.DIV({'style': 'display:none; visibility:hidden;'}, null);
c = total_Ok;
for (i=0; i<c; i++) {
dom.appendChildNodes(testRunnerResults, dom.DIV({'class': 'test_ok'}, "ok"));
}
c = total_not_Ok;
for (i=0; i<c; i++) {
dom.appendChildNodes(testRunnerResults, dom.DIV({'class': 'test_not_ok'}, "fail"));
}
document.getElementsByTagName("body")[0].appendChild(testRunnerResults);
if (typeof(parent) != "undefined" && parent.TestRunner) {
parent.TestRunner.testFinished(document);
}
};

View File

@ -0,0 +1,51 @@
/*
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/.
*/
.test_ok {
color: green;
display: none;
}
.test_not_ok {
color: red;
display: block;
}
.test_ok, .test_not_ok {
border-bottom-width: 2px;
border-bottom-style: solid;
border-bottom-color: black;
}
.all_pass {
background-color: lime;
}
.some_fail {
background-color: red;
}
.tests_report {
border-width: 2px;
border-style: solid;
width: 20em;
}

View File

@ -0,0 +1,100 @@
<!--
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/.
-->
<html>
<head>
<title>Clipperz.PM.DataModel.DirectLogin - test</title>
<script>Clipperz = {}</script>
<script type="text/javascript" src="../../../../../js/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="../../../../../js/React/react-with-addons-0.10.0.js"></script>
<script type="text/javascript" src="../../../../SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="../../../../SimpleTest/test.css">
<script type='text/javascript' src='../../../../../js/Clipperz/YUI/Utils.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Base.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Date.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/ByteArray.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Logging.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Async.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Signal.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/KeyValueObjectStore.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/Base.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/BigInt.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/AES.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/AES_2.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/SHA.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/PRNG.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/SRP.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Toll.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Proxy.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Proxy/Proxy.Offline.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Proxy/Proxy.Test.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Connection.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Crypto.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Strings.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Strings/Strings_en-US.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Date.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/EncryptedRemoteObject.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/Record.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/Record.Version.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/Record.Version.Field.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/DirectLogin.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/DirectLoginInput.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/DirectLoginBinding.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.Header.Legacy.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.Header.RecordIndex.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.Header.Preferences.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.Header.OneTimePasswords.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/OneTimePassword.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.AccountInfo.js'></script>
<script type="text/javascript" src="../../../../SimpleTest/SimpleTest.Async.js"></script>
<script>
Clipperz_IEisBroken = false;
</script>
<!--[if IE]><script>
Clipperz_IEisBroken = true;
Clipperz_normalizedNewLine = '\x0d\x0a';
</script><![endif]-->
</head>
<body>
<pre id="test">
<script>
Clipperz.PM.Strings.Languages.setSelectedLanguage('en-us');
</script>
<script type="text/javascript" src="User.data.js"></script>
<script type="text/javascript" src="User.data.old.js"></script>
<script type="text/javascript" src="DirectLogin.test.js"></script>
</pre>
</body>
</html>

View File

@ -0,0 +1,190 @@
/*
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.Crypto.PRNG.defaultRandomGenerator().fastEntropyAccumulationForTestingPurpose();
var tests = {
/*
user = new Clipperz.PM.DataModel.User({username:'test', getPassphraseFunction:function () { return 'test';}});
...
deferredResult.addMethod(proxy.dataStore(), 'setupWithEncryptedData', testData['test_test_offline_copy_data']);
deferredResult.addMethod(user, 'getRecord', '8280842f41162b673335b63860637e8472e8bbff0efa2bc78b0dbc5e09712e13');
user = new Clipperz.PM.DataModel.User({username:'joe', getPassphraseFunction:function () { return 'clipperz';}});
...
deferredResult.addMethod(proxy.dataStore(), 'setupWithEncryptedData', testData['joe_clipperz_offline_copy_data']);
deferredResult.addMethod(user, 'getRecord', '5cdac63b317f3942da38f3a3de3b7f0e5d6678200951c6216230295550f63fb4'); // WEB PASSWORD (0)
deferredResult.addMethod(user, 'getRecord', '36ec1a41118813ced3553534fa2607d781cba687768db305beed368a8e06e113'); // DIGG (1)
deferredResult.addMethod(user, 'getRecord', 'c0ce9130ca365bb02418d4305ea1d29e49c3f0e96d44b9d3cb6b4b6843d25065'); // SAP (2)
deferredResult.addMethod(user, 'getRecord', 'd5f700b9c3367c39551ea49e00a9ab20dae09dd79d46047b983fc7c4bfaa050d'); // YAHOO (4)
DirectLogin references
- dba0db679802f0e6aa6d0b7a6aaf42350aabc5f057409edd99a268a92ebb6496 // Yahoo! Mail
- aa18149164302d5dbe7e2d3724565b9550e00887b49978559783b2e38c625584 // (Yahoo! Groups)
- 6f7bbc4e42ea462b5246e6f51c3f86056bec50601ce2de6067c8c1d26f21c07f // (Flickr)
- a7b32e72502804bf2946a2a8856139cbbb759c5777e6b3e673db1fdf7e3bd06e // (My Yahoo!)
*/
//-------------------------------------------------------------------------
'editDirectLoginLabel_test': function (someTestArgs) {
var deferredResult;
var proxy;
var user;
proxy = new Clipperz.PM.Proxy.Test({shouldPayTolls:true, isDefault:true, readOnly:false});
user = new Clipperz.PM.DataModel.User({username:'joe', getPassphraseFunction:function () { return 'clipperz';}});
deferredResult = new Clipperz.Async.Deferred("editDirectLoginLabel_test", someTestArgs);
deferredResult.addMethod(proxy.dataStore(), 'setupWithEncryptedData', testData['joe_clipperz_offline_copy_data']);
deferredResult.addMethod(user, 'login');
deferredResult.addMethod(user, 'getRecord', 'd5f700b9c3367c39551ea49e00a9ab20dae09dd79d46047b983fc7c4bfaa050d'); // YAHOO (4)
deferredResult.addMethodcaller('directLogins');
deferredResult.addCallback(MochiKit.Base.itemgetter('dba0db679802f0e6aa6d0b7a6aaf42350aabc5f057409edd99a268a92ebb6496'));
deferredResult.addCallback(function (aDirectLogin) {
var innerDeferredResult;
var updatedLabel;
updatedLabel = "updated Yahoo! Mail label";
innerDeferredResult = new Clipperz.Async.Deferred("editDirectLoginLabel_test <inner>", someTestArgs);
innerDeferredResult.addMethod(aDirectLogin, 'label');
innerDeferredResult.addTest("Yahoo! Mail", "The label of the selected direct login is correct.");
innerDeferredResult.addMethod(aDirectLogin, 'setLabel', updatedLabel);
innerDeferredResult.addMethod(aDirectLogin, 'label');
innerDeferredResult.addTest(updatedLabel, "The DirectLogin returns the correct label even before committing data.");
innerDeferredResult.addMethod(user, 'hasPendingChanges');
innerDeferredResult.addTest(true, "When changing the label of a DirectLogin, the user should report pending changes.");
//innerDeferredResult.addCallback(function () { console.log("+_+_+_+_+_+_+_+_+_+_+_+ >>>")});
innerDeferredResult.addMethod(user, 'saveChanges');
//innerDeferredResult.addCallback(function () { console.log("+_+_+_+_+_+_+_+_+_+_+_+ <<<")});
innerDeferredResult.addMethod(user, 'hasPendingChanges');
innerDeferredResult.addTest(false, "After saving changes there should be no pending changes left.");
innerDeferredResult.addMethod(aDirectLogin, 'label');
innerDeferredResult.addTest(updatedLabel, "The DirectLogin returns the correct label even after committing data.");
innerDeferredResult.callback();
return innerDeferredResult;
})
deferredResult.callback();
return deferredResult;
},
//-------------------------------------------------------------------------
'editDirectLoginLabel_thanResetItToThePreviousValue_test': function (someTestArgs) {
var deferredResult;
var proxy;
var user;
proxy = new Clipperz.PM.Proxy.Test({shouldPayTolls:true, isDefault:true, readOnly:false});
user = new Clipperz.PM.DataModel.User({username:'joe', getPassphraseFunction:function () { return 'clipperz';}});
deferredResult = new Clipperz.Async.Deferred("editDirectLoginLabel_thanResetItToThePreviousValue_test", someTestArgs);
deferredResult.addMethod(proxy.dataStore(), 'setupWithEncryptedData', testData['joe_clipperz_offline_copy_data']);
deferredResult.addMethod(user, 'login');
deferredResult.addMethod(user, 'getRecord', 'd5f700b9c3367c39551ea49e00a9ab20dae09dd79d46047b983fc7c4bfaa050d'); // YAHOO (4)
deferredResult.addMethodcaller('directLogins');
deferredResult.addCallback(MochiKit.Base.itemgetter('dba0db679802f0e6aa6d0b7a6aaf42350aabc5f057409edd99a268a92ebb6496'));
deferredResult.addCallback(function (aDirectLogin) {
var innerDeferredResult;
var originalLabel;
var updatedLabel;
originalLabel = "Yahoo! Mail";
updatedLabel = "updated Yahoo! Mail label";
innerDeferredResult = new Clipperz.Async.Deferred("editDirectLoginLabel_thanResetItToThePreviousValue_test <inner>", someTestArgs);
innerDeferredResult.addMethod(aDirectLogin, 'label');
innerDeferredResult.addTest(originalLabel, "The label of the selected direct login is correct.");
innerDeferredResult.addMethod(aDirectLogin, 'setLabel', updatedLabel);
innerDeferredResult.addMethod(aDirectLogin, 'label');
innerDeferredResult.addTest(updatedLabel, "The DirectLogin returns the correct label even before committing data.");
innerDeferredResult.addMethod(user, 'hasPendingChanges');
innerDeferredResult.addTest(true, "When changing the label of a DirectLogin, the user should report pending changes [2].");
innerDeferredResult.addMethod(aDirectLogin, 'setLabel', originalLabel);
innerDeferredResult.addMethod(aDirectLogin, 'hasPendingChanges');
innerDeferredResult.addTest(false, "Restoring the original label, the directLogin should report no pending changes.");
innerDeferredResult.addMethod(aDirectLogin.record(), 'hasPendingChanges');
innerDeferredResult.addTest(false, "Restoring the original label, the record should report no pending changes.");
innerDeferredResult.addMethod(user, 'hasPendingChanges');
innerDeferredResult.addTest(false, "Restoring the original label, the user should report no pending changes.");
innerDeferredResult.callback();
return innerDeferredResult;
})
deferredResult.callback();
return deferredResult;
},
//-------------------------------------------------------------------------
/*
'bindingValues_test': function (someTestArgs) {
var deferredResult;
var proxy;
var user;
proxy = new Clipperz.PM.Proxy.Test({shouldPayTolls:true, isDefault:true, readOnly:false});
user = new Clipperz.PM.DataModel.User({username:'joe', getPassphraseFunction:function () { return 'clipperz';}});
deferredResult = new Clipperz.Async.Deferred("DirectLogin.bindingValues_test", someTestArgs);
deferredResult.addMethod(proxy.dataStore(), 'setupWithEncryptedData', testData['joe_clipperz_offline_copy_data']);
deferredResult.addMethod(user, 'login');
deferredResult.addMethod(user, 'getRecord', 'd5f700b9c3367c39551ea49e00a9ab20dae09dd79d46047b983fc7c4bfaa050d'); // YAHOO (4)
deferredResult.addMethodcaller('directLogins');
deferredResult.addCallback(MochiKit.Base.itemgetter('dba0db679802f0e6aa6d0b7a6aaf42350aabc5f057409edd99a268a92ebb6496'));
deferredResult.addMethodcaller('bindingValues');
deferredResult.addCallback(function (someBindingValues) {
SimpleTest.is(MochiKit.Base.keys(someBindingValues).length, 2, "there should be 2 bindings for this direct login");
SimpleTest.is(someBindingValues['login'], 'joe.clipperz', "the login field should be filled with 'joe.clipperz'");
SimpleTest.is(someBindingValues['passwd'], 'enfvDG1RxAsl', "the passwd field should be filled with 'enfvDG1RxAsl'");
})
deferredResult.callback();
return deferredResult;
},
*/
//-------------------------------------------------------------------------
'syntaxFix': MochiKit.Base.noop
};
//#############################################################################
SimpleTest.runDeferredTests("Clipperz.PM.DataModel.DirectLogin", tests, {trace:false});

View File

@ -0,0 +1,28 @@
/*
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/.
*/
directLoginConfigurations = {
'Yahoo! Mail': '{\n "page": {\n "title": "Yahoo! Mail"\n },\n "form": {\n "attributes": {\n "action": "https://login.yahoo.com/config/login?",\n "method": "post"\n },\n "inputs": [\n {\n "type": "hidden",\n "name": ".tries",\n "value": "1"\n },\n {\n "type": "hidden",\n "name": ".src",\n "value": "ym"\n },\n {\n "type": "hidden",\n "name": ".md5",\n "value": ""\n },\n {\n "type": "hidden",\n "name": ".hash",\n "value": ""\n },\n {\n "type": "hidden",\n "name": ".js",\n "value": ""\n },\n {\n "type": "hidden",\n "name": ".last",\n "value": ""\n },\n {\n "type": "hidden",\n "name": "promo",\n "value": ""\n },\n {\n "type": "hidden",\n "name": ".intl",\n "value": "us"\n },\n {\n "type": "hidden",\n "name": ".bypass",\n "value": ""\n },\n {\n "type": "hidden",\n "name": ".partner",\n "value": ""\n },\n {\n "type": "hidden",\n "name": ".u",\n "value": "5gp62cl2vg3ov"\n },\n {\n "type": "hidden",\n "name": ".v",\n "value": "0"\n },\n {\n "type": "hidden",\n "name": ".challenge",\n "value": "iBEY0IK6k3t9Uals32mrTos8s48p"\n },\n {\n "type": "hidden",\n "name": ".yplus",\n "value": ""\n },\n {\n "type": "hidden",\n "name": ".emailCode",\n "value": ""\n },\n {\n "type": "hidden",\n "name": "pkg",\n "value": ""\n },\n {\n "type": "hidden",\n "name": "stepid",\n "value": ""\n },\n {\n "type": "hidden",\n "name": ".ev",\n "value": ""\n },\n {\n "type": "hidden",\n "name": "hasMsgr",\n "value": "0"\n },\n {\n "type": "hidden",\n "name": ".chkP",\n "value": "Y"\n },\n {\n "type": "hidden",\n "name": ".done",\n "value": "http://mail.yahoo.com"\n },\n {\n "type": "hidden",\n "name": ".pd",\n "value": "ym_ver%3d0%26c="\n },\n {\n "type": "text",\n "name": "login",\n "value": ""\n },\n {\n "type": "password",\n "name": "passwd",\n "value": ""\n },\n {\n "type": "checkbox",\n "name": ".persistent",\n "value": "y"\n },\n {\n "type": "submit",\n "name": ".save",\n "value": "Sign In"\n }\n ]\n },\n "version": "0.2"\n}',
'Parallels': '{"page": {"title": "Parallels Account"},\n"form": {"attributes": {"action": "https://www.parallels.com/account/",\n"method": "post"},\n"inputs": [{"type": "text",\n"name": "Email",\n"value": ""},\n{"type": "password",\n"name": "Password",\n"value": ""}]},\n"version": "0.2.3"}',
__syntaxFix__: "syntax fix"
};

View File

@ -0,0 +1,60 @@
<!--
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/.
-->
<html>
<head>
<title>Clipperz.PM.DataModel.EncryptedRemoteObject - test</title>
<script>Clipperz = {}</script>
<script type="text/javascript" src="../../../../../js/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="../../../../SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="../../../../SimpleTest/test.css">
<script type='text/javascript' src='../../../../../js/Clipperz/YUI/Utils.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Base.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/ByteArray.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Logging.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Async.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Signal.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/KeyValueObjectStore.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/Base.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/BigInt.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/AES.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/AES_2.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/SHA.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/PRNG.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/SRP.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Proxy.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Connection.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Crypto.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/EncryptedRemoteObject.js'></script>
<script type="text/javascript" src="../../../../SimpleTest/SimpleTest.Async.js"></script>
</head>
<body>
<pre id="test">
<script type="text/javascript" src="EncryptedRemoteObject.test.js"></script>
</pre>
</body>
</html>

View File

@ -0,0 +1,220 @@
/*
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.Crypto.PRNG.defaultRandomGenerator().fastEntropyAccumulationForTestingPurpose();
var tests = {
//-------------------------------------------------------------------------
'simple_tests': function(someTestArgs) {
var deferredResult;
var encryptedRemoteObject;
var key;
var version;
var rawData;
key = "just a random key";
version = Clipperz.PM.Crypto.encryptingFunctions.currentVersion;
rawData = "just a random text to encrypt";
encryptedRemoteObject = new Clipperz.PM.DataModel.EncryptedRemoteObject({
'retrieveKeyFunction': MochiKit.Base.noop,
'retrieveRemoteDataFunction': function () { return "--"},
'encryptedDataKeypath': '--',
'encryptedVersionKeypath': '--'
});
SimpleTest.ok(encryptedRemoteObject != null, "create an encryptedRemoteObject");
deferredResult = Clipperz.Async.callbacks("EncryptedRemoteObject.test - simple_tests", [
MochiKit.Base.method(encryptedRemoteObject, 'getRemoteData'),
function(aResult) {
SimpleTest.is(aResult, "--", "setting and getting serverData works");
}
], someTestArgs);
return deferredResult;
},
//-------------------------------------------------------------------------
'decrypt_test': function (someTestArgs) {
var deferredResult;
var encryptedRemoteObject;
var key;
var version;
var rawData;
key = "just a random key";
version = Clipperz.PM.Crypto.encryptingFunctions.currentVersion;
rawData = "just a random text to encrypt";
encryptedRemoteObject = new Clipperz.PM.DataModel.EncryptedRemoteObject({
'retrieveKeyFunction': MochiKit.Base.partial(MochiKit.Async.succeed, key),
'retrieveRemoteDataFunction': MochiKit.Base.partial(Clipperz.Async.callbacks, "EncryptedRemoteObject.test - decrypt_test <encrypt data>", [
MochiKit.Base.partial(Clipperz.PM.Crypto.deferredEncrypt, {key:key, value:rawData, version:version}),
function (someEncryptedData) {
return {
'data': someEncryptedData,
'version': version
}
}
], someTestArgs)//,
// 'encryptedDataKeypath': 'data',
// 'encryptedVersionKeypath': 'version'
});
deferredResult = new Clipperz.Async.Deferred("decrypt_test", someTestArgs);
deferredResult.addMethod(encryptedRemoteObject, 'getDecryptedData');
deferredResult.addCallback(function (aResult) {
SimpleTest.is(aResult, rawData, "encrypt and decrypt works");
})
deferredResult.callback();
return deferredResult;
},
//-------------------------------------------------------------------------
'getValue_test': function (someTestArgs) {
var deferredResult;
var encryptedRemoteObject;
var key;
var version;
var rawData;
key = "just a random key";
version = Clipperz.PM.Crypto.encryptingFunctions.currentVersion;
rawData = {
key1: 'value1',
key2: 'value2'
};
encryptedRemoteObject = new Clipperz.PM.DataModel.EncryptedRemoteObject({
'reference': "testReference",
'retrieveKeyFunction': MochiKit.Base.partial(MochiKit.Async.succeed, key),
'retrieveRemoteDataFunction': MochiKit.Base.partial(Clipperz.Async.callbacks, "EncryptedRemoteObject.test - decrypt_test <encrypt data>", [
MochiKit.Base.partial(Clipperz.PM.Crypto.deferredEncrypt, {key:key, value:rawData, version:version}),
function (someEncryptedData) {
return {
'data': someEncryptedData,
'version': version
}
}
], someTestArgs)//,
// 'encryptedDataKeypath': 'data',
// 'encryptedVersionKeypath': 'version'
});
deferredResult = new Clipperz.Async.Deferred("decrypt_test", someTestArgs);
deferredResult.addMethod(encryptedRemoteObject, 'getValue', 'key1');
deferredResult.addTest('value1', "getting 'key1' works");
deferredResult.addMethod(encryptedRemoteObject, 'hasAnyCleanTextData');
deferredResult.addTest(true, "After accessing a value, hasAnyCleanTextData returns false");
deferredResult.addMethod(encryptedRemoteObject, 'hasPendingChanges');
deferredResult.addTest(false, "if nothing has changed, the object should return not pending changes");
deferredResult.addMethod(encryptedRemoteObject, 'deleteAllCleanTextData');
deferredResult.addMethod(encryptedRemoteObject, 'hasAnyCleanTextData');
deferredResult.addTest(false, "After deleting all cleanTextData, hasAnyCleanTextData returns false");
deferredResult.addMethod(encryptedRemoteObject, 'getValue', 'key1');
deferredResult.addTest('value1', "getting 'key1' (also after a lock) works correctly");
deferredResult.addMethod(encryptedRemoteObject, 'setValue', 'key1', 'new value1');
deferredResult.addMethod(encryptedRemoteObject, 'getValue', 'key1');
deferredResult.addTest('new value1', "after setting a new value, it is correctly returned");
deferredResult.addMethod(encryptedRemoteObject, 'values');
deferredResult.addCallback(function (someValues) {
SimpleTest.is(someValues['key1'], 'new value1', "the value got straight from the objectStore is correct");
});
deferredResult.addMethod(encryptedRemoteObject, 'hasPendingChanges');
deferredResult.addTest(true, "once a value has been changed, the object should return that there're some pending changes");
deferredResult.addMethod(encryptedRemoteObject, 'revertChanges');
deferredResult.addMethod(encryptedRemoteObject, 'hasPendingChanges');
deferredResult.addTest(false, "reverting the changes should return the object to its initial state, without any peding changes");
deferredResult.addMethod(encryptedRemoteObject, 'getValue', 'key1');
deferredResult.addTest('value1', "also the value of the changed item has been restored");
deferredResult.callback();
return deferredResult;
},
//-------------------------------------------------------------------------
'encrypt_with_new_object_test': function (someTestArgs) {
var deferredResult;
var encryptedRemoteObject;
var key;
// var version;
// var rawData;
key = "just a random key";
// version = Clipperz.PM.Crypto.encryptingFunctions.currentVersion;
// rawData = "just a random text to encrypt";
encryptedRemoteObject = new Clipperz.PM.DataModel.EncryptedRemoteObject({
'retrieveRemoteDataFunction': MochiKit.Base.noop
});
encryptedRemoteObject.setValue('key1', "value1");
encryptedRemoteObject.setValue('key2', "value2");
encryptedRemoteObject.setValue('key3', "value3");
deferredResult = new Clipperz.Async.Deferred("encrypt_with_new_object_test", someTestArgs);
deferredResult.addMethod(encryptedRemoteObject, 'prepareRemoteDataWithKey', key);
deferredResult.addCallback(MochiKit.Base.itemgetter('data'));
deferredResult.collectResults({
'key': MochiKit.Base.partial(MochiKit.Async.succeed, key),
'value': MochiKit.Async.succeed,
'version': MochiKit.Base.partial(MochiKit.Async.succeed, Clipperz.PM.Crypto.encryptingFunctions.currentVersion)
});
deferredResult.addCallback(Clipperz.PM.Crypto.deferredDecrypt);
deferredResult.addCallback(function (aResult) {
SimpleTest.is(aResult['key1'], "value1", "encrypt and decrypt works for first element");
SimpleTest.is(aResult['key2'], "value2", "encrypt and decrypt works for second element");
SimpleTest.is(aResult['key3'], "value3", "encrypt and decrypt works for third element");
})
deferredResult.callback();
return deferredResult;
},
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
'syntaxFix': MochiKit.Base.noop
};
//#############################################################################
SimpleTest.runDeferredTests("Clipperz.PM.DataModel.EncryptedRemoteObject", tests, {trace:false});

View File

@ -0,0 +1,99 @@
<!--
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/.
-->
<html>
<head>
<title>Clipperz.PM.DataModel.User - test</title>
<script>Clipperz = {}</script>
<script type="text/javascript" src="../../../../../js/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="../../../../SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="../../../../SimpleTest/test.css">
<script type='text/javascript' src='../../../../../js/Clipperz/YUI/Utils.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Base.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Date.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/ByteArray.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Logging.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Async.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Signal.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/KeyValueObjectStore.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/Base.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/BigInt.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/AES.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/SHA.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/PRNG.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/SRP.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Toll.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Proxy.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Proxy/Proxy.Offline.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Proxy/Proxy.Test.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Connection.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Crypto.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/UI/DirectLoginController.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Strings.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Strings/Strings_en-US.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Date.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/EncryptedRemoteObject.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/Record.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/Record.Version.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/Record.Version.Field.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/DirectLogin.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/DirectLoginInput.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/DirectLoginBinding.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/DirectLoginFormValue.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.Header.Legacy.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.Header.RecordIndex.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.Header.Preferences.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.Header.OneTimePasswords.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/OneTimePassword.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.AccountInfo.js'></script>
<script type="text/javascript" src="../../../../SimpleTest/SimpleTest.Async.js"></script>
<script>
Clipperz_IEisBroken = false;
</script>
<!--[if IE]><script>
Clipperz_IEisBroken = true;
Clipperz_normalizedNewLine = '\x0d\x0a';
</script><![endif]-->
</head>
<body>
<pre id="test">
<script>
Clipperz.PM.Strings.Languages.setSelectedLanguage('en-us');
</script>
<script type="text/javascript" src="User.data.js"></script>
<script type="text/javascript" src="OneTimePassword.test.js"></script>
</pre>
</body>
</html>

View 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/.
*/
Clipperz.Crypto.PRNG.defaultRandomGenerator().fastEntropyAccumulationForTestingPurpose();
var tests = {
//-------------------------------------------------------------------------
'isValidOneTimePasswordValue_test': function (someTestArgs) {
var otp;
var notOTP;
otp = 'yaxx k7ww - f8y6 tqz5 - 58b6 th44 - 9cwv q0fg';
SimpleTest.is(Clipperz.PM.DataModel.OneTimePassword.isValidOneTimePasswordValue(otp), true, "isValidOneTimePasswordValue [expect true] - test 1");
notOTP = 'trustno1';
SimpleTest.is(Clipperz.PM.DataModel.OneTimePassword.isValidOneTimePasswordValue(notOTP), false, "isValidOneTimePasswordValue [expect false] - test 1");
return MochiKit.Async.succeed('done');
},
//-------------------------------------------------------------------------
'loginUsingOtp_test': function (someTestArgs) {
var deferredResult;
var proxy;
var user, user2;
var username;
var passphrase;
username = "test";
passphrase = "yaxx k7ww - f8y6 tqz5 - 58b6 th44 - 9cwv q0fg"; // OTP
proxy = new Clipperz.PM.Proxy.Test({shouldPayTolls:true, isDefault:true, readOnly:false});
user = new Clipperz.PM.DataModel.User({username:username, getPassphraseFunction:function () { return passphrase;}});
user2 = new Clipperz.PM.DataModel.User({username:username, getPassphraseFunction:function () { return passphrase;}});
deferredResult = new Clipperz.Async.Deferred("loginUsingOtp_test", someTestArgs);
deferredResult.addMethod(proxy.dataStore(), 'setupWithEncryptedData', testData['test_test_with_otps']);
deferredResult.addMethod(user, 'login');
deferredResult.addMethod(user, 'getRecords');
deferredResult.addCallback(MochiKit.Base.itemgetter('length'));
deferredResult.addTest(1, "This account has one single card");
deferredResult.addMethod(user, 'getOneTimePasswords');
deferredResult.addCallback(MochiKit.Base.itemgetter('length'));
deferredResult.addTest(1, "This account has one OTP");
deferredResult.addMethod(user, 'getOneTimePasswords');
deferredResult.addCallback(MochiKit.Base.itemgetter(0));
deferredResult.addCallback(MochiKit.Base.methodcaller('status'));
deferredResult.addTest('USED', "The available OTP has been unsed to login, and should be marked accordingly");
deferredResult.addMethod(user2, 'login');
deferredResult.shouldFail("trying to login using the same OTP twice");
deferredResult.callback();
return deferredResult;
},
//-------------------------------------------------------------------------
'changePassphraseAndLoginUsingOtp_test': function (someTestArgs) {
var deferredResult;
var proxy;
var user;
var user2;
var user3;
var otp;
otp = "yaxx k7ww - f8y6 tqz5 - 58b6 th44 - 9cwv q0fg"; // OTP
newPassphrase = 'tset';
proxy = new Clipperz.PM.Proxy.Test({shouldPayTolls:true, isDefault:true, readOnly:false});
user = new Clipperz.PM.DataModel.User({username:'test', getPassphraseFunction:function () { return 'test';}});
user2 = new Clipperz.PM.DataModel.User({username:'test', getPassphraseFunction:function () { return otp;}});
deferredResult = new Clipperz.Async.Deferred("changePassphraseAndLoginUsingOtp_test", someTestArgs);
deferredResult.addMethod(proxy.dataStore(), 'setupWithEncryptedData', testData['test_test_with_otps']);
deferredResult.addMethod(user, 'login');
deferredResult.addMethod(user, 'getRecords');
deferredResult.addCallback(MochiKit.Base.itemgetter('length'));
deferredResult.addTest(1, "This account has only a single card");
deferredResult.addMethod(user, 'changePassphrase', newPassphrase);
deferredResult.addMethod(user, 'logout');
deferredResult.addMethod(user2, 'login');
deferredResult.addMethod(user2, 'getRecords');
deferredResult.addCallback(MochiKit.Base.itemgetter('length'));
deferredResult.addTest(1, "This account has oly a single card");
deferredResult.addMethod(user2, 'logout');
deferredResult.callback();
return deferredResult;
},
//-------------------------------------------------------------------------
'loginUsingOtpAndWrongUsername_test': function (someTestArgs) {
var deferredResult;
var proxy;
var user, user2;
var username;
var wrongUsername;
var passphrase;
username = "test";
wrongUsername = "tset";
passphrase = "yaxx k7ww - f8y6 tqz5 - 58b6 th44 - 9cwv q0fg"; // OTP
proxy = new Clipperz.PM.Proxy.Test({shouldPayTolls:true, isDefault:true, readOnly:false});
user = new Clipperz.PM.DataModel.User({username:wrongUsername, getPassphraseFunction:function () { return passphrase;}});
user2 = new Clipperz.PM.DataModel.User({username:username, getPassphraseFunction:function () { return passphrase;}});
deferredResult = new Clipperz.Async.Deferred("loginUsingOtpAndWrongUsername_test", someTestArgs);
deferredResult.addMethod(proxy.dataStore(), 'setupWithEncryptedData', testData['test_test_with_otps']);
deferredResult.addMethod(user, 'login');
deferredResult.shouldFail("login in using the wrong username with the OTP should fail");
deferredResult.addMethod(user2, 'login');
deferredResult.shouldFail("trying to reuse the same OTP should fail, even if now it is used with the correct username");
deferredResult.callback();
return deferredResult;
},
//-------------------------------------------------------------------------
'loginUserWithAPassphraseLookingExactlyLikeAnOTP_test': function (someTestArgs) {
var deferredResult;
var proxy;
var user;
var username;
var passphrase;
username = "otp_user";
passphrase = "yaxx k7ww - f8y6 tqz5 - 58b6 th44 - 9cwv q0fg"; // passphrase
proxy = new Clipperz.PM.Proxy.Test({shouldPayTolls:true, isDefault:true, readOnly:false});
user = new Clipperz.PM.DataModel.User({username:username, getPassphraseFunction:function () { return passphrase;}});
deferredResult = new Clipperz.Async.Deferred("loginUserWithAPassphraseLookingExactlyLikeAnOTP_test", someTestArgs);
deferredResult.addMethod(proxy.dataStore(), 'setupWithEncryptedData', testData['otp_user_test']);
deferredResult.addMethod(user, 'login');
deferredResult.addMethod(user, 'getRecords');
deferredResult.addCallback(MochiKit.Base.itemgetter('length'));
deferredResult.addTest(1, "This account has one single card");
deferredResult.callback();
return deferredResult;
},
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
'syntaxFix': MochiKit.Base.noop
};
//#############################################################################
SimpleTest.runDeferredTests("Clipperz.PM.DataModel.OneTimePassword", tests, {trace:false});

View File

@ -0,0 +1,94 @@
<!--
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/.
-->
<html>
<head>
<title>Clipperz.PM.DataModel.Record - test</title>
<script>Clipperz = {}</script>
<script type="text/javascript" src="../../../../../js/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="../../../../SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="../../../../SimpleTest/test.css">
<script type='text/javascript' src='../../../../../js/Clipperz/YUI/Utils.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Base.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Date.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/ByteArray.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Logging.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Async.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Signal.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Set.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/KeyValueObjectStore.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/Base.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/BigInt.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/AES.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/AES_2.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/SHA.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/PRNG.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/SRP.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Toll.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Strings.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Strings/Strings_en-US.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Date.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Proxy.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Proxy/Proxy.Offline.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Proxy/Proxy.Test.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Connection.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Crypto.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Strings.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Strings/Strings_en-US.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Date.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/EncryptedRemoteObject.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/Record.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/Record.Version.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/Record.Version.Field.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/DirectLogin.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/DirectLoginInput.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/DirectLoginBinding.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/DirectLoginFormValue.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.Header.Legacy.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.Header.RecordIndex.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.Header.Preferences.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.Header.OneTimePasswords.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/OneTimePassword.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.AccountInfo.js'></script>
<script type="text/javascript" src="../../../../SimpleTest/SimpleTest.Async.js"></script>
</head>
<body>
<pre id="test">
<script>
Clipperz.PM.Strings.Languages.setSelectedLanguage('en-us');
</script>
<script type="text/javascript" src="DirectLoginConfigurations.data.js"></script>
<script type="text/javascript" src="User.data.js"></script>
<script type="text/javascript" src="Record.test.js"></script>
</pre>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,102 @@
<!--
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/.
-->
<html>
<head>
<title>Clipperz.PM.DataModel.User - test</title>
<script>Clipperz = {}</script>
<script type="text/javascript" src="../../../../../js/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="../../../../SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="../../../../SimpleTest/test.css">
<script type='text/javascript' src='../../../../../js/Clipperz/YUI/Utils.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Base.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Date.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/ByteArray.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Logging.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Async.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Signal.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/KeyValueObjectStore.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/Base.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/BigInt.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/AES.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/AES_2.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/SHA.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/PRNG.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/Crypto/SRP.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Toll.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Proxy.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Proxy/Proxy.Offline.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Proxy/Proxy.Test.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Proxy/Proxy.Offline.DataStore.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Connection.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Crypto.js'></script>
<!-- script type='text/javascript' src='../../../../../js/Clipperz/PM/UI/Common/Controllers/DirectLoginRunner.js'></script -->
<script type='text/javascript' src='../../../../../js/Clipperz/PM/UI/DirectLoginController.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Strings.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Strings/Strings_en-US.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/Date.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/EncryptedRemoteObject.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/Record.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/Record.Version.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/Record.Version.Field.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/DirectLogin.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/DirectLoginInput.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/DirectLoginBinding.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/DirectLoginFormValue.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.Header.Legacy.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.Header.RecordIndex.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.Header.Preferences.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.Header.OneTimePasswords.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/OneTimePassword.js'></script>
<script type='text/javascript' src='../../../../../js/Clipperz/PM/DataModel/User.AccountInfo.js'></script>
<script type="text/javascript" src="../../../../SimpleTest/SimpleTest.Async.js"></script>
<script>
Clipperz_IEisBroken = false;
</script>
<!--[if IE]><script>
Clipperz_IEisBroken = true;
Clipperz_normalizedNewLine = '\x0d\x0a';
</script><![endif]-->
</head>
<body>
<pre id="test">
<script>
Clipperz.PM.Strings.Languages.setSelectedLanguage('en-us');
</script>
<script type="text/javascript" src="User.data.js"></script>
<script type="text/javascript" src="User.data.old.js"></script>
<script type="text/javascript" src="User.test.js"></script>
</pre>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,42 @@
<!--
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/.
-->
<html>
<head>
<title>Clipperz.PM.DataModel.* - tests</title>
<script type="text/javascript" src="../../../../../js/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="../../../../SimpleTest/TestRunner.js"></script>
</head>
<body>
<script>
TestRunner.runTests(
'DirectLogin.html',
'EncryptedRemoteObject.html',
'OneTimePassword.html',
'Record.html',
'User.html'
);
</script>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More