45 files changed, 5021 insertions, 806 deletions
diff --git a/frontend/gamma/js/Clipperz/Async.js b/frontend/gamma/js/Clipperz/Async.js index 97d8ecf..f7a9517 100644 --- a/frontend/gamma/js/Clipperz/Async.js +++ b/frontend/gamma/js/Clipperz/Async.js @@ -513,9 +513,9 @@ MochiKit.Base.update(Clipperz.Async, { return MochiKit.Base.map(function (aResult) { if (aResult[0]) { return aResult[1]; - } else { + } else { throw aResult[1]; - } + } }, aResultList); }); diff --git a/frontend/gamma/js/Clipperz/Base.js b/frontend/gamma/js/Clipperz/Base.js index 76b2c3f..9d399d9 100644 --- a/frontend/gamma/js/Clipperz/Base.js +++ b/frontend/gamma/js/Clipperz/Base.js @@ -77,6 +77,11 @@ MochiKit.Base.update(Clipperz.Base, { return MochiKit.Base.compose(function(aResult) { return -aResult; }, aComparator); }, + 'caseInsensitiveKeyComparator': function (aKey) { + return function (a, b) { + return MochiKit.Base.compare(a[aKey].toLowerCase(), b[aKey].toLowerCase()); + } + }, //------------------------------------------------------------------------- /* 'dependsOn': function(module, deps) { diff --git a/frontend/gamma/js/Clipperz/PM/Connection.js b/frontend/gamma/js/Clipperz/PM/Connection.js index b4e8aaa..a05a310 100644 --- a/frontend/gamma/js/Clipperz/PM/Connection.js +++ b/frontend/gamma/js/Clipperz/PM/Connection.js @@ -41,6 +41,7 @@ Clipperz.PM.Connection = function (args) { this._clipperz_pm_crypto_version = null; this._connectionId = null; this._sharedSecret = null; + this._serverLockValue = null; return this; } @@ -146,6 +147,16 @@ MochiKit.Logging.logError("### Connection.defaultErrorHandler: " + anErrorString this._connectionId = aValue; }, + //------------------------------------------------------------------------- + + 'serverLockValue': function () { + return this._serverLockValue; + }, + + 'setServerLockValue': function (aValue) { + this._serverLockValue = aValue; + }, + //========================================================================= /* // TODO: ????? @@ -320,13 +331,12 @@ Clipperz.PM.Connection.SRP['1.0'].prototype = MochiKit.Base.update(new Clipperz. ], {trace:false}) }, - 'login': function(/*anUsername, aPassphrase*/) { + 'login': function(isReconnecting) { var deferredResult; var cryptoVersion; var srpConnection; cryptoVersion = this.clipperz_pm_crypto_version(); - deferredResult = new Clipperz.Async.Deferred("Connection.login", {trace:false}); deferredResult.addCallback(this.getCredentialsFunction()); deferredResult.addMethod(this, 'normalizedCredentials'); @@ -399,6 +409,13 @@ Clipperz.PM.Connection.SRP['1.0'].prototype = MochiKit.Base.update(new Clipperz. // if (this.oneTimePassword() != null) { /// ?? result = this.user().oneTimePasswordManager().archiveOneTimePassword(this.oneTimePassword())); // } + + if ((isReconnecting == true) && (this.serverLockValue() != someParameters['lock'])) { + throw Clipperz.PM.Connection.exception.StaleData; + } else { + this.setServerLockValue(someParameters['lock']); + } + return someParameters; }, this)); // deferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'updatedProgressState', 'connection_loggedIn'); @@ -429,12 +446,19 @@ Clipperz.PM.Connection.SRP['1.0'].prototype = MochiKit.Base.update(new Clipperz. 'message': function(aMessageName, someParameters) { var args; + var parameters; + + parameters = someParameters || {}; + if (typeof(parameters['user']) != 'undefined') { + parameters['user']['lock'] = this.serverLockValue(); + } //console.log(">>> Connection.message", aMessageName, someParameters); args = { message: aMessageName, srpSharedSecret: this.sharedSecret(), - parameters: (someParameters || {}) +// parameters: (someParameters || {}) + parameters: parameters } return this.sendMessage(args); @@ -449,8 +473,7 @@ Clipperz.PM.Connection.SRP['1.0'].prototype = MochiKit.Base.update(new Clipperz. deferredResult.addMethod(this.proxy(), 'message', someArguments); deferredResult.addCallback(MochiKit.Base.bind(function(res) { if (typeof(res['lock']) != 'undefined') { -// TODO: ????? -// ?? this.user().setLock(res['lock']); + this.setServerLockValue(res['lock']); } return res; }, this)); @@ -587,6 +610,7 @@ Clipperz.PM.Connection.SRP['1.1'].prototype = MochiKit.Base.update(new Clipperz. Clipperz.PM.Connection.exception = { WrongChecksum: new MochiKit.Base.NamedError("Clipperz.ByteArray.exception.InvalidValue"), + StaleData: new MochiKit.Base.NamedError("Stale data"), UnexpectedRequest: new MochiKit.Base.NamedError("Clipperz.ByteArray.exception.UnexpectedRequest") }; diff --git a/frontend/gamma/js/Clipperz/PM/DataModel/User.js b/frontend/gamma/js/Clipperz/PM/DataModel/User.js index 72d4006..646ce21 100644 --- a/frontend/gamma/js/Clipperz/PM/DataModel/User.js +++ b/frontend/gamma/js/Clipperz/PM/DataModel/User.js @@ -44,7 +44,7 @@ Clipperz.PM.DataModel.User = function (args) { this._connectionVersion = 'current'; this._serverData = null; - this._serverLockValue = null; +// this._serverLockValue = null; this._transientState = null; this._deferredLocks = { @@ -93,7 +93,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, { }, //------------------------------------------------------------------------- - +/* 'serverLockValue': function () { return this._serverLockValue; }, @@ -101,7 +101,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, { 'setServerLockValue': function (aValue) { this._serverLockValue = aValue; }, - +*/ //------------------------------------------------------------------------- 'transientState': function () { @@ -220,8 +220,8 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, { deferredResult.addMethod(this, 'prepareRemoteDataWithKey'); deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'advanceProgress'); deferredResult.addMethod(this.connection(), 'register'); - deferredResult.addCallback(MochiKit.Base.itemgetter('lock')); - deferredResult.addMethod(this, 'setServerLockValue'); +// deferredResult.addCallback(MochiKit.Base.itemgetter('lock')); +// deferredResult.addMethod(this, 'setServerLockValue'); deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'userSuccessfullyRegistered'); // deferredResult.addErrback (MochiKit.Base.method(this, 'handleRegistrationFailure')); @@ -247,7 +247,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, { MochiKit.Base.method(this.data(), 'setValue', 'passphrase') ], [])); deferredResult.addErrback(MochiKit.Base.method(this, 'getPassphrase')); - deferredResult.addMethod(this.connection(), 'login'); + deferredResult.addMethod(this.connection(), 'login', false); deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'userSuccessfullyLoggedIn'); deferredResult.addErrback (MochiKit.Base.method(this, 'handleConnectionFallback')); @@ -329,7 +329,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, { var oneTimePasswords; //console.log(">>> ***************** user.unpackServerData", someServerData); - this.setServerLockValue(someServerData['lock']); +// this.setServerLockValue(someServerData['lock']); headerVersion = this.headerFormatVersion(someServerData['header']); @@ -662,8 +662,8 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, { MochiKit.Base.method(this, 'invokeMethodNamedOnRecords', 'commitTransientState'), MochiKit.Base.method(this, 'transientState'), - MochiKit.Base.itemgetter('lock'), - MochiKit.Base.method(this, 'setServerLockValue'), +// MochiKit.Base.itemgetter('lock'), +// MochiKit.Base.method(this, 'setServerLockValue'), MochiKit.Base.method(this, 'resetTransientState', true) ], {trace:false}); }, @@ -740,7 +740,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, { return aResult; }, this), result); deferredResult.addCallback(Clipperz.Async.setItem, result, 'version', Clipperz.PM.Crypto.encryptingFunctions.currentVersion); - deferredResult.addCallback(Clipperz.Async.setItem, result, 'lock', this.serverLockValue()); +// deferredResult.addCallback(Clipperz.Async.setItem, result, 'lock', this.serverLockValue()); deferredResult.callback(); return deferredResult; diff --git a/frontend/gamma/js/Clipperz/PM/PIN.js b/frontend/gamma/js/Clipperz/PM/PIN.js new file mode 100644 index 0000000..bc932b2 --- a/dev/null +++ b/frontend/gamma/js/Clipperz/PM/PIN.js @@ -0,0 +1,134 @@ +/* + +Copyright 2008-2011 Clipperz Srl + +This file is part of Clipperz Community Edition. +Clipperz Community Edition is an online password manager. +For further information about its features and functionalities please +refer to http://www.clipperz.com. + +* Clipperz Community Edition 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 Community Edition 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 Community Edition. If not, see + <http://www.gnu.org/licenses/>. + +*/ + +if (typeof(Clipperz) == 'undefined') { Clipperz = {}; } +if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; } +if (typeof(Clipperz.PM.PIN) == 'undefined') { Clipperz.PM.PIN = {}; } + +MochiKit.Base.update(Clipperz.PM.PIN, { + + //------------------------------------------------------------------------- + + '__repr__': function () { + return "[" + this.NAME + " " + this.VERSION + "]"; + }, + + //------------------------------------------------------------------------- + + 'toString': function () { + return this.__repr__(); + }, + + 'CREDENTIALS': 'CLIPPERZ.CREDENTIALS', + 'FAILURE_COUNT': 'CLIPPERZ.FAILED_LOGIN_COUNT', + 'ALLOWED_RETRY': 3, + + //------------------------------------------------------------------------- + + 'isSet': function () { + return (this.storedCredentials() != null); + }, + + 'storedCredentials': function () { + return localStorage[this.CREDENTIALS]; + }, + + //------------------------------------------------------------------------- + + 'recordFailedAttempt': function () { + var failureCount; + var result; + + failureCount = localStorage[this.FAILURE_COUNT]; + + if (failureCount == null) { + failureCount = 0 + } + + failureCount ++; + + if (failureCount < this.ALLOWED_RETRY) { + localStorage[this.FAILURE_COUNT] = failureCount; + result = failureCount; + } else { + this.removeLocalCredentials(); + result = -1; + } + + return result; + }, + + 'resetFailedAttemptCount': function () { + localStorage.removeItem(this.FAILURE_COUNT); + }, + + 'failureCount': function () { + return localStorage[this.FAILURE_COUNT]; + }, + + //------------------------------------------------------------------------- + + 'deriveKeyFromPin': function (aPIN) { + return Clipperz.Crypto.SHA.sha256(new Clipperz.ByteArray(aPIN)); + }, + + 'credentialsWithPIN': function (aPIN) { + var byteArrayValue; + var decryptedValue; + var result; + + byteArrayValue = (new Clipperz.ByteArray()).appendBase64String(localStorage[this.CREDENTIALS]); + decryptedValue = Clipperz.Crypto.AES.decrypt(this.deriveKeyFromPin(aPIN), byteArrayValue).asString(); + try { + result = Clipperz.Base.evalJSON(decryptedValue); + } catch (error) { + result = {'username':'fakeusername', 'passphrase':'fakepassphrase'}; + } + + return result; + }, + + 'setCredentialsWithPIN': function (aPIN, someCredentials) { + var encodedValue; + var byteArrayValue; + var encryptedValue; + + encodedValue = Clipperz.Base.serializeJSON(someCredentials); + byteArrayValue = new Clipperz.ByteArray(encodedValue); + encryptedValue = Clipperz.Crypto.AES.encrypt(this.deriveKeyFromPin(aPIN), byteArrayValue).toBase64String(); + + localStorage[this.CREDENTIALS] = encryptedValue; + }, + + 'removeLocalCredentials': function () { + localStorage.removeItem(this.CREDENTIALS); + localStorage.removeItem(this.FAILURE_COUNT); + }, + + //------------------------------------------------------------------------- + __syntaxFix__: "syntax fix" + +}); + diff --git a/frontend/gamma/js/Clipperz/PM/Proxy/Proxy.OfflineCache.js b/frontend/gamma/js/Clipperz/PM/Proxy/Proxy.OfflineCache.js new file mode 100644 index 0000000..803c590 --- a/dev/null +++ b/frontend/gamma/js/Clipperz/PM/Proxy/Proxy.OfflineCache.js @@ -0,0 +1,65 @@ +/* + +Copyright 2008-2011 Clipperz Srl + +This file is part of Clipperz Community Edition. +Clipperz Community Edition is an online password manager. +For further information about its features and functionalities please +refer to http://www.clipperz.com. + +* Clipperz Community Edition 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 Community Edition 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 Community Edition. If not, see + <http://www.gnu.org/licenses/>. + +*/ + +if (typeof(Clipperz) == 'undefined') { Clipperz = {}; } +if (typeof(Clipperz.PM) == 'undefined') { Clipperz.PM = {}; } + +//============================================================================= + +Clipperz.PM.Proxy.OfflineCache = function(args) { + args = args || {}; + + Clipperz.PM.Proxy.Offline.superclass.constructor.call(this, args); + +// this._dataStore = args.dataStore || new Clipperz.PM.Proxy.Offline.DataStore(args); + + return this; +} + +Clipperz.Base.extend(Clipperz.PM.Proxy.OfflineCache, Clipperz.PM.Proxy, { + + 'toString': function () { + return "Clipperz.PM.Proxy.OfflineCache"; + }, + + //------------------------------------------------------------------------- + +// 'dataStore': function () { +// return this._dataStore; +// }, + + //------------------------------------------------------------------------- + + 'sendMessage': function(aFunctionName, someParameters) { + throw Clipperz.Base.exception.MethodNotImplementedYet; +// return this.dataStore().processMessage(aFunctionName, someParameters); + }, + + //------------------------------------------------------------------------- + + __syntaxFix__: "syntax fix" + +}); + diff --git a/frontend/gamma/js/Clipperz/PM/UI/Common/Components/BaseComponent.js b/frontend/gamma/js/Clipperz/PM/UI/Common/Components/BaseComponent.js index 2a03fdf..b9d7adf 100644 --- a/frontend/gamma/js/Clipperz/PM/UI/Common/Components/BaseComponent.js +++ b/frontend/gamma/js/Clipperz/PM/UI/Common/Components/BaseComponent.js @@ -406,6 +406,10 @@ Clipperz.Base.extend(Clipperz.PM.UI.Common.Components.BaseComponent, /*Ext.Compo return result; }, + 'getAnchor': function (aValue) { + return '#' + this.getId(aValue); + }, + //------------------------------------------------------------------------- 'getElement': function(aValue) { diff --git a/frontend/gamma/js/Clipperz/PM/UI/Common/Components/Button.js b/frontend/gamma/js/Clipperz/PM/UI/Common/Components/Button.js index 716d851..1010c9d 100644 --- a/frontend/gamma/js/Clipperz/PM/UI/Common/Components/Button.js +++ b/frontend/gamma/js/Clipperz/PM/UI/Common/Components/Button.js @@ -62,7 +62,8 @@ Clipperz.Base.extend(Clipperz.PM.UI.Common.Components.Button, Clipperz.PM.UI.Com //------------------------------------------------------------------------- 'renderSelf': function () { - this.append(this.element(), {tag:'div', id:this.getId('wrapper'), cls:'button_wrapper', children:[ +/* + this.append(this.element(), {tag:'div', id:this.getId('button'), cls:'button_wrapper', children:[ {tag:'div', id:this.getId('bodyWrapper'), cls:'button_bodyWrapper', children:[ {tag:'div', id:this.getId('body'), cls:'button_body', children:[ {tag:'span', html:this.text()} @@ -70,36 +71,43 @@ Clipperz.Base.extend(Clipperz.PM.UI.Common.Components.Button, Clipperz.PM.UI.Com {tag:'div', id:this.getId('footer'), cls:'button_footer'} ]} ]}); +*/ +/* + this.append(this.element(), {tag:'div', id:this.getId('button'), cls:'button', children:[ + {tag:'span', html:this.text()} + ]}); +*/ + this.append(this.element(), {tag:'a', id:this.getId('button'), cls:'button', html:this.text()}); if (this.isDefault()) { - MochiKit.DOM.addElementClass(this.getId('wrapper'), 'default'); + MochiKit.DOM.addElementClass(this.getId('button'), 'default'); } - MochiKit.Signal.connect(this.getId('wrapper'), 'onmouseenter', this, 'handleOnMouseEnter'); - MochiKit.Signal.connect(this.getId('wrapper'), 'onmouseleave', this, 'handleOnMouseLeave'); - MochiKit.Signal.connect(this.getId('wrapper'), 'onmousedown', this, 'handleOnMouseDown'); - MochiKit.Signal.connect(this.getId('wrapper'), 'onclick', this, 'handleOnClick'); +// MochiKit.Signal.connect(this.getId('button'), 'onmouseenter', this, 'handleOnMouseEnter'); +// MochiKit.Signal.connect(this.getId('button'), 'onmouseleave', this, 'handleOnMouseLeave'); +// MochiKit.Signal.connect(this.getId('button'), 'onmousedown', this, 'handleOnMouseDown'); + MochiKit.Signal.connect(this.getId('button'), 'onclick', this, 'handleOnClick'); }, //------------------------------------------------------------------------- - +/* 'handleOnMouseEnter': function (anEvent) { - MochiKit.DOM.addElementClass(this.getId('wrapper'), 'hover'); + MochiKit.DOM.addElementClass(this.getId('button'), 'hover'); }, 'handleOnMouseLeave': function (anEvent) { - MochiKit.DOM.removeElementClass(this.getId('wrapper'), 'hover'); - MochiKit.DOM.removeElementClass(this.getId('wrapper'), 'clicked'); + MochiKit.DOM.removeElementClass(this.getId('button'), 'hover'); + MochiKit.DOM.removeElementClass(this.getId('button'), 'clicked'); }, 'handleOnMouseDown': function (anEvent) { - MochiKit.DOM.addElementClass(this.getId('wrapper'), 'clicked'); + MochiKit.DOM.addElementClass(this.getId('button'), 'clicked'); }, - +*/ 'handleOnClick': function (anEvent) { MochiKit.Signal.signal(this, 'onclick', anEvent); }, - + //------------------------------------------------------------------------- __syntaxFix__: "syntax fix" }); diff --git a/frontend/gamma/js/Clipperz/PM/UI/Common/Components/SimpleMessagePanel.js b/frontend/gamma/js/Clipperz/PM/UI/Common/Components/SimpleMessagePanel.js index 1992154..1d816a9 100644 --- a/frontend/gamma/js/Clipperz/PM/UI/Common/Components/SimpleMessagePanel.js +++ b/frontend/gamma/js/Clipperz/PM/UI/Common/Components/SimpleMessagePanel.js @@ -98,14 +98,29 @@ Clipperz.Base.extend(Clipperz.PM.UI.Common.Components.SimpleMessagePanel, Clippe }, 'setType': function (aValue) { - if (this.getElement('icon') != null) { - MochiKit.DOM.removeElementClass(this.getId('icon'), this._type); - MochiKit.DOM.addElementClass(this.getId('icon'), aValue); - } +// if (this.getElement('icon') != null) { +// MochiKit.DOM.removeElementClass(this.getId('icon'), this._type); +// MochiKit.DOM.addElementClass(this.getId('icon'), aValue); +// } this._type = aValue; }, + 'icon': function () { + var type = this.type(); + var result; + + if (type == 'ALERT') { + result = '!'; + } else if (type == 'INFO') { + result = 'i'; + } else if (type == 'ERROR') { + result = '!'; + } + + return result; + }, + //------------------------------------------------------------------------- 'buttons': function () { @@ -132,17 +147,20 @@ Clipperz.Base.extend(Clipperz.PM.UI.Common.Components.SimpleMessagePanel, Clippe 'renderSelf': function() { this.append(this.element(), {tag:'div', cls:'SimpleMessagePanel', id:this.getId('panel'), children: [ - {tag:'div', cls:'header', children:[]}, +// {tag:'div', cls:'header', children:[]}, {tag:'div', cls:'body', children:[ - {tag:'div', id:this.getId('icon'), cls:'img ' + this.type(), children:[{tag:'div'}]}, +// {tag:'div', id:this.getId('icon'), cls:'img ' + this.type(), children:[{tag:'div'}]}, + {tag:'div', /*id:this.getId('icon'),*/ cls:'img ' + this.type(), children:[{tag:'canvas', id:this.getId('icon')}]}, {tag:'h3', id:this.getId('title'), html:this.title()}, {tag:'p', id:this.getId('text'), html:this.text()}, {tag:'div', id:this.getId('container')}, {tag:'div', id:this.getId('buttonArea'), cls:'buttonArea', children:[]} - ]}, - {tag:'div', cls:'footer', children:[]} + ]} +// {tag:'div', cls:'footer', children:[]} ]}); + Clipperz.PM.UI.Canvas.marks[this.icon()](this.getElement('icon'), "#ffffff"); + MochiKit.Signal.connect(this.getId('panel'), 'onkeydown', this, 'keyDownHandler'); this.renderButtons(); diff --git a/frontend/gamma/js/Clipperz/PM/UI/Mobile/Components/CardDetail.js b/frontend/gamma/js/Clipperz/PM/UI/Mobile/Components/CardDetail.js new file mode 100644 index 0000000..32dfa63 --- a/dev/null +++ b/frontend/gamma/js/Clipperz/PM/UI/Mobile/Components/CardDetail.js @@ -0,0 +1,299 @@ +/* + +Copyright 2008-2011 Clipperz Srl + +This file is part of Clipperz Community Edition. +Clipperz Community Edition is an online password manager. +For further information about its features and functionalities please +refer to http://www.clipperz.com. + +* Clipperz Community Edition 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 Community Edition 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 Community Edition. If not, see + <http://www.gnu.org/licenses/>. + +*/ + +Clipperz.Base.module('Clipperz.PM.UI.Mobile.Components'); + +Clipperz.PM.UI.Mobile.Components.CardDetail = function(args) { + args = args || {}; + + Clipperz.PM.UI.Mobile.Components.CardDetail.superclass.constructor.apply(this, arguments); + +// this._cardReference = null; + + return this; +} + +//============================================================================= + +Clipperz.Base.extend(Clipperz.PM.UI.Mobile.Components.CardDetail, Clipperz.PM.UI.Common.Components.BaseComponent, { + + //------------------------------------------------------------------------- + + 'toString': function () { + return "Clipperz.PM.UI.Mobile.Components.CardDetail component"; + }, + + //------------------------------------------------------------------------- +/* + 'cardReference': function () { + return this._cardReference; + }, + + 'setCardReference': function (aValue) { + this._cardReference = aValue; + }, +*/ + //------------------------------------------------------------------------- + + 'renderSelf': function () { +console.log("CardDetail.renderSelf"); + this.append(this.element(), {tag:'div', cls:'cardDetail', children:[ + {tag:'div', cls:'toolbar', children:[ + {tag:'a', href:'#', cls:'back', html:"List"}, + {tag:'h1', id:this.getId('cardTitle'), html:"…"} + ]}, + {tag:'div', cls:'scroll', id:this.getId('cardDetails'), children:[ + ]} + ]}); + }, +/* + 'renderSelf': function() { + this.append(this.element(), [ + {tag:'div', cls:'cardDetail', id:this.getId('cardDetail'), children:[ + {tag:'div', id:this.getId('progressBar')} //, + ]} + ]); + + this.addComponent(new Clipperz.PM.UI.Common.Components.ProgressBar({'element':this.getElement('progressBar')})); + MochiKit.Signal.signal(Clipperz.PM.UI.Common.Controllers.ProgressBarController.defaultController, 'updateProgress', 0); + }, +*/ + + 'setTitle': function (aValue) { + this.getElement('cardTitle').innerHTML = aValue; + }, + + 'fieldListElement': function () { + var result; + + result = this.getElement('fieldList'); + if (result == null) { + result = this.append(this.getElement('cardDetails'), {tag:'ul', cls:'rounded', id:this.getId('fieldList')}); + } + + return result; + }, + + 'renderFieldValues': function (someFieldValues) { + var fieldClass; + + if ((someFieldValues['actionType'] != 'NONE') || (someFieldValues['label'] != '') && (someFieldValues['value'] != '')) { + if (someFieldValues['isHidden'] == true) { + fieldClass = 'password'; + } else { + fieldClass = ''; + } + + this.append(this.fieldListElement(), {tag:'li', cls:'cardField', children:[ + {tag:'a', href:'#', cls:fieldClass, html:someFieldValues['value'], children:[ + {tag:'small', cls:'label', html:someFieldValues['label']} + ]} + ]}) + } + }, + + 'addField': function (aField) { + var deferredResult; + var fieldValues; + + fieldValues = {}; + deferredResult = new Clipperz.Async.Deferred("CardDetail.addField", {trace:false}); + deferredResult.addMethod(aField, 'label'); + deferredResult.addCallback(function (aValue) { fieldValues['label'] = aValue; }); + deferredResult.addMethod(aField, 'value'); + deferredResult.addCallback(function (aValue) { fieldValues['value'] = aValue; }); + deferredResult.addMethod(aField, 'actionType'); + deferredResult.addCallback(function (aValue) { fieldValues['actionType'] = aValue; }); + deferredResult.addMethod(aField, 'isHidden'); + deferredResult.addCallback(function (aValue) { fieldValues['isHidden'] = aValue; }); + deferredResult.addMethod(this, 'renderFieldValues', fieldValues); + deferredResult.callback(); + + return deferredResult; + }, + + //------------------------------------------------------------------------- + + 'directLoginElement': function () { + var result; + + result = this.getElement('directLoginList'); + if (result == null) { + this.append(this.getElement('cardDetails'), {tag:'h2', html:"Direct login"}); + result = this.append(this.getElement('cardDetails'), {tag:'ul', cls:'rounded', id:this.getId('directLoginList')}); + } + + return result; + }, + + 'addDirectLogin': function (aDirectLogin) { + this.append(this.directLoginElement(), {tag:'li', cls:'directLogin forward', children:[ + {tag:'a', href:'#', html:"direct login", children:[ + {tag:'small', cls:'favicon', children:[{tag:'img', cls:'favicon', src:'http://www.clipperz.com/favicon.ico'}]} + ]} + ]}) + +console.log("ADD DIRECT LOGIN", aDirectLogin); + }, + + //========================================================================= + + 'showCard': function (aCard) { + var deferredResult; + +// this.render(); + +console.log("CardDetail.showCard", aCard); + deferredResult = new Clipperz.Async.Deferred("CardDetail.showCard", {trace:false}); + deferredResult.addMethod(aCard, 'label'); + deferredResult.addMethod(this, 'setTitle'); + + deferredResult.addMethod(aCard, 'fields'); + deferredResult.addCallback(MochiKit.Base.values); + deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.method(this, 'addField')); + + deferredResult.addMethod(aCard, 'directLogins'); + deferredResult.addCallback(MochiKit.Base.values); + deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.method(this, 'addDirectLogin')); + + + deferredResult.callback(); + + return deferredResult; +// return Clipperz.Async.callbacks("CardDialogController.updateComponentState", [ +// MochiKit.Base.method(this.record(), 'hasPendingChanges'), +// MochiKit.Base.method(this.cardDialogComponent(), 'setShouldEnableSaving'), +// +// MochiKit.Base.method(this.record(), 'label'), +// MochiKit.Base.method(this.cardDialogComponent(), 'setTitle'), +// MochiKit.Base.method(this.record(), 'notes'), +// MochiKit.Base.method(this.cardDialogComponent(), 'setNotes'), +// +// MochiKit.Base.method(this.record(), 'fields'), +// MochiKit.Base.values, +// MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.method(this, 'addCardDialogComponentWithField')), +// +// MochiKit.Base.method(this.record(), 'directLogins'), +// MochiKit.Base.values, +// MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.method(this, 'addCardDialogComponentWithDirectLogin')), +// +// MochiKit.Base.method(this.cardDialogComponent(), 'resetNewFieldInputs'), +// MochiKit.Base.noop +// ], {trace:false}); + + }, + + //========================================================================= + + 'showCardDetails': function (someData) { + this.element().innerHTML = ''; + this.append(this.element(), [ + {tag:'fieldset', id:this.getId('fields'), children:MochiKit.Base.map(function (aFieldData) { + return {tag:'div', cls:'row', children:[ + {tag:'label', html:aFieldData['label']}, +// {tag:'span', cls:('fieldValue ' + (aFieldData['isHidden'] ? 'password' : 'text')), html:aFieldData['value']} + {tag:'div', cls:('fieldValue ' + (aFieldData['isHidden'] ? 'password' : 'text')), children:[ + {tag:'div', children:[{tag:'p', html:aFieldData['value']}]} + ]} +// {tag:'input', type:'text', cls:('fieldValue ' + (aFieldData['isHidden'] ? 'password' : 'text')), value:aFieldData['value'], disabled:true} + + ]} + }, someData['fields'])} + ]); + + MochiKit.Iter.forEach(MochiKit.Selector.findChildElements(this.element(), ['span.password']), MochiKit.Base.bind(function (aPasswordElement) { + MochiKit.Signal.connect(aPasswordElement, 'onclick', function (anEvent) { alert(MochiKit.DOM.scrapeText(anEvent.src())); }) + }, this)); + + if (someData['directLogins'].length > 0) { + this.append(this.element(), [ + {tag:'h2', html:"Direct logins"}, + {tag:'fieldset', id:this.getId('directLogins'), children:MochiKit.Base.map(function (aDirectLoginData) { + return {tag:'div', cls:'row', id:('directLogin_' + aDirectLoginData['_reference']), children:[ + {tag:'img', cls:'favicon', src:aDirectLoginData['favicon']}, +// {tag:'input', cls:'directLogin', disabled:'disabled', type:'text', name:aDirectLoginData['label'], value:aDirectLoginData['label']} + {tag:'span', cls:'directLogin', html:aDirectLoginData['label']} + ]} + }, someData['directLogins'])} + ]); + + MochiKit.Base.map(MochiKit.Base.bind(function (aRowNode) { + MochiKit.Signal.connect(aRowNode, 'onclick', this, 'directLoginClickHandler'); + }, this), + MochiKit.Selector.findChildElements(this.getElement('directLogins'), ['div.row']) + ) + }; + + if (someData['notes'] != '') { + this.append(this.element(), [ + {tag:'h2', html:"Notes"}, + {tag:'fieldset', id:this.getId('fieldset'), children:[ + {tag:'div', cls:'row notes', children:[ + {tag:'span', html:someData['notes']} + ]} + ]} + ]); + }; + + return true; + }, + + //------------------------------------------------------------------------- +/* + 'toggleClickHandler': function (anEvent) { + var nextState; + var fieldValue; + +//console.log("TOGGLE"); + anEvent.preventDefault; + fieldValue = MochiKit.Selector.findChildElements(anEvent.src().parentNode.parentNode, ['span.password'])[0]; + + nextState = (MochiKit.DOM.getNodeAttribute(anEvent.src(), 'toggled') != 'true'); + if (nextState) { + MochiKit.DOM.removeElementClass(fieldValue, 'clear'); + } else { + MochiKit.DOM.addElementClass(fieldValue, 'clear'); + } + + MochiKit.DOM.setNodeAttribute(anEvent.src(), 'toggled', nextState); + }, +* / + //========================================================================= +/* + 'directLoginClickHandler': function (anEvent) { + anEvent.preventDefault(); + + if (/(directLogin_)/.test(anEvent.src().id)) { + var directLoginReference; + + directLoginReference = anEvent.src().id.match(/(directLogin_)(.*)/)[2]; + MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectedDirectLogin', {cardReference:this.cardReference(), directLoginReference:directLoginReference}); + } + }, +*/ + //========================================================================= + + __syntaxFix__: "syntax fix" +}); diff --git a/frontend/gamma/js/Clipperz/PM/UI/iPhone/Components/CardList.js b/frontend/gamma/js/Clipperz/PM/UI/Mobile/Components/CardList.js index c3f2701..a4aa212 100644 --- a/frontend/gamma/js/Clipperz/PM/UI/iPhone/Components/CardList.js +++ b/frontend/gamma/js/Clipperz/PM/UI/Mobile/Components/CardList.js @@ -23,12 +23,12 @@ refer to http://www.clipperz.com. */ -Clipperz.Base.module('Clipperz.PM.UI.iPhone.Components'); +Clipperz.Base.module('Clipperz.PM.UI.Mobile.Components'); -Clipperz.PM.UI.iPhone.Components.CardList = function(args) { +Clipperz.PM.UI.Mobile.Components.CardList = function(args) { args = args || {}; - Clipperz.PM.UI.iPhone.Components.CardList.superclass.constructor.apply(this, arguments); + Clipperz.PM.UI.Mobile.Components.CardList.superclass.constructor.apply(this, arguments); this._cardDetail = null; @@ -37,44 +37,97 @@ Clipperz.PM.UI.iPhone.Components.CardList = function(args) { //============================================================================= -Clipperz.Base.extend(Clipperz.PM.UI.iPhone.Components.CardList, Clipperz.PM.UI.Common.Components.BaseComponent, { +Clipperz.Base.extend(Clipperz.PM.UI.Mobile.Components.CardList, Clipperz.PM.UI.Common.Components.BaseComponent, { //------------------------------------------------------------------------- 'toString': function () { - return "Clipperz.PM.UI.iPhone.Components.CardList component"; + return "Clipperz.PM.UI.Mobile.Components.CardList component"; }, //------------------------------------------------------------------------- - 'renderSelf': function(/*aContainer, aPosition*/) { - this.append(this.element(), [ - {tag:'div', cls:'toolbar', id:'toolbar', children:[ - {tag:'h1', id:'pageTitle', html:"cards"}, - {tag:'a', id:'backButton', cls:'button', href:'#', html:"cards"} + 'renderSelf': function () { + this.append(this.element(), {tag:'div', cls:'cardList', children:[ + {tag:'div', cls:'toolbar', children:[ + {tag:'h1', html:"clipperz"}, +// {tag:'input', name:'search', type:'search', autocomplete:'off', placeholder:"search", id:this.getId('search')}, + {tag:'a', href:'#', id:'settings', cls:'button', html:"*"} ]}, - {tag:'div', cls:'cardList', id:this.getId('cardList'), children:[ - {tag:'form', title:'search', cls:'panel cardListSearchForm', id:this.getId('cardListSearchForm'), children:[ - {tag:'input', type:'search', name:'search', value:"", placeholder:"search", id:this.getId('searchField')} - ]}, - {tag:'ul', cls:'panel cardListPanel', id:this.getId('cardListPanel'), children:[]} - ]}, - {tag:'div', cls:'panel cardDetailPanel', id:this.getId('cardDetail')} - ]); - - MochiKit.Signal.connect(this.getElement('cardListSearchForm'), 'onsubmit', this, 'searchHandler'); - MochiKit.Signal.connect(this.getElement('cardListSearchForm'), 'onkeydown', this, 'searchHandler'); - MochiKit.Signal.connect(this.getElement('cardListSearchForm'), 'onkeyup', this, 'searchHandler'); + {tag:'div', cls:'scroll', id:this.getId('listBox'), children:[ + {tag:'ul', cls:'rounded', id:this.getId('list'), children:[ + {tag:'li', html:'loading'} + ]} + ]} + ]}); + + MochiKit.Signal.connect(this.getElement('list'), 'onclick', this, 'cardSelectionHandler'); + MochiKit.Signal.connect(this.getElement('list'), 'ontouchstart', this, 'cardSelectionHandler'); +// MochiKit.Signal.connect(this.getElement('cardListSearchForm'), 'onsubmit', this, 'searchHandler'); +// MochiKit.Signal.connect(this.getElement('cardListSearchForm'), 'onkeydown', this, 'searchHandler'); +// MochiKit.Signal.connect(this.getElement('cardListSearchForm'), 'onkeyup', this, 'searchHandler'); - MochiKit.Signal.connect(this.getElement('cardListPanel'), 'onclick', this, 'cardListClickHandler'); - MochiKit.Signal.connect('backButton', 'onclick', this, 'backButtonClickHandler'); +// MochiKit.Signal.connect(this.getElement('cardListPanel'), 'onclick', this, 'cardListClickHandler'); +// MochiKit.Signal.connect('backButton', 'onclick', this, 'backButtonClickHandler'); - MochiKit.Style.hideElement('backButton'); - MochiKit.Style.hideElement(this.getElement('cardDetail')); +// MochiKit.Style.hideElement('backButton'); +// MochiKit.Style.hideElement(this.getElement('cardDetail')); }, - //------------------------------------------------------------------------- + 'showCards': function (someCards) { + var cardListElement; + if (this.isFullyRendered() == false) { + this.render(); + }; + + cardListElement = this.getElement('list') + + 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') + }; + +//console.log("someCards", someCards); + deferredResult = new Clipperz.Async.Deferred("CardList.showCards", {trace:false}); + deferredResult.addCallback(MochiKit.Base.map, Clipperz.Async.collectResults("CardList.value - collectResults", cardInfo, {trace:false})); + deferredResult.addCallback(Clipperz.Async.collectAll); + deferredResult.addCallback(MochiKit.Base.methodcaller('sort', Clipperz.Base.caseInsensitiveKeyComparator('label'))); + deferredResult.addCallbackPass(MochiKit.DOM.replaceChildNodes, cardListElement); +// deferredResult.addCallbackPass(MochiKit.DOM.removeElementClass, cardListElement, 'loading'); + deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.method(this, 'appendCardToList', cardListElement)); + deferredResult.callback(someCards); + }, + + 'appendCardToList': function (aCardListElement, aCardInfo) { +//console.log("appendCardToList", aCardInfo); + this.append(aCardListElement, {tag:'li', cls:'cardListItem arrow', cardreference:aCardInfo['_reference'], children:[ + {tag:'a', href:'#', html:aCardInfo['label'], children:[ + {tag:'small', cls:'favicon', children:[{tag:'img', cls:'favicon', src:aCardInfo['favicon']}]} + ]} + ]}); + }, + + 'cardSelectionHandler': function (anEvent) { + var listElement; + var cardReference; + + anEvent.preventDefault(); + + listElement = anEvent.target(); + if (MochiKit.DOM.getNodeAttribute(listElement, 'cardreference') == null) { + listElement = MochiKit.DOM.getFirstParentByTagAndClassName(anEvent.target(), tagName='li', className='cardListItem'); + } + cardReference = MochiKit.DOM.getNodeAttribute(listElement, 'cardreference'); +console.log("###", listElement, cardReference); + // TODO: Notify card with reference MochiKit.DOM.getNodeAttribute(listElement, 'cardreference') has been selected + MochiKit.Signal.signal(this, 'selectedCard', cardReference); + }, + //------------------------------------------------------------------------- +/* 'searchHandler': function (anEvent) { if ((typeof(anEvent.key()) != 'undefined') && (anEvent.key().string == 'KEY_ENTER')) { // RETURN anEvent.preventDefault(); @@ -127,7 +180,7 @@ Clipperz.Base.extend(Clipperz.PM.UI.iPhone.Components.CardList, Clipperz.PM.UI.C 'cardDetail': function (someData) { if (this._cardDetail == null) { - this._cardDetail = new Clipperz.PM.UI.iPhone.Components.CardDetail({element:this.getElement('cardDetail')}); + this._cardDetail = new Clipperz.PM.UI.Mobile.Components.CardDetail({element:this.getElement('cardDetail')}); } return this._cardDetail; @@ -195,7 +248,7 @@ Clipperz.Base.extend(Clipperz.PM.UI.iPhone.Components.CardList, Clipperz.PM.UI.C ], {duration:1, afterFinish:MochiKit.Base.method(this, 'removeCardDetail')}) }, - +*/ //========================================================================= __syntaxFix__: "syntax fix" }); diff --git a/frontend/gamma/js/Clipperz/PM/UI/Mobile/Components/LoginForm.js b/frontend/gamma/js/Clipperz/PM/UI/Mobile/Components/LoginForm.js new file mode 100644 index 0000000..eafcdbc --- a/dev/null +++ b/frontend/gamma/js/Clipperz/PM/UI/Mobile/Components/LoginForm.js @@ -0,0 +1,356 @@ +/* + +Copyright 2008-2011 Clipperz Srl + +This file is part of Clipperz Community Edition. +Clipperz Community Edition is an online password manager. +For further information about its features and functionalities please +refer to http://www.clipperz.com. + +* Clipperz Community Edition 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 Community Edition 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 Community Edition. If not, see + <http://www.gnu.org/licenses/>. + +*/ + +Clipperz.Base.module('Clipperz.PM.UI.Mobile.Components'); + +Clipperz.PM.UI.Mobile.Components.LoginForm = function(args) { + args = args || {}; + + this._pin = ''; + + this._message = null; + this._steps = 0; + this._actualSteps = 0; + + this._callback = null; + this._errorCallback = null; + + this._mode = 'CREDENTIALS'; + + Clipperz.PM.UI.Mobile.Components.LoginForm.superclass.constructor.apply(this, arguments); + + return this; +} + +//============================================================================= + +Clipperz.Base.extend(Clipperz.PM.UI.Mobile.Components.LoginForm, Clipperz.PM.UI.Common.Components.BaseComponent, { + + //------------------------------------------------------------------------- + + 'toString': function () { + return "Clipperz.PM.UI.Mobile.Components.LoginForm component"; + }, + + //------------------------------------------------------------------------- + + 'callback': function () { + return this._callback; + }, + + 'errorCallback': function () { + return this._errorCallback; + }, + + //------------------------------------------------------------------------- + + 'mode': function () { + return this._mode; + }, + + 'setMode': function (aValue) { + this._mode = aValue; + }, + + //.......................................................................... + + 'pin': function () { + return this._pin; + }, + + 'setPin': function (aValue) { + this._pin = aValue; + }, + + //.......................................................................... + + 'username': function () { + return this._username; + }, + + 'setUsername': function (aValue) { + this._username = aValue; + }, + + //.......................................................................... + + 'passphrase': function () { + return this._passphrase; + }, + + 'setPassphrase': function (aValue) { + this._passphrase = aValue; + }, + + //------------------------------------------------------------------------- + + 'message': function () { + return this._message; + }, + + '_setMessage': function (aValue) { + this._message = aValue; + + if (aValue == null) { + MochiKit.Style.hideElement(this.getElement('credentialsMessage')); + } else { + this.getElement('message').innerHTML = aValue; + MochiKit.Style.showElement(this.getElement('credentialsMessage')); + } + }, + + 'setMessage': function (aValue) { + this._setMessage(aValue); + MochiKit.DOM.removeElementClass(this.getElement('credentialsMessage'), 'error'); + }, + + 'setErrorMessage': function (aValue) { + this._setMessage(aValue); + MochiKit.DOM.addElementClass(this.getElement('credentialsMessage'), 'error'); + }, + + //------------------------------------------------------------------------- + + 'setCallbacks': function (args) { + this._callback = args['callback']; + this._errorCallback = args['errorCallback']; + }, + + 'showErrors': function (args) { +//console.log("LoginForm.showErrors", args); + if (args['previousFailedAttempt'] == 'LOGIN') { + this.setErrorMessage("Wrong credentials"); + } else if (args['previousFailedAttempt'] == 'PIN') { + if (args['failedAttempts'] == -1) { + this.setErrorMessage("Wrong PIN - Resetted"); + } else { + this.setErrorMessage("Wrong PIN"); + } + } else { + this.setMessage(null); + } + }, + + 'updateWithArgs': function (args) { + this.renderIfNeeded(); + this.setCallbacks(args); + this.showErrors(args); + this.updateRendering(); + }, + + 'showPinLogin': function (args) { + this.setPin(''); + this.setMode('PIN'); + this.updateWithArgs(args); + +// $(this.getAnchor('PIN')).focus(); + this.getElement('PIN').focus(); + }, + + 'showCredentialsLogin': function (args) { + this.setMode('CREDENTIALS'); + this.updateWithArgs(args); + + if (this.getElement('usernameField').value.length == 0) { +// $(this.getAnchor('usernameField')).focus(); + this.getElement('usernameField').focus(); + } else { +// $(this.getAnchor('passphraseField')).focus(); + this.getElement('passphraseField').focus(); + this.getElement('passphraseField').select(); + } + }, + + //------------------------------------------------------------------------- + + 'renderIfNeeded': function () { + if (this.isFullyRendered() == false) { + this.render(); + }; + this.updateRendering(); + }, + + 'updateRendering': function () { + MochiKit.Style.showElement(this.getElement('credentialsBody')); + MochiKit.Style.hideElement(this.getElement('validating')); + +// this.hideAllPanes(); + MochiKit.Base.map(function (aNode) { MochiKit.Style.hideElement(aNode); }, MochiKit.Selector.findDocElements('div.credentialsBody > div')); + if (this.mode() == 'CREDENTIALS') { + selectedPanel = this.getElement('credentials') + } else if (this.mode() == 'PIN') { + selectedPanel = this.getElement('pin') +// this.updatePinDisplay(); + } else { + throw 'Unhandled login form mode'; + } + MochiKit.Style.showElement(selectedPanel); + + MochiKit.Style.hideElement(this.getElement('validating')); + }, + + 'renderSelf': function() { + var selectedPanel; + this.append(this.element(), {tag:'div', id:'login', children:[ + {tag:'div', cls:'toolbar', children:[ + {tag:'h1', html:"clipperz"} + ]}, + {tag:'div', cls:'scroll', children:[ + //================================================================== + {tag:'div', cls:'credentialsMessage', id:this.getId('credentialsMessage'), children:[ + {tag:'h1', cls:'message', id:this.getId('message'), html:"Message"} + ]}, + //================================================================== + {tag:'div', cls:'credentialsBody', id:this.getId('credentialsBody'), children:[ + //-------------------------------------------------------------- + {tag:'div', cls:'pin', id:this.getId('pin'), children:[ + {tag:'form', cls:'scroll', id:this.getId('pinForm'), children:[ + {tag:'ul', cls:'edit rounded', children:[ + {tag:'li', children:[{tag:'input', type:'number', name:'PIN', placeholder:"PIN", id:this.getId('PIN') }]}, + ]}, + {tag:'a', href:'#', cls:'greenButton', id:this.getId('pinSubmitButton'), html:"Login"} + ]} + ]}, + //-------------------------------------------------------------- + {tag:'div', cls:'credentials', id:this.getId('credentials'), children:[ + {tag:'form', cls:'scroll', id:this.getId('credentialsForm'), children:[ + {tag:'ul', cls:'edit rounded', children:[ + {tag:'li', children:[{tag:'input', type:'email', name:'name', /*value:'joe',*/ placeholder:"username", id:this.getId('usernameField') }]}, + {tag:'li', children:[{tag:'input', type:'password', name:'passphrase', /*value:'clipperz',*/ placeholder:"passphrase", id:this.getId('passphraseField') }]} + ]}, + {tag:'a', href:'#', cls:'greenButton', id:this.getId('credentialsSubmitButton'), html:"Login"} +// {tag:'input', type:'submit', cls:'greenButton', id:this.getId('credentialsSubmitButton'), value:"Login"} + + ]} + ]}, + //-------------------------------------------------------------- + ]}, + //================================================================== + {tag:'div', cls:'validating', id:this.getId('validating'), children:[ + {tag:'div', cls:'loading', children:[ + {tag:'div', cls:'spinner', children:[ + {tag:'div', cls:'bar01'}, + {tag:'div', cls:'bar02'}, + {tag:'div', cls:'bar03'}, + {tag:'div', cls:'bar04'}, + {tag:'div', cls:'bar05'}, + {tag:'div', cls:'bar06'}, + {tag:'div', cls:'bar07'}, + {tag:'div', cls:'bar08'}, + {tag:'div', cls:'bar09'}, + {tag:'div', cls:'bar10'}, + {tag:'div', cls:'bar11'}, + {tag:'div', cls:'bar12'} + ]} + ]}, + {tag:'div', id:this.getId('loadingMessage')}, + {tag:'a', href:'#', cls:'grayButton', id:this.getId('loginCancelButton'), html:"Cancel"} + ]} + //================================================================== + ]} + ]}); + + MochiKit.Signal.connect(this.getElement('credentialsForm'), 'onsubmit', this, 'submitCredentialsHandler'); + MochiKit.Signal.connect(this.getElement('credentialsSubmitButton'), 'onclick', this, 'submitCredentialsHandler'); + + MochiKit.Signal.connect(this.getElement('pinForm'), 'onsubmit', this, 'submitPinHandler'); + MochiKit.Signal.connect(this.getElement('pinSubmitButton'), 'onclick', this, 'submitPinHandler'); + + MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, 'initProgress', this, 'initProgressHandle'); + MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, 'updateProgress', this, 'updateProgressHandle'); + MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, 'advanceProgress', this, 'advanceProgressHandle'); + MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, 'progressDone', this, 'progressDoneHandle'); + }, + + //------------------------------------------------------------------------- + + 'submitPinHandler': function (anEvent) { + var pin; + + this.setMessage(null); + pin = this.getElement('PIN').value; +// $(this.getAnchor('PIN')).blur(); + this.getElement('PIN').blur(); + + credentials = Clipperz.PM.PIN.credentialsWithPIN(pin); + this.loginWithCredentials(credentials); + }, + + 'submitCredentialsHandler': function (anEvent) { +//console.log("submitCredentialsHandler"); + var credentials; + + this.setMessage(null); + + credentials = {}; + credentials['username'] = this.getElement('usernameField').value; + credentials['passphrase'] = this.getElement('passphraseField').value; +// $(this.getAnchor('passphraseField')).blur(); + this.getElement('passphraseField').blur(); + + this.loginWithCredentials(credentials); + }, + + //------------------------------------------------------------------------- + + 'loginWithCredentials': function (someCredentials) { + var args; + + args = {}; + args['credentials'] = someCredentials; + args['errorCallback'] = this.errorCallback(); + + MochiKit.Style.hideElement(this.getElement('credentialsBody')); + MochiKit.Style.showElement(this.getElement('validating')); + + MochiKit.Async.callLater(0.1, this.callback(), args); + }, + + //------------------------------------------------------------------------- + + 'initProgressHandle': function (anEvent) { +//console.log("** initProgressHandle", anEvent); + this._steps = anEvent['steps']; + this._actualSteps = 0; + }, + + 'updateProgressHandle': function (anEvent) { +//console.log("** updateProgressHandle", anEvent); + this._steps += anEvent['extraSteps']; + }, + + 'advanceProgressHandle': function (anEvent) { +//console.log("** advanceProgressHandle", anEvent); + this._actualSteps ++; +//console.log("STEPS: " + this._actualSteps + "/" + this._steps); + }, + + 'progressDoneHandle': function (anEvent) { +//console.log("** progressDoneHandle", anEvent); + }, + + //------------------------------------------------------------------------- + __syntaxFix__: "syntax fix" +}); diff --git a/frontend/gamma/js/Clipperz/PM/UI/Mobile/Controllers/MainController.js b/frontend/gamma/js/Clipperz/PM/UI/Mobile/Controllers/MainController.js new file mode 100644 index 0000000..12a61f7 --- a/dev/null +++ b/frontend/gamma/js/Clipperz/PM/UI/Mobile/Controllers/MainController.js @@ -0,0 +1,393 @@ +/* + +Copyright 2008-2011 Clipperz Srl + +This file is part of Clipperz Community Edition. +Clipperz Community Edition is an online password manager. +For further information about its features and functionalities please +refer to http://www.clipperz.com. + +* Clipperz Community Edition 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 Community Edition 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 Community Edition. If not, see + <http://www.gnu.org/licenses/>. + +*/ + +Clipperz.Base.module('Clipperz.PM.UI.Mobile.Controllers'); + +Clipperz.PM.UI.Mobile.Controllers.MainController = function() { + this._jQTouch = null; + this._user = null; + this._proxy = null; + this._loginForm = null; + this._cardList = null; + this._cardDetail = null; + + return this; +} + +MochiKit.Base.update(Clipperz.PM.UI.Mobile.Controllers.MainController.prototype, { + + 'toString': function () { + return "Clipperz.PM.UI.Mobile.Controllers.MainController"; + }, + + //------------------------------------------------------------------------- + + 'user': function () { + return this._user; + }, + + 'setUser': function (aValue) { + this._user = aValue; + }, + + //------------------------------------------------------------------------- + + 'jQTouch': function () { + return this._jQTouch; + }, + + 'setJQTouch': function (aValue) { + this._jQTouch = aValue; + }, + + //========================================================================= + + 'run': function () { + console.log("MainController.run"); + + MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, 'doLogin', MochiKit.Base.method(this, 'doLogin')); + Clipperz.DOM.Helper.overwrite(MochiKit.DOM.currentDocument().body, {tag:'div', id:'jqt', children:[ + {tag:'div', id:'loginForm'}, + {tag:'div', id:'cardList'}, + {tag:'div', id:'cardDetail'}, + {tag:'div', id:'preferences'} + ]}); + + this.showLoginForm(); + + this.initjQTouch(); + + +// this.showAddToHomeScreenBaloon(); +// this.selectInitialProxy(); + }, + + 'initjQTouch': function () { + var jqt; + + jqt = new $.jQTouch({ + icon: 'data:image/png;charset=utf-8;base64,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', +// icon4: 'jqtouch4.png', +// startupScreen: null, // Pass a string path to a 320px x 460px startup screen for full screen apps. + statusBar: 'black-translucent', // Styles the status bar when running as a fullscreen app. Other options are `default`, `black`, and `black-translucent`. +// addGlossToIcon: true, // Set to 'false' to prevent automatic glossy button effect on icon. + preloadImages: false, // Pass an array of image paths to load them before page loads. Ex: `['images/link_over.png', 'images/link_select.png']` + fixedViewport: true, // Removes the user's ability to scale the page. Ensures the site behaves more like an application. +// fullScreen: true, // The website will become a fullscreen application when saved to a user's home screen. Set to `false` to disable. +// fullScreenClass: 'fullscreen' // Adds a class to the `<body>` when running in full-screen mode, to allow for easy detection and styling. Set to `false` to disable. +// themeSelectionSelector: '#jqt #themes ul', // ??? + +// useAnimations: true, // Set to `false` to disable all animations. +// useFastTouch: true, // Removes ~350ms onClick delay when tapping a link (use in conjunction with the .tap() event) **Experimental** +// useTouchScroll: true, // Adds support for iOS5 scrolling. Set to false to disable. **Experimental** + + cacheGetRequests: false, // Automatically caches GET requests, so subsequent taps reference the pre-loaded views. (default: true) + +// backSelector: '.back, .cancel, .goback', // A CSS selector for back links/buttons. When clicked, the page history goes back one, automatically reversing whichever entrance animation was used. + +// cubeSelector: '.cube', // Link selector for a cube animation. +// dissolveSelector: '.dissolve', // Link selector for a dissolve animation. +// fadeSelector: '.fade', // Link selector for a fade animation. +// flipSelector: '.flip', // Link selector for a 3d flip animation. + formSelector: null, // Sets which forms are automatically submitted via Ajax. (default: 'form') +// popSelector: '.pop', // Link selector for a pop animation. (default: '.pop') +// slideSelector: 'body > * > ul li a', // Link selector for the default slide-left transition. By default applies to all links within an unordered list. Accepts any jQuery-capable selector `'li > a, a:not(.dontslide)'`, etc. (default: 'body > * > ul li a') +// slideupSelector: '.slideup', // Link selector for a slide up animation. (default: '.slideup') +// submitSelector: '.submit', // Selector which, when clicked, will submit its parent form (and close keyboard if open). (default: '.submit') +// swapSelector: '.swap', // Link selector for 3d swap animation. (default: '.swap') +// touchSelector: 'a, .touch', // Selector for items which are automatically given expanded touch events. This makes ordinary links more responsive and provides trigger events like `swipe` (default: 'a, .touch') + + debug: false + }); + + this.setJQTouch(jqt); + }, + + //========================================================================= + + 'showAddToHomeScreenBaloon': function () { +console.log(">>> showAddToHomeScreenBaloon"); + }, + + //------------------------------------------------------------------------- + + 'selectInitialProxy': function () { +//console.log(">>> selectInitialProxy"); + if (this.isOnline()) { +//console.log("--- selectInitialProxy: using default proxy"); + this._proxy = Clipperz.PM.Proxy.defaultProxy; + } else { + if (this.hasLocalData()) { +//console.log("--- selectInitialProxy: using local cache proxy"); + this._proxy = new Clipperz.PM.Proxy.OfflineCache({'shouldPayTolls':false}); + } else { + this.showOfflineError(); + } + } + }, + + //------------------------------------------------------------------------- + + 'showLoginForm': function (args) { + args = args || {}; + + args['callback'] = MochiKit.Base.method(this, 'doLogin'); + + if (Clipperz.PM.PIN.isSet()) { + args['errorCallback'] = MochiKit.Base.method(this, 'handleFailedPinLogin'); + this.loginForm().showPinLogin(args); + } else { + args['errorCallback'] = MochiKit.Base.method(this, 'handleFailedCredentialsLogin'); + this.loginForm().showCredentialsLogin(args); + } + }, + + //......................................................................... + + 'handleFailedCredentialsLogin': function () { +console.log("LOGIN FAILED"); + this.showLoginForm({'previousFailedAttempt':'LOGIN'}); + }, + + //......................................................................... + + 'handleFailedPinLogin': function () { + var failedAttempts; + var status; + + failedAttempts = Clipperz.PM.PIN.recordFailedAttempt(); + this.showLoginForm({'previousFailedAttempt':'PIN', 'failedAttempts': failedAttempts}); + }, + + //------------------------------------------------------------------------- + + 'doLogin': function (someArgs) { + var deferredResult; + var credentials; + var errorCallback; + var user; + var getPassphraseDelegate; + +//console.log(">>> MainController.doLogin", someArgs); + credentials = someArgs['credentials']; + errorCallback = someArgs['errorCallback'] || MochiKit.Base.noop; + + getPassphraseDelegate = MochiKit.Base.partial(MochiKit.Async.succeed, credentials.passphrase); + user = new Clipperz.PM.DataModel.User({'username':credentials.username, 'getPassphraseFunction':getPassphraseDelegate}); + + deferredResult = new Clipperz.Async.Deferred('MainController.doLogin', {trace:false}); + deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'initProgress', {'steps':4}); + deferredResult.addCallback(MochiKit.Async.wait, 0.1); + deferredResult.addMethod(Clipperz.Crypto.PRNG.defaultRandomGenerator(), 'deferredEntropyCollection'); + deferredResult.addMethod(user, 'login'); + deferredResult.addCallbacks( + MochiKit.Base.method(this, 'processSuccessfulLogin', user), + errorCallback + ); + deferredResult.callback(); + + return deferredResult; + }, + + //.......................................................................... + + 'processSuccessfulLogin': function (aUser) { + var deferredResult; + + deferredResult = new Clipperz.Async.Deferred('MainController.processSuccessfulLogin', {trace:false}); + deferredResult.addMethod(Clipperz.PM.PIN, 'resetFailedAttemptCount'); +// deferredResult.addMethod(this, 'removeLoginForm'); + deferredResult.addMethod(this, 'setUser', aUser); + deferredResult.addMethod(this, 'setupApplication'); + deferredResult.addMethod(this, 'runApplication'); + deferredResult.callback(); + + return deferredResult; + }, + + //------------------------------------------------------------------------- + + 'setupApplication': function () { + var deferredResult; + +console.log(">>> setupApplication"); + deferredResult = new Clipperz.Async.Deferred("MainController.setupApplication", {trace:false}); + deferredResult.addMethod(this, 'welcomeFirstTimeUser'); + deferredResult.addMethod(this, 'showPaymentReminder'); + deferredResult.addMethod(this, 'copyDataLocally'); + deferredResult.callback(arguments); + + return deferredResult; + }, + + + //.......................................................................... + + 'isFirstTimeUser': function () { + return false; + }, + + 'welcomeFirstTimeUser': function () { + var deferredResult; + + deferredResult = new Clipperz.Async.Deferred('MainController.welcomeFirstTimeUser', {trace:false}); + + if (this.isFirstTimeUser()) { + deferredResult.addCallback(function () { console.log("--> welcome"); }); + } + deferredResult.callback(); + + return deferredResult; + }, + + //.......................................................................... + + 'shouldShowPaymentReminder': function () { + return true; + }, + + 'showPaymentReminder': function () { + var deferredResult; + + deferredResult = new Clipperz.Async.Deferred('MainController.showPaymentReminder', {trace:false}); + + if (this.shouldShowPaymentReminder()) { + deferredResult.addCallback(function () { console.log("--> payment reminder"); }); + } + deferredResult.callback(); + + return deferredResult; + }, + + //.......................................................................... + + 'canCopyDataLocally': function () { + return false; + }, + + 'copyDataLocally': function () { + var deferredResult; + + deferredResult = new Clipperz.Async.Deferred('MainController.copyDataLocally', {trace:false}); + + if (this.canCopyDataLocally()) { + deferredResult.addCallback(function () { console.log("--> copy data locally"); }); + } + deferredResult.callback(); + + return deferredResult; + + }, + + //------------------------------------------------------------------------- + + 'runApplication': function () { + var deferredResult; + +//console.log(">>> runApplication"); + deferredResult = new Clipperz.Async.Deferred('MainController.runApplication', {trace:true}); + deferredResult.addMethod(this.user(), 'getRecords'); + deferredResult.addMethod(this, 'showCards'); + deferredResult.callback(); + + return deferredResult; + }, + + //========================================================================= + + 'showOfflineError': function (anException) { + alert("Error: " + anException); + throw anException; + }, + + //========================================================================= + + 'isOnline': function() { + return navigator.onLine; + }, + + 'hasLocalData': function() { + return false; + }, + + //========================================================================= + + 'loginForm': function() { + if (this._loginForm == null) { + this._loginForm = new Clipperz.PM.UI.Mobile.Components.LoginForm({element:MochiKit.DOM.getElement('loginForm')}); + } + + return this._loginForm; + }, + + 'removeLoginForm': function () { + if (this._loginForm != null) { + this._loginForm.remove(); + this._loginForm = null; + } + }, + + //------------------------------------------------------------------------- + + 'cardList': function () { + if (this._cardList == null) { + this._cardList = new Clipperz.PM.UI.Mobile.Components.CardList({element:MochiKit.DOM.getElement('cardList')}); + MochiKit.Signal.connect(this._cardList, 'selectedCard', this, 'selectCardHandler'); + } + + return this._cardList; + }, + + 'showCards': function (someCards) { + this.cardList().showCards(someCards); + this.jQTouch().goTo('#cardList', 'slideleft'); + }, + + //------------------------------------------------------------------------- + + 'cardDetail': function () { + if (this._cardDetail == null) { + this._cardDetail = new Clipperz.PM.UI.Mobile.Components.CardDetail({element:MochiKit.DOM.getElement('cardDetail')}); + } + + return this._cardDetail; + }, + + 'selectCardHandler': function (aCardReference) { + var deferredResult; + + deferredResult = new Clipperz.Async.Deferred("MainController.selectCardHandler", {trace:true}); + deferredResult.addMethod(this.cardDetail(), 'render'); + deferredResult.addMethod(this.jQTouch(), 'goTo', '#cardDetail', 'slideleft'); + deferredResult.addMethod(this.user(), 'getRecord', aCardReference); + deferredResult.addMethod(this.cardDetail(), 'showCard'); + deferredResult.callback(); + + return deferredResult; + }, + + //========================================================================= + __syntaxFix__: "syntax fix" +}); diff --git a/frontend/gamma/js/Clipperz/PM/UI/Web/Components/AccountPanel.js b/frontend/gamma/js/Clipperz/PM/UI/Web/Components/AccountPanel.js index ee6d7a3..d6b0574 100644 --- a/frontend/gamma/js/Clipperz/PM/UI/Web/Components/AccountPanel.js +++ b/frontend/gamma/js/Clipperz/PM/UI/Web/Components/AccountPanel.js @@ -41,6 +41,10 @@ Clipperz.PM.UI.Web.Components.AccountPanel = function(args) { tab: 'passphraseTab', panel: 'passphrasePanel' }, + 'OTP': { + tab: 'OTPTab', + panel: 'OTPPanel' + }, 'PREFERENCES': { tab: 'preferencesTab', panel: 'preferencesPanel' @@ -74,6 +78,7 @@ Clipperz.Base.extend(Clipperz.PM.UI.Web.Components.AccountPanel, Clipperz.PM.UI. {tag:'ul', children:[ // {tag:'li', id:this.getId('accountTab'), children:[{tag:'a', href:'#', html:'Account'}], cls:'first'}, {tag:'li', id:this.getId('passphraseTab'), children:[{tag:'a', href:'#', html:'Passphrase'}], cls:'first'}, + {tag:'li', id:this.getId('OTPTab'), children:[{tag:'a', href:'#', html:'One Time Passwords'}]}, {tag:'li', id:this.getId('preferencesTab'), children:[{tag:'a', href:'#', html:'Preferences'}]}, {tag:'li', id:this.getId('loginHistoryTab'), children:[{tag:'a', href:'#', html:'Login history'}]} ]} @@ -117,16 +122,16 @@ Clipperz.Base.extend(Clipperz.PM.UI.Web.Components.AccountPanel, Clipperz.PM.UI. {tag:'div', cls:'clear'}, {tag:'div', cls:'confirmButton', id:this.getId('confirmationButton'), children:[ {tag:'span', html:"change passphrase"} - ]}, - - {tag:'h3', cls:'manageOTP', html:"Manage One-Time Passphrases"}, - {} + ]} + ]}, + {tag:'li', id:this.getId('OTPPanel'), children:[ +// {tag:'h3', html:"Manage One-Time Passphrases"} ]}, {tag:'li', id:this.getId('preferencesPanel'), children:[ - {tag:'h3', html:"-- Preferences --"} +// {tag:'h3', html:"-- Preferences --"} ]}, {tag:'li', id:this.getId('loginHistoryPanel'), children:[ - {tag:'h3', html:"-- Login History --"} +// {tag:'h3', html:"-- Login History --"} ]} ]} ]} diff --git a/frontend/gamma/js/Clipperz/PM/UI/Web/Components/DataPanel.js b/frontend/gamma/js/Clipperz/PM/UI/Web/Components/DataPanel.js index d2f1045..462d864 100644 --- a/frontend/gamma/js/Clipperz/PM/UI/Web/Components/DataPanel.js +++ b/frontend/gamma/js/Clipperz/PM/UI/Web/Components/DataPanel.js @@ -82,16 +82,18 @@ Clipperz.Base.extend(Clipperz.PM.UI.Web.Components.DataPanel, Clipperz.PM.UI.Com {tag:'div', cls:'subPanelContent', children:[ {tag:'ul', children:[ {tag:'li', id:this.getId('offlineCopyPanel'), children:[ - {tag:'h3', html:"Offline copy"} +// {tag:'h3', html:"Offline copy"}, + {tag:'p', html:"With just one click you can dump all your encrypted data from Clipperz servers to your hard disk and create a read-only offline version of Clipperz to be used when you are not connected to the Internet."}, + {tag:'a', id:this.getId('offlineCopyDownloadLink'), href:'#', html:"Download", cls:'downloadOfflineCopy'} ]}, {tag:'li', id:this.getId('sharingPanel'), children:[ - {tag:'h3', html:"Sharing"} +// {tag:'h3', html:"Sharing"} ]}, {tag:'li', id:this.getId('importPanel'), children:[ - {tag:'h3', html:"Import"} +// {tag:'h3', html:"Import"} ]}, {tag:'li', id:this.getId('exportPanel'), children:[ - {tag:'h3', html:"Export"} +// {tag:'h3', html:"Export"} ]} ]} ]} @@ -101,8 +103,14 @@ Clipperz.Base.extend(Clipperz.PM.UI.Web.Components.DataPanel, Clipperz.PM.UI.Com ]); this.tabPanelController().setup({selected:this.initiallySelectedTab()}); + MochiKit.Signal.connect(this.getId('offlineCopyDownloadLink'), 'onclick', this, 'downloadOfflineCopy'); }, - + + 'downloadOfflineCopy': function (anEvent) { + anEvent.preventDefault(); + MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'downloadOfflineCopy', anEvent.src()); + }, + //------------------------------------------------------------------------- __syntaxFix__: "syntax fix" }); diff --git a/frontend/gamma/js/Clipperz/PM/UI/Web/Components/LoginProgress.js b/frontend/gamma/js/Clipperz/PM/UI/Web/Components/LoginProgress.js index 5d082b5..26506e7 100644 --- a/frontend/gamma/js/Clipperz/PM/UI/Web/Components/LoginProgress.js +++ b/frontend/gamma/js/Clipperz/PM/UI/Web/Components/LoginProgress.js @@ -82,9 +82,10 @@ Clipperz.Base.extend(Clipperz.PM.UI.Web.Components.LoginProgress, Clipperz.PM.UI ]}, {tag:'div', cls:'footer', children:[ {tag:'div', cls:'buttonArea', id:this.getId('buttonArea'), children:[ - {tag:'div', cls:'button', id:this.getId('button'), children:[ - {tag:'a', href:'#', id:this.getId('buttonLink'), html:"cancel"} - ]} +// {tag:'div', cls:'button', id:this.getId('button'), children:[ +// {tag:'a', href:'#', id:this.getId('buttonLink'), html:"cancel"} +// ]} + {tag:'a', cls:'button', id:this.getId('button'), html:"cancel"} ]} ]} ]}); @@ -95,7 +96,8 @@ Clipperz.Base.extend(Clipperz.PM.UI.Web.Components.LoginProgress, Clipperz.PM.UI this.addComponent(new Clipperz.PM.UI.Common.Components.ProgressBar({'element':this.getElement('progressBar')})); MochiKit.Style.hideElement(this.getElement('errorBox')); - MochiKit.Signal.connect(this.getId('buttonLink'), 'onclick', this, 'cancelEventHandler'); +// MochiKit.Signal.connect(this.getId('buttonLink'), 'onclick', this, 'cancelEventHandler'); + MochiKit.Signal.connect(this.getId('button'), 'onclick', this, 'cancelEventHandler'); }, //------------------------------------------------------------------------- @@ -121,7 +123,9 @@ Clipperz.Base.extend(Clipperz.PM.UI.Web.Components.LoginProgress, Clipperz.PM.UI //------------------------------------------------------------------------- 'showErrorMessage': function() { - this.getElement('buttonLink').innerHTML = "close"; +// this.getElement('buttonLink').innerHTML = "close"; + this.getElement('button').innerHTML = "close"; + MochiKit.DOM.addElementClass(this.getElement('button'), 'default'); MochiKit.Style.hideElement(this.getElement('progressBar')); diff --git a/frontend/gamma/js/Clipperz/PM/UI/Web/Components/PageFooter.js b/frontend/gamma/js/Clipperz/PM/UI/Web/Components/PageFooter.js index a25c8f5..dcf506f 100644 --- a/frontend/gamma/js/Clipperz/PM/UI/Web/Components/PageFooter.js +++ b/frontend/gamma/js/Clipperz/PM/UI/Web/Components/PageFooter.js @@ -49,12 +49,11 @@ Clipperz.Base.extend(Clipperz.PM.UI.Web.Components.PageFooter, Clipperz.PM.UI.Co this.append(this.element(), [ {tag:'div', cls:'footerWrapper', children:[ {tag:'div', cls:'footerContent', children:[ -// {tag:'div', cls:'footerStarIcon'}, {tag:'canvas', id:this.getId('footerStarIcon'), cls:'footerStarIcon'}, - {tag:'span', cls:'copyright', html:'Copyright © 2009-2012 Clipperz Srl'}, + {tag:'span', cls:'copyright', html:'Copyright © 2009-2013 Clipperz Srl'}, {tag:'a', href:'http://www.clipperz.com/terms_of_service', target:'_blank', html:'terms of service'}, {tag:'a', href:'http://www.clipperz.com/privacy_policy', target:'_blank', html:'privacy policy'}, - {tag:'span', cls:'applicationVersion', html:'application version: [1992]'} + {tag:'div', cls:'applicationVersion', htmlString:'application version: <a href="https://github.com/clipperz/password-manager/tree/' + Clipperz_version + '" target="github">' + Clipperz_version + '</a>'} ]} ]} ]); diff --git a/frontend/gamma/js/Clipperz/PM/UI/Web/Components/ToolsPanel.js b/frontend/gamma/js/Clipperz/PM/UI/Web/Components/ToolsPanel.js index 3ee6189..0fa369f 100644 --- a/frontend/gamma/js/Clipperz/PM/UI/Web/Components/ToolsPanel.js +++ b/frontend/gamma/js/Clipperz/PM/UI/Web/Components/ToolsPanel.js @@ -82,16 +82,16 @@ Clipperz.Base.extend(Clipperz.PM.UI.Web.Components.ToolsPanel, Clipperz.PM.UI.Co {tag:'div', cls:'subPanelContent', children:[ {tag:'ul', children:[ {tag:'li', id:this.getId('passwordGeneratorPanel'), children:[ - {tag:'h3', html:"Password generator"} +// {tag:'h3', html:"Password generator"} ]}, {tag:'li', id:this.getId('bookmarkletPanel'), children:[ - {tag:'h3', html:"Bookmarklet"} +// {tag:'h3', html:"Bookmarklet"} ]}, {tag:'li', id:this.getId('compactEditionPanel'), children:[ - {tag:'h3', html:"Compact edition"} +// {tag:'h3', html:"Compact edition"} ]}, {tag:'li', id:this.getId('httpAuthPanel'), children:[ - {tag:'h3', html:"HTTP Auth"} +// {tag:'h3', html:"HTTP Auth"} ]} ]} ]} diff --git a/frontend/gamma/js/Clipperz/PM/UI/Web/Controllers/AppController.js b/frontend/gamma/js/Clipperz/PM/UI/Web/Controllers/AppController.js index 9a0e744..1ab2e69 100644 --- a/frontend/gamma/js/Clipperz/PM/UI/Web/Controllers/AppController.js +++ b/frontend/gamma/js/Clipperz/PM/UI/Web/Controllers/AppController.js @@ -231,9 +231,11 @@ MochiKit.Base.update(Clipperz.PM.UI.Web.Controllers.AppController.prototype, { this.hideAllAppPageTabSlots(); this.appPage().showSlot(this.slotNameForTab('cards')); - MochiKit.Signal.connect(this.tabSidePanel(), 'tabSelected', this, 'handleTabSelected'); - MochiKit.Signal.connect(this.tabSidePanel(), 'addCard', this, 'handleAddCard'); - MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, 'addCard', this, 'handleAddCard'); + MochiKit.Signal.connect(this.tabSidePanel(), 'tabSelected', this, 'handleTabSelected'); + MochiKit.Signal.connect(this.tabSidePanel(), 'addCard', this, 'handleAddCard'); + MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, 'addCard', this, 'handleAddCard'); + + MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, 'downloadOfflineCopy', this, 'handleDownloadOfflineCopy'); deferredResult = new Clipperz.Async.Deferred("AppController.run", {trace:false}); @@ -321,6 +323,29 @@ MochiKit.Base.update(Clipperz.PM.UI.Web.Controllers.AppController.prototype, { ], {trace:false}); }, + 'handleDownloadOfflineCopy': function (anEvent) { +console.log("AppController.handleDownloadOfflineCopy"); + var downloadHref; + + downloadHref = window.location.href.replace(/\/[^\/]*$/,'') + Clipperz_dumpUrl; + + if (Clipperz_IEisBroken == true) { + window.open(downloadHref, ""); + } else { + var deferredResult; + var newWindow; + + newWindow = window.open("", ""); + + deferredResult = new Clipperz.Async.Deferred("AppController.handleDownloadOfflineCopy", {trace:true}); + deferredResult.addCallback(MochiKit.Base.method(this.user().connection(), 'message'), 'echo', {'echo':"echo"}); + deferredResult.addCallback(function(aWindow) { + aWindow.location.href = downloadHref; + }, newWindow); + deferredResult.callback(); + } + }, + //============================================================================= __syntaxFix__: "syntax fix" }); diff --git a/frontend/gamma/js/Clipperz/PM/UI/iPhone/Components/CardDetail.js b/frontend/gamma/js/Clipperz/PM/UI/iPhone/Components/CardDetail.js deleted file mode 100644 index 5380aa1..0000000 --- a/frontend/gamma/js/Clipperz/PM/UI/iPhone/Components/CardDetail.js +++ b/dev/null @@ -1,163 +0,0 @@ -/* - -Copyright 2008-2011 Clipperz Srl - -This file is part of Clipperz Community Edition. -Clipperz Community Edition is an online password manager. -For further information about its features and functionalities please -refer to http://www.clipperz.com. - -* Clipperz Community Edition 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 Community Edition 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 Community Edition. If not, see - <http://www.gnu.org/licenses/>. - -*/ - -Clipperz.Base.module('Clipperz.PM.UI.iPhone.Components'); - -Clipperz.PM.UI.iPhone.Components.CardDetail = function(args) { - args = args || {}; - - Clipperz.PM.UI.iPhone.Components.CardDetail.superclass.constructor.apply(this, arguments); - - this._cardReference = null; - - return this; -} - -//============================================================================= - -Clipperz.Base.extend(Clipperz.PM.UI.iPhone.Components.CardDetail, Clipperz.PM.UI.Common.Components.BaseComponent, { - - //------------------------------------------------------------------------- - - 'toString': function () { - return "Clipperz.PM.UI.iPhone.Components.CardDetail component"; - }, - - //------------------------------------------------------------------------- - - 'cardReference': function () { - return this._cardReference; - }, - - 'setCardReference': function (aValue) { - this._cardReference = aValue; - }, - - //------------------------------------------------------------------------- - - 'renderSelf': function(/*aContainer, aPosition*/) { - this.append(this.element(), [ - {tag:'div', cls:'cardDetail', id:this.getId('cardDetail'), children:[ - {tag:'div', id:this.getId('progressBar')} //, -// {tag:'h1', cls:'loading', html:"loading"} - ]} - ]); - - this.addComponent(new Clipperz.PM.UI.Common.Components.ProgressBar({'element':this.getElement('progressBar')})); - MochiKit.Signal.signal(Clipperz.PM.UI.Common.Controllers.ProgressBarController.defaultController, 'updateProgress', 0); - }, - - //========================================================================= - - 'showCardDetails': function (someData) { - this.element().innerHTML = ''; - this.append(this.element(), [ - {tag:'fieldset', id:this.getId('fields'), children:MochiKit.Base.map(function (aFieldData) { - return {tag:'div', cls:'row', children:[ - {tag:'label', html:aFieldData['label']}, -// {tag:'span', cls:('fieldValue ' + (aFieldData['isHidden'] ? 'password' : 'text')), html:aFieldData['value']} - {tag:'div', cls:('fieldValue ' + (aFieldData['isHidden'] ? 'password' : 'text')), children:[ - {tag:'div', children:[{tag:'p', html:aFieldData['value']}]} - ]} -// {tag:'input', type:'text', cls:('fieldValue ' + (aFieldData['isHidden'] ? 'password' : 'text')), value:aFieldData['value'], disabled:true} - - ]} - }, someData['fields'])} - ]); - - MochiKit.Iter.forEach(MochiKit.Selector.findChildElements(this.element(), ['span.password']), MochiKit.Base.bind(function (aPasswordElement) { - MochiKit.Signal.connect(aPasswordElement, 'onclick', function (anEvent) { alert(MochiKit.DOM.scrapeText(anEvent.src())); }) - }, this)); - - if (someData['directLogins'].length > 0) { - this.append(this.element(), [ - {tag:'h2', html:"Direct logins"}, - {tag:'fieldset', id:this.getId('directLogins'), children:MochiKit.Base.map(function (aDirectLoginData) { - return {tag:'div', cls:'row', id:('directLogin_' + aDirectLoginData['_reference']), children:[ - {tag:'img', cls:'favicon', src:aDirectLoginData['favicon']}, -// {tag:'input', cls:'directLogin', disabled:'disabled', type:'text', name:aDirectLoginData['label'], value:aDirectLoginData['label']} - {tag:'span', cls:'directLogin', html:aDirectLoginData['label']} - ]} - }, someData['directLogins'])} - ]); - - MochiKit.Base.map(MochiKit.Base.bind(function (aRowNode) { - MochiKit.Signal.connect(aRowNode, 'onclick', this, 'directLoginClickHandler'); - }, this), - MochiKit.Selector.findChildElements(this.getElement('directLogins'), ['div.row']) - ) - }; - - if (someData['notes'] != '') { - this.append(this.element(), [ - {tag:'h2', html:"Notes"}, - {tag:'fieldset', id:this.getId('fieldset'), children:[ - {tag:'div', cls:'row notes', children:[ - {tag:'span', html:someData['notes']} - ]} - ]} - ]); - }; - - return true; - }, - - //------------------------------------------------------------------------- -/* - 'toggleClickHandler': function (anEvent) { - var nextState; - var fieldValue; - -//console.log("TOGGLE"); - anEvent.preventDefault; - fieldValue = MochiKit.Selector.findChildElements(anEvent.src().parentNode.parentNode, ['span.password'])[0]; - - nextState = (MochiKit.DOM.getNodeAttribute(anEvent.src(), 'toggled') != 'true'); - if (nextState) { - MochiKit.DOM.removeElementClass(fieldValue, 'clear'); - } else { - MochiKit.DOM.addElementClass(fieldValue, 'clear'); - } - - MochiKit.DOM.setNodeAttribute(anEvent.src(), 'toggled', nextState); - }, -*/ - //========================================================================= - - 'directLoginClickHandler': function (anEvent) { - anEvent.preventDefault(); - - if (/(directLogin_)/.test(anEvent.src().id)) { - var directLoginReference; - - directLoginReference = anEvent.src().id.match(/(directLogin_)(.*)/)[2]; - MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectedDirectLogin', {cardReference:this.cardReference(), directLoginReference:directLoginReference}); - } - }, - - //========================================================================= - - __syntaxFix__: "syntax fix" -}); diff --git a/frontend/gamma/js/Clipperz/PM/UI/iPhone/Components/LoginForm.js b/frontend/gamma/js/Clipperz/PM/UI/iPhone/Components/LoginForm.js deleted file mode 100644 index 5341878..0000000 --- a/frontend/gamma/js/Clipperz/PM/UI/iPhone/Components/LoginForm.js +++ b/dev/null @@ -1,178 +0,0 @@ -/* - -Copyright 2008-2011 Clipperz Srl - -This file is part of Clipperz Community Edition. -Clipperz Community Edition is an online password manager. -For further information about its features and functionalities please -refer to http://www.clipperz.com. - -* Clipperz Community Edition 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 Community Edition 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 Community Edition. If not, see - <http://www.gnu.org/licenses/>. - -*/ - -Clipperz.Base.module('Clipperz.PM.UI.iPhone.Components'); - -Clipperz.PM.UI.iPhone.Components.LoginForm = function(args) { - args = args || {}; - - Clipperz.PM.UI.iPhone.Components.LoginForm.superclass.constructor.apply(this, arguments); - - return this; -} - -//============================================================================= - -Clipperz.Base.extend(Clipperz.PM.UI.iPhone.Components.LoginForm, Clipperz.PM.UI.Common.Components.BaseComponent, { - - //------------------------------------------------------------------------- - - 'toString': function () { - return "Clipperz.PM.UI.iPhone.Components.LoginForm component"; - }, - - //------------------------------------------------------------------------- - - 'focusOnUsername': function () { - this.getElement('username').focus(); - }, - - //------------------------------------------------------------------------- - - 'username': function () { - return this.getElement('username').value; - }, - - 'passphrase': function () { - return this.getElement('passphrase').value; - }, - - //------------------------------------------------------------------------- - - 'renderSelf': function(/*aContainer, aPosition*/) { - this.append(this.element(), [ - {tag:'div', cls:'toolbar iPhoneClipperzToolbar', children:[ - {tag:'h1', id:'pageTitle', html:'Clipperz'}, - {tag:'a', id:'backButton', cls:'button', href:'#', html:"back"} - ]}, - {tag:'form', title:'Theaters', cls:'panel toolbarlessPanel loginForm', id:this.getId('loginFormPanel'), children:[ - {tag:'fieldset', id:this.getId('fieldset'), children:[ - {tag:'div', cls:'row', children:[ - {tag:'label', html:"username"}, - {tag:'input', type:'text', name:'username', value:"", autocorrect:'off', autocapitalize:'off', id:this.getId('username')} - ]}, - {tag:'div', cls:'row', children:[ - {tag:'label', html:"passphrase"}, - {tag:'input', type:'password', name:'passphrase', value:"", id:this.getId('passphrase')} - ]} - ]}, - {tag:'a', cls:'whiteButton', type:'submit', href:'#', html:"Login", id:this.getId('submit')} - ]}, - {tag:'div', cls:'panel toolbarlessPanel loginProgressPanel', id:this.getId('loginProgressPanel'), children:[ - {tag:'div', id:this.getId('progressBar')} //, -// {tag:'a', cls:'whiteButton', type:'submit', href:'#', html:"Cancel", id:this.getId('cancel')} - ]}, - {tag:'div', cls:'panel loginErrorPanel', id:this.getId('loginErrorPanel'), children:[ - {tag:'div', cls:'errorMessage', id:this.getId('errorMessageBox'), children:[ - {tag:'h2', id:this.getId('errorMessage'), html:"Login failed"} - ]} - ]} - ]); - - MochiKit.Signal.connect(this.getElement('submit'), 'onclick', this, 'submitHandler'); - MochiKit.Signal.connect(this.getElement('loginFormPanel'), 'onsubmit', this, 'submitHandler'); - -// MochiKit.Signal.connect(this.getElement('cancel'), 'onclick', this, 'cancelHandler'); - MochiKit.Signal.connect('backButton', 'onclick', this, 'backHandler'); - - this.addComponent(new Clipperz.PM.UI.Common.Components.ProgressBar({'element':this.getElement('progressBar')})); - -// MochiKit.Style.hideElement(this.getElement('errorMessage')); - - this.showLoginForm(); -// MochiKit.Async.callLater(0.2, MochiKit.Base.method(this, 'focusOnUsername')); - }, - - //------------------------------------------------------------------------- - - 'showLoginForm': function () { - MochiKit.Style.showElement(this.getElement('loginFormPanel')); - MochiKit.Style.hideElement(this.getElement('loginProgressPanel')); - MochiKit.Style.hideElement(this.getElement('loginErrorPanel')); - MochiKit.Style.hideElement('backButton'); - }, - - 'slideInLoginForm': function () { - var offset; - - offset = ((MochiKit.DOM.getNodeAttribute(MochiKit.DOM.currentDocument().body, 'orientation') == 'portrait') ? 320 : 480); - - MochiKit.Style.showElement(this.getElement('loginFormPanel')); - MochiKit.Style.setElementPosition(this.getElement('loginFormPanel'), {x:-offset, y:0}); - - new MochiKit.Visual.Sequence([ - new MochiKit.Visual.Parallel([ - new MochiKit.Visual.Move(this.getElement('loginErrorPanel'), {x:offset, y:0, mode:'relative', transition:MochiKit.Visual.Transitions.linear, sync:true}), - new MochiKit.Visual.Move(this.getElement('loginFormPanel'), {x:0, y:0, mode:'absolute', transition:MochiKit.Visual.Transitions.linear, sync:true}), - MochiKit.Visual.fade ('backButton', { transition:MochiKit.Visual.Transitions.linear, sync:true}) - ], {duration:0.5, sync:true}), - MochiKit.Visual.fade(this.getElement('loginErrorPanel'), {duration:0, sync:true}) - ], {}) - }, - - 'showLoginProgress': function () { - MochiKit.Style.hideElement(this.getElement('loginFormPanel')); - MochiKit.Style.showElement(this.getElement('loginProgressPanel')); - }, - - 'showLoginError': function (anError) { - this.getElement('errorMessage').innerHTML = "Login error"; - - MochiKit.Style.showElement('backButton'); - MochiKit.Style.hideElement(this.getElement('loginProgressPanel')); - MochiKit.Style.showElement(this.getElement('loginErrorPanel')); - MochiKit.Style.setElementPosition(this.getElement('loginErrorPanel'), {x:0, y:45}); - }, - - //------------------------------------------------------------------------- -/* - 'disableCancelButton': function () { - MochiKit.DOM.hideElement(this.getElement('cancel')); - }, -*/ - //------------------------------------------------------------------------- - - 'submitHandler': function (anEvent) { - anEvent.preventDefault(); - - MochiKit.Signal.signal(this, 'doLogin', {'username':this.username(), 'passphrase':this.passphrase()}); - }, - - 'cancelHandler': function (anEvent) { - anEvent.preventDefault(); - -//console.log("CANCEL"); - }, - - 'backHandler': function (anEvent) { - anEvent.preventDefault(); - - this.slideInLoginForm(); - }, - - //------------------------------------------------------------------------- - - __syntaxFix__: "syntax fix" -}); diff --git a/frontend/gamma/js/Clipperz/PM/UI/iPhone/Controllers/MainController.js b/frontend/gamma/js/Clipperz/PM/UI/iPhone/Controllers/MainController.js deleted file mode 100644 index 3fcaae1..0000000 --- a/frontend/gamma/js/Clipperz/PM/UI/iPhone/Controllers/MainController.js +++ b/dev/null @@ -1,369 +0,0 @@ -/* - -Copyright 2008-2011 Clipperz Srl - -This file is part of Clipperz Community Edition. -Clipperz Community Edition is an online password manager. -For further information about its features and functionalities please -refer to http://www.clipperz.com. - -* Clipperz Community Edition 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 Community Edition 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 Community Edition. If not, see - <http://www.gnu.org/licenses/>. - -*/ - -Clipperz.Base.module('Clipperz.PM.UI.iPhone.Controllers'); - -// Some parts of this controller have been derived from the iUI library. - -Clipperz.PM.UI.iPhone.Controllers.MainController = function() { - this._loginForm = null; - this._cardList = null; - this._cachedValues = null; - this._user = null; - - if (typeof window.onorientationchange == 'object') { - MochiKit.Signal.connect(window, 'onorientationchange', this, 'orientationChangeHandler'); - MochiKit.Async.callLater(0, MochiKit.Base.method(this, 'orientationChangeHandler')); - } else { - this.setOrientation('portrait'); -// this.setOrientation('landscape'); - } - - this.addMetaTag('viewport', 'width=devicewidth; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;'); - this.addMetaTag('apple-mobile-web-app-capable', 'yes'); - this.addMetaTag('apple-mobile-web-app-status-bar-style', 'black'); - - this.addLinkTag('apple-touch-icon', 'data:image/png;charset=utf-8;base64,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'); -// this.addLinkTag('apple-touch-startup-image', 'default.png'); - -// if (!window.navigator.standalone) // not running as an installed app - - MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, 'selectedDirectLogin', this, 'selectedDirectLoginHandler'); - - MochiKit.DOM.addElementClass(document.body, 'iPhone'); - return this; -} - -MochiKit.Base.update(Clipperz.PM.UI.iPhone.Controllers.MainController.prototype, { - - 'toString': function () { - return "Clipperz.PM.UI.iPhone.Controllers.MainController"; - }, - - //========================================================================= - - 'user': function () { - return this._user; - }, - - 'setUser': function (aValue) { - this._user = aValue; - }, - - //========================================================================= - - 'loginForm': function() { - if (this._loginForm == null) { - MochiKit.DOM.removeElement('mainDiv'); - this._loginForm = new Clipperz.PM.UI.iPhone.Components.LoginForm({element:MochiKit.DOM.currentDocument().body}); - MochiKit.Signal.connect(this._loginForm, 'doLogin', this, 'doLoginHandler') - } - - return this._loginForm; - }, - - 'removeLoginForm': function () { - if (this._loginForm != null) { - this._loginForm.remove(); - this._loginForm = null; - } - }, - - //----------------------------------------------------------------------------- - - 'cardList': function () { - if (this._cardList == null) { - this._cardList = new Clipperz.PM.UI.iPhone.Components.CardList({element:MochiKit.DOM.currentDocument().body}); - MochiKit.Signal.connect(this._cardList, 'searchEvent', this, 'searchEventHandler') - MochiKit.Signal.connect(this._cardList, 'selectedCard', this, 'selecetedCardHandler') - } - - return this._cardList; - }, - - //========================================================================= - - 'currentWidth': function () { - return this._currentWidth; - }, - - 'setCurrentWidth': function (aValue) { - this._currentWidth = aValue; - }, - - //========================================================================= - - 'orientationChangeHandler': function () { - switch(window.orientation) { - case 0: - this.setOrientation('portrait'); - break; - case 90: - case -90: - this.setOrientation('landscape'); - break; - } - }, - - //------------------------------------------------------------------------- - - 'setOrientation': function (anOrientation) { - document.body.setAttribute('orientation', anOrientation); - setTimeout(scrollTo, 100, 0, 1); - }, - - //------------------------------------------------------------------------- - - 'slidePages': function (fromPage, toPage, backwards) { - var axis; - var slideDone; - - slideDone = function () { - // console.log("slideDone"); - if (!hasClass(toPage, "dialog")) { - fromPage.removeAttribute("selected"); - } - checkTimer = setInterval(checkOrientAndLocation, 300); - setTimeout(updatePage, 0, toPage, fromPage); - fromPage.removeEventListener('webkitTransitionEnd', slideDone, false); - } - - axis = (backwards ? fromPage : toPage).getAttribute("axis"); - - clearInterval(checkTimer); - - if (canDoSlideAnim() && axis != 'y') { - slide2(fromPage, toPage, backwards, slideDone); - } else { - slide1(fromPage, toPage, backwards, axis, slideDone); - } - }, - - //------------------------------------------------------------------------- - - 'getCachedValues': function () { - var deferredResult; - - if (this._cachedObjects != null) { - deferredResult = MochiKit.Async.succeed(this._cachedObjects); - } else { - deferredResult = new Clipperz.Async.Deferred("MainController.getCachedValues", {trace:false}); - deferredResult.addMethod(this.user(), 'getRecords'); - deferredResult.addCallback(MochiKit.Base.map, Clipperz.Async.collectResults("MainController.getCachedValues - collectResults", { - '_rowObject': MochiKit.Async.succeed, - '_reference': MochiKit.Base.methodcaller('reference'), - 'label': MochiKit.Base.methodcaller('label'), - 'favicon': MochiKit.Base.methodcaller('favicon'), - '_searchableContent': MochiKit.Base.methodcaller('searchableContent') - }, {trace:false})); - deferredResult.addCallback(Clipperz.Async.collectAll); - deferredResult.addCallback(MochiKit.Base.bind(function (someRows) { - this._cachedObjects = someRows; - return this._cachedObjects; - }, this)); - deferredResult.callback(); - } - - return deferredResult; - }, - //========================================================================= - - 'run': function(shouldShowRegistrationForm) { - this.loginForm().render(); - MochiKit.Async.callLater(1, MochiKit.Base.method(this.loginForm(), 'focusOnUsername')); - }, - - //========================================================================= - - 'doLoginHandler': function (someArgs) { - var deferredResult; - var parameters; - var shouldUseOTP; -// var loginProgress; - var user; - var getPassphraseDelegate; - - parameters = someArgs; - shouldUseOTP = (typeof(parameters.passphrase) == 'undefined'); - - getPassphraseDelegate = MochiKit.Base.partial(MochiKit.Async.succeed, parameters.passphrase); - user = new Clipperz.PM.DataModel.User({'username':parameters.username, 'getPassphraseFunction':getPassphraseDelegate}); - - deferredResult = new Clipperz.Async.Deferred("MainController.doLogin", {trace:false}); - deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'initProgress', {'steps':4}); - deferredResult.addMethod(this.loginForm(), 'showLoginProgress'); - deferredResult.addCallback(MochiKit.Async.wait, 0.1); - deferredResult.addMethod(Clipperz.Crypto.PRNG.defaultRandomGenerator(), 'deferredEntropyCollection'); - deferredResult.addMethod(user, 'login'); - deferredResult.addMethod(this, 'setUser', user); - deferredResult.addMethod(user, 'getRecords'); - deferredResult.addMethod(this, 'removeLoginForm'); - deferredResult.addMethod(this.cardList(), 'render'); - deferredResult.addMethod(this, 'displaySelectedRecords', ''); - deferredResult.addErrback(MochiKit.Base.method(this.loginForm(), 'showLoginError')); - deferredResult.callback(); - - return deferredResult; - }, - - //========================================================================= - - 'searchEventHandler': function (aValue) { -//console.log("searching for ... " + aValue); - return this.displaySelectedRecords(aValue); - }, - - //========================================================================= - - '_displaySelectedRows': function (aFilter, someRows) { - var result; - - result = someRows; - - if (aFilter != null) { - var filter; - var filterRegExp; - - filter = aFilter.replace(/[^A-Za-z0-9]/g, "\\$&"); - filterRegExp = new RegExp(filter, "i"); - result = MochiKit.Base.filter(function (aCachedResult) { return filterRegExp.test(aCachedResult['_searchableContent'])}, result); - } - - - result.sort(MochiKit.Base.partial(function (aKey, aComparator, aObject, bObject) { - return aComparator(aObject[aKey], bObject[aKey]); - }, 'label', Clipperz.Base.caseInsensitiveCompare)); - - this.cardList().update(result); - }, - - //------------------------------------------------------------------------- - - 'displaySelectedRecords': function (aFilter) { - return Clipperz.Async.callbacks("MainController.displaySelectedrows", [ - MochiKit.Base.method(this, 'getCachedValues'), - MochiKit.Base.method(this, '_displaySelectedRows', aFilter) - ], {trace:false}); - }, - - //========================================================================= - - 'selecetedCardHandler': function (aRecordReference) { - var deferredResult; - var recordData; - - recordData = {}; -//console.log("Showing detail for card with reference", aRecordReference); - deferredResult = new Clipperz.Async.Deferred("MainController.selectedCardHandler", {trace:false}); - deferredResult.addMethod(this.user(), 'getRecord', aRecordReference); - deferredResult.collectResults({ - '_reference': MochiKit.Base.methodcaller('reference'), - 'title': MochiKit.Base.methodcaller('label'), - 'favicon': MochiKit.Base.methodcaller('favicon') - }); - deferredResult.addCallback(function (someData) { - MochiKit.Base.update(recordData, someData); - }) - deferredResult.addMethod(this.cardList(), 'showCard', recordData); - - deferredResult.addMethod(this.user(), 'getRecord', aRecordReference); - deferredResult.addMethodcaller('notes'); - deferredResult.addCallback(function (someNotes) { - recordData['notes'] = someNotes; - }) - - deferredResult.addMethod(this.user(), 'getRecord', aRecordReference); - deferredResult.addMethodcaller('getCurrentRecordVersion'); - deferredResult.addMethodcaller('fields'); - deferredResult.addCallback(MochiKit.Base.values); - deferredResult.addCallback(MochiKit.Base.map, Clipperz.Async.collectResults("MainController.selectedCardHandler - fields", { - 'label': MochiKit.Base.methodcaller('label'), - 'value': MochiKit.Base.methodcaller('value'), - 'isHidden': MochiKit.Base.methodcaller('isHidden') - }, {trace:false})); - deferredResult.addCallback(Clipperz.Async.collectAll); - deferredResult.addCallback(function (someData) { - recordData['fields'] = someData; - }); - - deferredResult.addMethod(this.user(), 'getRecord', aRecordReference); - deferredResult.addMethodcaller('directLogins'); - deferredResult.addCallback(MochiKit.Base.values); - deferredResult.addCallback(MochiKit.Base.map, Clipperz.Async.collectResults("MainController.selectedCardHandler - directLogins", { - 'label': MochiKit.Base.methodcaller('label'), - 'favicon': MochiKit.Base.methodcaller('favicon'), - '_reference': MochiKit.Base.methodcaller('reference') - }, {trace:false})); - deferredResult.addCallback(Clipperz.Async.collectAll); - deferredResult.addCallback(function (someData) { - recordData['directLogins'] = someData; - }); - - deferredResult.addMethod(this.cardList(), 'showCardDetails', recordData); - deferredResult.callback(); - - return deferredResult; - }, - - //========================================================================= - - 'selectedDirectLoginHandler': function (someData) { - var deferredResult; - -//console.log("<<< signal - directLogin"); - deferredResult = new Clipperz.Async.Deferred("MainController.selectedDirectLoginHandler", {trace:false}); - deferredResult.addMethod(this.user(), 'getRecord', someData['cardReference']); - deferredResult.addMethodcaller('directLogins'); - deferredResult.addCallback(MochiKit.Base.itemgetter(someData['directLoginReference'])); -// deferredResult.addMethodcaller('runDirectLogin'); - deferredResult.addCallback(Clipperz.PM.UI.Common.Controllers.DirectLoginRunner.openDirectLogin); - deferredResult.callback(); - - return deferredResult; - }, - - //========================================================================= - - 'addMetaTag': function (aName, aContent) { - var metaTag; - - metaTag = document.createElement('meta'); - metaTag.name = aName; - metaTag.content = aContent; - document.getElementsByTagName('head')[0].appendChild(metaTag); - }, - - 'addLinkTag': function (aRel, anHref) { - var linkTag; - - linkTag = document.createElement('link'); - linkTag.rel = aRel; - linkTag.href = anHref; - document.getElementsByTagName('head')[0].appendChild(linkTag); - }, - - //========================================================================= - __syntaxFix__: "syntax fix" -});
\ No newline at end of file diff --git a/frontend/gamma/js/JQTouch/extensions/jqt.actionsheet.js b/frontend/gamma/js/JQTouch/extensions/jqt.actionsheet.js new file mode 100644 index 0000000..2a5f8d1 --- a/dev/null +++ b/frontend/gamma/js/JQTouch/extensions/jqt.actionsheet.js @@ -0,0 +1,159 @@ +/* + + _/ _/_/ _/_/_/_/_/ _/ + _/ _/ _/ _/_/ _/ _/ _/_/_/ _/_/_/ + _/ _/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/ + _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ + _/ _/_/ _/ _/ _/_/ _/_/_/ _/_/_/ _/ _/ + _/ + _/ + + Documentation and issue tracking on Google Code <http://code.google.com/p/jqtouch/> + + (c) 2012 by jQTouch project members. + See LICENSE.txt for license. + + Author: Thomas Yip +*/ + +/* + + _/ _/_/ _/_/_/_/_/ _/ + _/ _/ _/ _/_/ _/ _/ _/_/_/ _/_/_/ + _/ _/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/ + _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ + _/ _/_/ _/ _/ _/_/ _/_/_/ _/_/_/ _/ _/ + _/ + _/ + + Documentation and issue tracking on Google Code <http://code.google.com/p/jqtouch/> + + (c) 2012 by jQTouch project members. + See LICENSE.txt for license. + + Author: Thomas Yip +*/ + +(function($) { + var src = $("head script").last().attr("src") || ''; + var scriptpath = src.split('?')[0].split('/').slice(0, -1).join('/')+'/'; + var csspath = scriptpath + 'jqt.actionsheet.css'; + var link = $('<link href="' + csspath + '" rel="stylesheet">'); + $('head').append($(link)); + + function hide(callback) { + var $target = $(this); + var data = $(this).data('actionsheet'); + var $source = data.source; + + var timeout; + + function cleanup() { + clearTimeout(timeout); + + $source.removeClass('transition'); + $target.removeClass('inmotion transition'); + !callback || callback.apply(this, arguments); + }; + timeout = setTimeout(cleanup, 500); + + if (data.shown) { + $(this).data('actionsheet', {}); + $target.one('webkitTransitionEnd', cleanup); + + $source.addClass('transition'); + $target.removeClass('current').addClass('inmotion transition'); + $('#jqt').removeClass('actionopened'); + } + return $target; + } + + function show(callback) { + var $target = $(this); + var data = $(this).data('actionsheet') || {}; + if (!data.shown) { + var $source = $('#jqt .current:not(.actionsheet)'); + + $target.one('webkitTransitionEnd', function() { + $source.removeClass('transition'); + $target.removeClass('inmotion transition'); + !callback || callback.apply(this, arguments); + }); + + data.shown = true; + data.source = $source; + $(this).data('actionsheet', data); + + $source.addClass('transition'); + $target.addClass('inmotion transition'); + $('#jqt').addClass('actionopened'); + setTimeout(function() { + $target.addClass('current'); + }, 50); + } + return $target; + } + + var methods = { + init: function(options) { + $(this).addClass('actionsheet'); + $(this).data({shown: false}); + }, + show: show, + hide: hide + }; + + $.fn.actionsheet = function(method) { + if (methods[method]) { + if ($(this).is('.actionsheet')) { + return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); + } else { + var msg = 'Target is not a `actionsheet`. Action `' + method + '` is ignored.'; + console.warn(msg); + } + } else if ( typeof method === 'object' || ! method ) { + return methods.init.apply(this, arguments); + } else { + $.error( 'Method ' + method + ' does not exist on jQuery.tooltip' ); + } + }; + + if ($.jQTouch) { + $.jQTouch.addTapHandler({ + name: 'open-actionsheet', + isSupported: function(e, params) { + return params.$el.is('.action'); + }, + fn: function(e, params) { + params.$el.removeClass('active'); + + var $target = $(params.hash); + $target.actionsheet('show'); + + return false; + } + }); + $.jQTouch.addTapHandler({ + name: 'follow-actionlink', + isSupported: function(e, params) { + if ($('#jqt').hasClass('actionopened')) { + return params.$el.is('.actionsheet a'); + } + return false; + }, + fn: function(e, params) { + params.$el.removeClass('active'); + + var $target = params.$el.closest('.actionsheet'); + $target.actionsheet('hide', function() { + if (!params.$el.is('.dismiss')) { + params.$el.trigger('tap'); + } + }); + return false; + } + }); + } else { + console.error('Extension `jqt.actionsheet` failed to load. jQT not found'); + } +})($); diff --git a/frontend/gamma/js/JQTouch/extensions/jqt.autotitles.js b/frontend/gamma/js/JQTouch/extensions/jqt.autotitles.js new file mode 100644 index 0000000..94f3d9b --- a/dev/null +++ b/frontend/gamma/js/JQTouch/extensions/jqt.autotitles.js @@ -0,0 +1,52 @@ +/* + + _/ _/_/ _/_/_/_/_/ _/ + _/ _/ _/ _/_/ _/ _/ _/_/_/ _/_/_/ + _/ _/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/ + _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ + _/ _/_/ _/ _/ _/_/ _/_/_/ _/_/_/ _/ _/ + _/ + _/ + + Created by David Kaneda <http://www.davidkaneda.com> + Maintained by Thomas Yip <http://beedesk.com/> + Sponsored by Sencha Labs <http://www.sencha.com/> + Special thanks to Jonathan Stark <http://www.jonathanstark.com/> + + Documentation and issue tracking on GitHub <http://github.com/senchalabs/jQTouch/> + + (c) 2009-2011 Sencha Labs + jQTouch may be freely distributed under the MIT license. + +*/ + +(function($) { + if ($.jQTouch) + { + $.jQTouch.addExtension(function AutoTitles(jQT){ + + var titleSelector='.toolbar h1'; + + $(function(){ + $('#jqt').bind('pageAnimationStart', function(e, data){ + if (data.direction === 'in'){ + var $title = $(titleSelector, $(e.target)); + var $ref = $(e.target).data('referrer'); + if ($title.length && $ref && $title.text() === ''){ + $title.html($ref.text()); + } + } + }); + }); + + function setTitleSelector(ts){ + titleSelector=ts; + } + + return { + setTitleSelector: setTitleSelector + }; + + }); + } +})($); diff --git a/frontend/gamma/js/JQTouch/extensions/jqt.floaty.js b/frontend/gamma/js/JQTouch/extensions/jqt.floaty.js new file mode 100644 index 0000000..c7e4485 --- a/dev/null +++ b/frontend/gamma/js/JQTouch/extensions/jqt.floaty.js @@ -0,0 +1,96 @@ +/* + + _/ _/_/ _/_/_/_/_/ _/ + _/ _/ _/ _/_/ _/ _/ _/_/_/ _/_/_/ + _/ _/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/ + _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ + _/ _/_/ _/ _/ _/_/ _/_/_/ _/_/_/ _/ _/ + _/ + _/ + + Created by David Kaneda <http://www.davidkaneda.com> + Documentation and issue tracking on Google Code <http://code.google.com/p/jqtouch/> + + Special thanks to Jonathan Stark <http://jonathanstark.com/> + and pinch/zoom <http://www.pinchzoom.com/> + + (c) 2009 by jQTouch project members. + See LICENSE.txt for license. + +*/ + +(function($) { + if ($.jQTouch) + { + $.jQTouch.addExtension(function Floaty(jQT){ + + $.fn.makeFloaty = function(options){ + var defaults = { + align: 'top', + spacing: 20, + time: '.3s' + }; + + var settings = $.extend({}, defaults, options); + + settings.align = (settings.align == 'top') ? 'top' : 'bottom'; + + return this.each(function(){ + var $el = $(this); + + $el.css({ + '-webkit-transition': 'top ' + settings.time + ' ease-in-out', + 'display': 'block', + 'min-height': '0 !important' + }).data('settings', settings); + + $(document).scroll(function(){ + if ($el.data('floatyVisible') === 'true') + { + $el.scrollFloaty(); + } + }); + $el.scrollFloaty(); + }); + }; + + $.fn.scrollFloaty = function(){ + + + return this.each(function(){ + var $el = $(this); + var settings = $el.data('settings'); // Settings not being set as object w/Zepto + var wHeight = $('html').attr('clientHeight'); // WRONG + + var newY = window.pageYOffset + + ((settings.align == 'top') ? + settings.spacing : wHeight - settings.spacing - $el.get(0).offsetHeight); + + $el.css('top', newY).data('floatyVisible', true); + }); + }; + + $.fn.hideFloaty = function(){ + return this.each(function(){ + var $el = $(this); + var oh = $el.get(0).offsetHeight; + + $el.css('top', -oh-10).data('floatyVisible', false); + }); + }; + + $.fn.toggleFloaty = function(){ + return this.each(function(){ + var $el = $(this); + if ($el.data('floatyVisible') === 'true'){ + $el.hideFloaty(); + } + else + { + $el.scrollFloaty(); + } + }); + }; + }); + } +})($);
\ No newline at end of file diff --git a/frontend/gamma/js/JQTouch/extensions/jqt.location.js b/frontend/gamma/js/JQTouch/extensions/jqt.location.js new file mode 100644 index 0000000..9d53a1a --- a/dev/null +++ b/frontend/gamma/js/JQTouch/extensions/jqt.location.js @@ -0,0 +1,51 @@ +(function($) { + if ($.jQTouch) + { + $.jQTouch.addExtension(function Location(){ + + var latitude, longitude, callback, callback2; + + function updateLocation(fn, fn2) { + if (navigator.geolocation) + { + callback = fn; + callback2 = fn2; + navigator.geolocation.getCurrentPosition(savePosition, failResponse); + return true; + } else { + console.log('Device not capable of geo-location.'); + fn(false); + return false; + } + } + function failResponse(error){ + if (callback2) { + callback2(error); + } + } + function savePosition(position) { + latitude = position.coords.latitude; + longitude = position.coords.longitude; + if (callback) { + callback(getLocation()); + } + } + function getLocation() { + if (latitude && longitude) { + return { + latitude: latitude, + longitude: longitude + }; + + } else { + console.log('No location available. Try calling updateLocation() first.'); + return false; + } + } + return { + updateLocation: updateLocation, + getLocation: getLocation + }; + }); + } +})($);
\ No newline at end of file diff --git a/frontend/gamma/js/JQTouch/extensions/jqt.menusheet.js b/frontend/gamma/js/JQTouch/extensions/jqt.menusheet.js new file mode 100644 index 0000000..8d21aca --- a/dev/null +++ b/frontend/gamma/js/JQTouch/extensions/jqt.menusheet.js @@ -0,0 +1,137 @@ +/* + + _/ _/_/ _/_/_/_/_/ _/ + _/ _/ _/ _/_/ _/ _/ _/_/_/ _/_/_/ + _/ _/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/ + _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ + _/ _/_/ _/ _/ _/_/ _/_/_/ _/_/_/ _/ _/ + _/ + _/ + + Documentation and issue tracking on Google Code <http://code.google.com/p/jqtouch/> + + (c) 2012 by jQTouch project members. + See LICENSE.txt for license. + + Author: Thomas Yip +*/ + +(function($) { + var src = $("head script").last().attr("src") || ''; + var scriptpath = src.split('?')[0].split('/').slice(0, -1).join('/')+'/'; + var csspath = scriptpath + 'jqt.menusheet.css'; + var link = $('<link href="' + csspath + '" rel="stylesheet">'); + $('head').append($(link)); + + function hide(callback) { + var $target = $(this); + var data = $(this).data('menusheet'); + if (data.shown) { + $(this).data('menusheet', {}); + var $source = data.source; + $source.unbind('touchstart mousedown', data.closehandler); + $source.one('webkitTransitionEnd', function() { + $source.removeClass('inmotion transition in'); + $target.removeClass('inmotion out'); + !callback || callback.apply(this, arguments); + }); + + $source.addClass('inmotion transition in'); + $target.addClass('inmotion out').removeClass('current'); + $('#jqt').removeClass('menuopened'); + } + return $target; + } + + function show(callback) { + var $target = $(this); + var data = $(this).data('menusheet') || {}; + if (!data.shown) { + var $source = $('#jqt .current:not(.menusheet)'); + var closehandler = function() { + $target.menusheet('hide'); + return false; + }; + + $source.one('webkitTransitionEnd', function() { + $source.one('touchstart mousedown', closehandler); + $source.removeClass('inmotion transition out'); + $target.removeClass('inmotion in'); + !callback || callback.apply(this, arguments); + }); + + data.shown = true; + data.closehandler = closehandler; + data.source = $source; + $(this).data('menusheet', data); + + $source.addClass('inmotion transition out'); + $target.addClass('current in'); + $('#jqt').addClass('menuopened'); + } + return $target; + } + + var methods = { + init: function(options) { + $(this).addClass('menusheet'); + $(this).data({shown: false}); + }, + show: show, + hide: hide + }; + + $.fn.menusheet = function(method) { + if (methods[method]) { + if ($(this).is('.menusheet')) { + return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); + } else { + var msg = 'Target is not a `menusheet`. Action `' + method + '` is ignored.'; + console.warn(msg); + } + } else if ( typeof method === 'object' || ! method ) { + return methods.init.apply(this, arguments); + } else { + $.error( 'Method ' + method + ' does not exist on jQuery.tooltip' ); + } + }; + + if ($.jQTouch) { + $.jQTouch.addTapHandler({ + name: 'open-menusheet', + isSupported: function(e, params) { + return params.$el.is('.menu'); + }, + fn: function(e, params) { + params.$el.removeClass('active'); + + var $target = $(params.hash); + $target.menusheet('show'); + + return false; + } + }); + $.jQTouch.addTapHandler({ + name: 'follow-menulink', + isSupported: function(e, params) { + if ($('#jqt').hasClass('menuopened')) { + return params.$el.is('.menusheet a'); + } + return false; + }, + fn: function(e, params) { + params.$el.removeClass('active'); + + var $target = params.$el.closest('.menusheet'); + $target.menusheet('hide', function() { + if (!params.$el.is('.dismiss')) { + params.$el.trigger('tap'); + } + }); + return false; + } + }); + } else { + console.error('Extension `jqt.menusheet` failed to load. jQT not found'); + } +})($); diff --git a/frontend/gamma/js/JQTouch/extensions/jqt.offline.js b/frontend/gamma/js/JQTouch/extensions/jqt.offline.js new file mode 100644 index 0000000..b333a16 --- a/dev/null +++ b/frontend/gamma/js/JQTouch/extensions/jqt.offline.js @@ -0,0 +1,97 @@ +/* + + _/ _/_/ _/_/_/_/_/ _/ + _/ _/ _/ _/_/ _/ _/ _/_/_/ _/_/_/ + _/ _/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/ + _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ + _/ _/_/ _/ _/ _/_/ _/_/_/ _/_/_/ _/ _/ + _/ + _/ + + Created by David Kaneda <http://www.davidkaneda.com> + Documentation and issue tracking on Google Code <http://code.google.com/p/jqtouch/> + + Special thanks to Jonathan Stark <http://jonathanstark.com/> + + Lots of this code is specifically derived from Jonathan's book, + "Building iPhone Apps with HTML, CSS, and JavaScript" + + (c) 2009 by jQTouch project members. + See LICENSE.txt for license. + +*/ + +(function($) { + if ($.jQTouch) + { + $.jQTouch.addExtension(function Offline(){ + + // Convenience array of status values + var cacheStatusValues = []; + cacheStatusValues[0] = 'uncached'; + cacheStatusValues[1] = 'idle'; + cacheStatusValues[2] = 'checking'; + cacheStatusValues[3] = 'downloading'; + cacheStatusValues[4] = 'updateready'; + cacheStatusValues[5] = 'obsolete'; + + // Listeners for all possible events + var cache = window.applicationCache; + cache.addEventListener('cached', logEvent, false); + cache.addEventListener('checking', logEvent, false); + cache.addEventListener('downloading', logEvent, false); + cache.addEventListener('error', logEvent, false); + cache.addEventListener('noupdate', logEvent, false); + cache.addEventListener('obsolete', logEvent, false); + cache.addEventListener('progress', logEvent, false); + cache.addEventListener('updateready', logEvent, false); + + // Log every event to the console + function logEvent(e) { + var online, status, type, message; + online = (isOnline()) ? 'yes' : 'no'; + status = cacheStatusValues[cache.status]; + type = e.type; + message = 'online: ' + online; + message+= ', event: ' + type; + message+= ', status: ' + status; + if (type == 'error' && navigator.onLine) { + message+= ' There was an unknown error, check your Cache Manifest.'; + } + console.log(message); + } + + function isOnline() { + return navigator.onLine; + } + + if (!$('html').attr('manifest')) { + console.log('No Cache Manifest listed on the <html> tag.') + } + + // Swap in newly download files when update is ready + cache.addEventListener('updateready', function(e){ + // Don't perform "swap" if this is the first cache + if (cacheStatusValues[cache.status] != 'idle') { + cache.swapCache(); + console.log('Swapped/updated the Cache Manifest.'); + } + } + , false); + + // These two functions check for updates to the manifest file + function checkForUpdates(){ + cache.update(); + } + function autoCheckForUpdates(){ + setInterval(function(){cache.update()}, 10000); + } + + return { + isOnline: isOnline, + checkForUpdates: checkForUpdates, + autoCheckForUpdates: autoCheckForUpdates + } + }); + } +})(jQuery);
\ No newline at end of file diff --git a/frontend/gamma/js/JQTouch/extensions/jqt.themeswitcher.js b/frontend/gamma/js/JQTouch/extensions/jqt.themeswitcher.js new file mode 100755 index 0000000..ef3a75d --- a/dev/null +++ b/frontend/gamma/js/JQTouch/extensions/jqt.themeswitcher.js @@ -0,0 +1,123 @@ +/* + + _/ _/_/ _/_/_/_/_/ _/ + _/ _/ _/ _/_/ _/ _/ _/_/_/ _/_/_/ + _/ _/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/ + _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ + _/ _/_/ _/ _/ _/_/ _/_/_/ _/_/_/ _/ _/ + _/ + _/ + + Documentation and issue tracking on Google Code <http://code.google.com/p/jqtouch/> + + (c) 2011 by jQTouch project members. + See LICENSE.txt for license. + +*/ + +(function($) { + if ($.jQTouch) { + + var scriptpath = $("script").last().attr("src").split('?')[0].split('/').slice(0, -1).join('/')+'/'; + + $.jQTouch.addExtension(function ThemeSwitcher(jQT) { + + var current, + link, + titles = {}, + defaults = { + themeStyleSelector: 'link[rel="stylesheet"][title]', + themeIncluded: [ + {title: 'jQTouch', href: scriptpath + '../themes/css/jqtouch.css'}, + {title: 'Apple', href: scriptpath + '../themes/css/apple.css'}, + {title: 'Vanilla', href: scriptpath + '../themes/css/vanilla.css'} + + ] + }, + options = $.extend({}, defaults, jQT.settings); + + function setStyleState(item, title) { + var $item = $(item); + + if ($item.attr('title') === title) { + item.disabled = false; // workaround for Firefox on Zepto + $item.removeAttr('disabled'); + } else { + item.disabled = true; // workaround for Firefox on Zepto + $item.attr('disabled', true); + } + } + + function initializeStyleState(item, title) { + // and, workaround for WebKit by initializing the 'disabled' attribute + if (!current) { + current = title; + } + setStyleState(item, current); + } + + // public + function switchStyle(title) { + current = title; + $(options.themeStyleSelector).each(function(i, item) { + setStyleState(item, title); + }); + } + + // collect title names, from <head> + $(options.themeStyleSelector).each(function(i, item) { + var $item = $(item); + var title = $item.attr('title'); + + titles[title] = true; + + initializeStyleState(item, title); + }); + + // add included theme + for (var i=0; i < options.themeIncluded.length; i++) { + var hash = options.themeIncluded[i]; + if (!(hash.title in titles)) { + link = $('<link title="' + hash.title + '" href="' + hash.href + '" rel="stylesheet">'); + $('head').append($(link)); + + titles[hash.title] = true; + + initializeStyleState(link, hash.title); + } + } + + if (options.themeSelectionSelector) { + // create UI items + for (var title in titles) { + var $item = $('<li><a href="#" data-title="' + title + '">' + title + '</a></li>'); + $(options.themeSelectionSelector).append($item); + } + + // bind to UI items + $(options.themeSelectionSelector).delegate('* > a', 'tap', function(e) { + e.preventDefault(); + e.stopPropagation(); + + var $a = $(this).closest('a'); + $a.removeClass('active'); + switchStyle($a.attr('data-title')); + + // poor-man simulation of radio button behaviour + $(options.themeSelectionSelector).find('a').removeClass('selected'); + $a.addClass('selected'); + }); + + // poor-man simulation of radio button behaviour + $(options.themeSelectionSelector).closest('#jqt > *').bind('pageAnimationEnd', function(e, data){ + if (data.direction === 'in') { + $(options.themeSelectionSelector).find('a[data-title="' + current + '"]').addClass('selected'); + } + }); + } + + return {switchStyle: switchStyle}; + + }); + } +})($); diff --git a/frontend/gamma/js/JQTouch/jqtouch.js b/frontend/gamma/js/JQTouch/jqtouch.js new file mode 100644 index 0000000..bdc6d2e --- a/dev/null +++ b/frontend/gamma/js/JQTouch/jqtouch.js @@ -0,0 +1,889 @@ +/* + + _/ _/_/ _/_/_/_/_/ _/ + _/ _/ _/ _/_/ _/ _/ _/_/_/ _/_/_/ + _/ _/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/ + _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ + _/ _/_/ _/ _/ _/_/ _/_/_/ _/_/_/ _/ _/ + _/ + _/ + + Created by David Kaneda <http://www.davidkaneda.com> + Maintained by Thomas Yip <http://beedesk.com/> + Sponsored by Sencha Labs <http://www.sencha.com/> + Special thanks to Jonathan Stark <http://www.jonathanstark.com/> + + Documentation and issue tracking on GitHub <http://github.com/senchalabs/jQTouch/> + + (c) 2009-2011 Sencha Labs + jQTouch may be freely distributed under the MIT license. + +*/ +(function() { + + var fx; + if ('Zepto' in window) { + fx = window.Zepto; + fx.fn.prop = fx.fn.attr; + + Event.prototype.isDefaultPrevented = function() { + return this.defaultPrevented; + }; + } else if ('jQuery' in window) { + fx = window.jQuery; + + // trick to get Zepto/touch.js to work for jQuery + window.Zepto = $; + } else { + throw('Either Zepto or jQuery is required but neither can be found.'); + } + + $.jQTouch = function(options) { + // Initialize internal jQT variables + var $ = fx, + $body, + $head=$('head'), + history=[], + newPageCount=0, + jQTSettings={}, + $currentPage='', + orientation='portrait', + touchSelectors=[], + publicObj={}, + tapBuffer=100, // High click delay = ~350, quickest animation (slide) = 250 + extensions=$.jQTouch.prototype.extensions, + extTapHandlers=$.jQTouch.prototype.tapHandlers, + tapHandlers=[], + animations=[], + hairExtensions='', + defaults = { + addGlossToIcon: true, + backSelector: '.back, .cancel, .goback', + cacheGetRequests: true, + debug: true, + defaultAnimation: 'slideleft', + fixedViewport: true, + formSelector: 'form', + fullScreen: true, + fullScreenClass: 'fullscreen', + icon: null, + icon4: null, // available in iOS 4.2 and later. + preloadImages: false, + startupScreen: null, + statusBar: 'default', // other options: black-translucent, black + submitSelector: '.submit', + touchSelector: 'a, .touch', + trackScrollPositions: true, + useAnimations: true, + useFastTouch: true, + useTouchScroll: true, + animations: [ // highest to lowest priority + {name:'cubeleft', selector:'.cubeleft, .cube', is3d: true}, + {name:'cuberight', selector:'.cuberight', is3d: true}, + {name:'dissolve', selector:'.dissolve'}, + {name:'fade', selector:'.fade'}, + {name:'flipleft', selector:'.flipleft, .flip', is3d: true}, + {name:'flipright', selector:'.flipright', is3d: true}, + {name:'pop', selector:'.pop', is3d: true}, + {name:'swapleft', selector:'.swap', is3d: true}, + {name:'slidedown', selector:'.slidedown'}, + {name:'slideright', selector:'.slideright'}, + {name:'slideup', selector:'.slideup'}, + {name:'slideleft', selector:'.slideleft, .slide, #jqt > * > ul li a'} + ] + }; // end defaults + + function warn(message) { + if (window.console !== undefined && jQTSettings.debug === true) { + console.warn(message); + } + } + function addAnimation(animation) { + if (typeof(animation.selector) === 'string' && typeof(animation.name) === 'string') { + animations.push(animation); + } + } + function addTapHandler(tapHandler) { + if (typeof(tapHandler.name) === 'string' + && typeof(tapHandler.isSupported) === 'function' + && typeof(tapHandler.fn) === 'function') { + + tapHandlers.push(tapHandler); + } + } + function addPageToHistory(page, animation) { + history.unshift({ + page: page, + animation: animation, + hash: '#' + page.attr('id'), + id: page.attr('id') + }); + } + + // Unfortunately, we can not assume the "tap" event + // is being used for links, forms, etc. + function clickHandler(e) { + // Figure out whether to prevent default + var $el = $(e.target); + + // Find the nearest tappable ancestor + if (!$el.is(touchSelectors.join(', '))) { + $el = $(e.target).closest(touchSelectors.join(', ')); + } + + // Prevent default if we found an internal link (relative or absolute) + if ($el && $el.attr('href') && !$el.isExternalLink()) { + warn('Need to prevent default click behavior'); + e.preventDefault(); + } else { + warn('No need to prevent default click behavior'); + } + + // Trigger a tap event if touchstart is not on the job + if ($.support.touch) { + warn('Not converting click to a tap event because touch handler is on the job'); + } else { + warn('Converting click event to a tap event because touch handlers are not present or off'); + $(e.target).trigger('tap', e); + } + + } + function doNavigation(fromPage, toPage, animation, goingBack) { + + goingBack = goingBack ? goingBack : false; + + // Error check for target page + if (toPage === undefined || toPage.length === 0) { + $.fn.unselect(); + warn('Target element is missing.'); + return false; + } + + // Error check for fromPage===toPage + if (toPage.hasClass('current')) { + $.fn.unselect(); + warn('You are already on the page you are trying to navigate to.'); + return false; + } + + // Collapse the keyboard + $(':focus').trigger('blur'); + + fromPage.trigger('pageAnimationStart', { direction: 'out', back: goingBack }); + toPage.trigger('pageAnimationStart', { direction: 'in', back: goingBack }); + + if ($.support.animationEvents && animation && jQTSettings.useAnimations) { + // Fail over to 2d animation if need be + if (!$.support.transform3d && animation.is3d) { + warn('Did not detect support for 3d animations, falling back to ' + jQTSettings.defaultAnimation); + animation.name = jQTSettings.defaultAnimation; + } + + // Reverse animation if need be + var finalAnimationName = animation.name, + is3d = animation.is3d ? 'animating3d' : ''; + + if (goingBack) { + finalAnimationName = finalAnimationName.replace(/left|right|up|down|in|out/, reverseAnimation ); + } + + warn('finalAnimationName is ' + finalAnimationName); + + // Bind internal "cleanup" callback + fromPage.bind('webkitAnimationEnd', navigationEndHandler); + + // Trigger animations + $body.addClass('animating ' + is3d); + + var lastScroll = window.pageYOffset; + + // Position the incoming page so toolbar is at top of viewport regardless of scroll position on from page + if (jQTSettings.trackScrollPositions === true) { + toPage.css('top', window.pageYOffset - (toPage.data('lastScroll') || 0)); + } + + toPage.addClass(finalAnimationName + ' in current'); + fromPage.removeClass('current').addClass(finalAnimationName + ' out inmotion'); + + if (jQTSettings.trackScrollPositions === true) { + fromPage.data('lastScroll', lastScroll); + $('.scroll', fromPage).each(function(){ + $(this).data('lastScroll', this.scrollTop); + }); + } + } else { + toPage.addClass('current in'); + fromPage.removeClass('current'); + navigationEndHandler(); + } + + // Housekeeping + $currentPage = toPage; + if (goingBack) { + history.shift(); + } else { + addPageToHistory($currentPage, animation); + } + setHash($currentPage.attr('id')); + + // Private navigationEnd callback + function navigationEndHandler(event) { + var bufferTime = tapBuffer; + + if ($.support.animationEvents && animation && jQTSettings.useAnimations) { + fromPage.unbind('webkitAnimationEnd', navigationEndHandler); + fromPage.removeClass(finalAnimationName + ' out inmotion'); + if (finalAnimationName) { + toPage.removeClass(finalAnimationName); + } + $body.removeClass('animating animating3d'); + if (jQTSettings.trackScrollPositions === true) { + toPage.css('top', -toPage.data('lastScroll')); + + // Have to make sure the scroll/style resets + // are outside the flow of this function. + setTimeout(function(){ + toPage.css('top', 0); + window.scroll(0, toPage.data('lastScroll')); + $('.scroll', toPage).each(function(){ + this.scrollTop = - $(this).data('lastScroll'); + }); + }, 0); + } + } else { + fromPage.removeClass(finalAnimationName + ' out inmotion'); + if (finalAnimationName) { + toPage.removeClass(finalAnimationName); + } + bufferTime += 260; + } + + // In class is intentionally delayed, as it is our ghost click hack + setTimeout(function(){ + toPage.removeClass('in'); + window.scroll(0,0); + }, bufferTime); + + fromPage.unselect(); + + // Trigger custom events + toPage.trigger('pageAnimationEnd', { + direction:'in', animation: animation, back: goingBack + }); + fromPage.trigger('pageAnimationEnd', { + direction:'out', animation: animation, back: goingBack + }); + } + + return true; + } + function reverseAnimation(animation) { + var opposites={ + 'up' : 'down', + 'down' : 'up', + 'left' : 'right', + 'right' : 'left', + 'in' : 'out', + 'out' : 'in' + }; + + return opposites[animation] || animation; + } + function getOrientation() { + return orientation; + } + function goBack() { + + // Error checking + if (history.length < 1 ) { + warn('History is empty.'); + } + + if (history.length === 1 ) { + warn('You are on the first panel.'); + window.history.go(-1); + } + + var from = history[0], + to = history[1]; + + if (doNavigation(from.page, to.page, from.animation, true)) { + return publicObj; + } else { + warn('Could not go back.'); + return false; + } + + } + function goTo(toPage, animation) { + + var fromPage = history[0].page; + + if (typeof animation === 'string') { + for (var i=0, max=animations.length; i < max; i++) { + if (animations[i].name === animation) { + animation = animations[i]; + break; + } + } + } + + if (typeof toPage === 'string') { + var nextPage = $(toPage); + + if (nextPage.length < 1) { + showPageByHref(toPage, { + animation: animation + }); + return; + } else { + toPage = nextPage; + } + } + if (doNavigation(fromPage, toPage, animation)) { + return publicObj; + } else { + warn('Could not animate pages.'); + return false; + } + } + function hashChangeHandler(e) { + if (location.hash === history[0].hash) { + warn('We are on the right panel'); + return true; + } else if (location.hash === '') { + goBack(); + return true; + } else { + if( (history[1] && location.hash === history[1].hash) ) { + goBack(); + return true; + } else { + // Lastly, just try going to the ID... + warn('Could not find ID in history, just forwarding to DOM element.'); + goTo($(location.hash), jQTSettings.defaultAnimation); + } + } + } + function init(options) { + jQTSettings = $.extend({}, defaults, options); + + // Preload images + if (jQTSettings.preloadImages) { + for (var i = jQTSettings.preloadImages.length - 1; i >= 0; i--) { + (new Image()).src = jQTSettings.preloadImages[i]; + } + } + + // Set appropriate icon (retina display available in iOS 4.2 and later.) + var precomposed = (jQTSettings.addGlossToIcon) ? '' : '-precomposed'; + if (jQTSettings.icon) { + hairExtensions += '<link rel="apple-touch-icon' + precomposed + '" href="' + jQTSettings.icon + '" />'; + } + if (jQTSettings.icon4) { + hairExtensions += '<link rel="apple-touch-icon' + precomposed + '" sizes="114x114" href="' + jQTSettings.icon4 + '" />'; + } + // Set startup screen + if (jQTSettings.startupScreen) { + hairExtensions += '<link rel="apple-touch-startup-image" href="' + jQTSettings.startupScreen + '" />'; + } + + // Set viewport + if (jQTSettings.fixedViewport) { + hairExtensions += '<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>'; + } + + // Set full-screen + if (jQTSettings.fullScreen) { + hairExtensions += '<meta name="apple-mobile-web-app-capable" content="yes" />'; + if (jQTSettings.statusBar) { + hairExtensions += '<meta name="apple-mobile-web-app-status-bar-style" content="' + jQTSettings.statusBar + '" />'; + } + } + + // Attach hair extensions + if (hairExtensions) { + $head.prepend(hairExtensions); + } + } + + function getAnimation(el) { + var animation; + + for (var i=0, max=animations.length; i < max; i++) { + if (el.is(animations[i].selector)) { + animation = animations[i]; + break; + } + } + + if (!animation) { + warn('Animation could not be found. Using ' + jQTSettings.defaultAnimation + '.'); + animation = jQTSettings.defaultAnimation; + } + return animation; + } + + function insertPages(nodes, animation) { + + var targetPage = null; + + // Call dom.createElement element directly instead of relying on $(nodes), + // to work around: https://github.com/madrobby/zepto/issues/312 + var div = document.createElement('div'); + div.innerHTML = nodes; + + $(div).children().each(function(index, node) { + var $node = $(this); + if (!$node.attr('id')) { + $node.attr('id', 'page-' + (++newPageCount)); + } + + // Remove any existing instance + $('#' + $node.attr('id')).remove(); + + $body.append($node); + $body.trigger('pageInserted', {page: $node}); + + if ($node.hasClass('current') || !targetPage) { + targetPage = $node; + } + }); + if (targetPage !== null) { + goTo(targetPage, animation); + return targetPage; + } else { + return false; + } + } + + function orientationChangeHandler() { + $body.css('minHeight', 1000); + scrollTo(0,0); + var bodyHeight = window.innerHeight; + $body.css('minHeight', bodyHeight); + + orientation = Math.abs(window.orientation) == 90 ? 'landscape' : 'portrait'; + $body.removeClass('portrait landscape').addClass(orientation).trigger('turn', {orientation: orientation}); + } + function setHash(hash) { + // Sanitize + location.hash = '#' + hash.replace(/^#/, ''); + } + function showPageByHref(href, options) { + + var defaults = { + data: null, + method: 'GET', + animation: null, + callback: null, + $referrer: null + }; + + var settings = $.extend({}, defaults, options); + + if (href != '#') { + $.ajax({ + url: href, + data: settings.data, + type: settings.method, + success: function (data) { + var firstPage = insertPages(data, settings.animation); + if (firstPage) { + if (settings.method == 'GET' && jQTSettings.cacheGetRequests === true && settings.$referrer) { + settings.$referrer.attr('href', '#' + firstPage.attr('id')); + } + if (settings.callback) { + settings.callback(true); + } + } + }, + error: function (data) { + if (settings.$referrer) { + settings.$referrer.unselect(); + } + if (settings.callback) { + settings.callback(false); + } + } + }); + } else if (settings.$referrer) { + settings.$referrer.unselect(); + } + } + function submitHandler(e, callback) { + + $(':focus').trigger('blur'); + + e.preventDefault(); + + var $form = (typeof(e)==='string') ? $(e).eq(0) : (e.target ? $(e.target) : $(e)); + + if ($form.length && $form.is(jQTSettings.formSelector) && $form.attr('action')) { + showPageByHref($form.attr('action'), { + data: $form.serialize(), + method: $form.attr('method') || "POST", + animation: getAnimation($form), + callback: callback + }); + return false; + } + return true; + } + function submitParentForm($el) { + + var $form = $el.closest('form'); + if ($form.length === 0) { + warn('No parent form found'); + } else { + warn('About to submit parent form'); + $form.trigger('submit'); + return false; + } + return true; + } + function supportForTransform3d() { + + var head, body, style, div, result; + + head = document.getElementsByTagName('head')[0]; + body = document.body; + + style = document.createElement('style'); + style.textContent = '@media (transform-3d),(-o-transform-3d),(-moz-transform-3d),(-webkit-transform-3d){#jqt-3dtest{height:3px}}'; + + div = document.createElement('div'); + div.id = 'jqt-3dtest'; + + // Add to the page + head.appendChild(style); + body.appendChild(div); + + // Check the result + result = div.offsetHeight === 3; + + // Clean up + style.parentNode.removeChild(style); + div.parentNode.removeChild(div); + + // Pass back result + warn('Support for 3d transforms: ' + result); + return result; + } + function supportIOS5() { + var support = false; + var REGEX_IOS_VERSION = /OS (\d+)(_\d+)* like Mac OS X/i; + + var agentString = window.navigator.userAgent; + if (REGEX_IOS_VERSION.test(agentString)) { + support = (REGEX_IOS_VERSION.exec(agentString)[1] >= 5); + } + return support; + } + function touchStartHandler(e){ + + var $el = $(e.target), + selectors = touchSelectors.join(', '); + + // Find the nearest tappable ancestor + if (!$el.is(selectors)) { + $el = $el.closest(selectors); + } + + // Make sure we have a tappable element + if ($el.length && $el.attr('href')) { + $el.addClass('active'); + } + + // Remove our active class if we move + $el.on($.support.touch ? 'touchmove' : 'mousemove', function(){ + $el.removeClass('active'); + }); + + $el.on('touchend', function(){ + $el.unbind('touchmove mousemove'); + }); + + } + function tapHandler(e){ + + if (e.isDefaultPrevented()) { + return true; + } + + // Grab the target element + var $el = $(e.target); + + // Find the nearest tappable ancestor + if (!$el.is(touchSelectors.join(', '))) { + $el = $el.closest(touchSelectors.join(', ')); + } + + // Make sure we have a tappable element + if (!$el.length || !$el.attr('href')) { + warn('Could not find a link related to tapped element'); + return true; + } + + // Init some vars + var target = $el.attr('target'), + hash = $el.prop('hash'), + href = $el.attr('href'); + + var params = { + e: e, + $el: $el, + target: target, + hash: hash, + href: href, + jQTSettings: jQTSettings + }; + + // Loop thru all handlers + for (var i=0, len=tapHandlers.length; i<len; i++) { + var handler = tapHandlers[i]; + var supported = handler.isSupported(e, params); + if (supported) { + var flag = handler.fn(e, params); + return flag; + } + } + } + function addDefaultTapHandlers() { + addTapHandler({ + name: 'external-link', + isSupported: function(e, params) { + return params.$el.isExternalLink(); + }, + fn: function(e, params) { + params.$el.unselect(); + return true; + } + }); + addTapHandler({ + name: 'back-selector', + isSupported: function(e, params) { + return params.$el.is(params.jQTSettings.backSelector); + }, + fn: function(e, params) { + // User clicked or tapped a back button + goBack(params.hash); + } + }); + addTapHandler({ + name: 'submit-selector', + isSupported: function(e, params) { + return params.$el.is(params.jQTSettings.submitSelector); + }, + fn: function(e, params) { + // User clicked or tapped a submit element + submitParentForm(params.$el); + } + }); + addTapHandler({ + name: 'webapp', + isSupported: function(e, params) { + return params.target === '_webapp'; + }, + fn: function(e, params) { + // User clicked or tapped an internal link, fullscreen mode + window.location = params.href; + return false; + } + }); + addTapHandler({ + name: 'no-op', + isSupported: function(e, params) { + return params.href === '#'; + }, + fn: function(e, params) { + // Allow tap on item with no href + params.$el.unselect(); + return true; + } + }); + addTapHandler({ + name: 'standard', + isSupported: function(e, params) { + return params.hash && params.hash !== '#'; + }, + fn: function(e, params) { + var animation = getAnimation(params.$el); + // Internal href + params.$el.addClass('active'); + goTo( + $(params.hash).data('referrer', params.$el), + animation, + params.$el.hasClass('reverse') + ); + return false; + } + }); + addTapHandler({ + name: 'external', + isSupported: function(e, params) { + return true; + }, + fn: function(e, params) { + var animation = getAnimation(params.$el); + + // External href + params.$el.addClass('loading active'); + showPageByHref(params.$el.attr('href'), { + animation: animation, + callback: function() { + params.$el.removeClass('loading'); + setTimeout($.fn.unselect, 250, params.$el); + }, + $referrer: params.$el + }); + return false; + } + }); + }; + + // Get the party started + init(options); + + // Document ready stuff + $(document).ready(function RUMBLE() { + // Store some properties in a support object + if (!$.support) $.support = {}; + $.support.animationEvents = (typeof window.WebKitAnimationEvent != 'undefined'); + $.support.touch = (typeof window.TouchEvent != 'undefined') && (window.navigator.userAgent.indexOf('Mobile') > -1) && jQTSettings.useFastTouch; + $.support.transform3d = supportForTransform3d(); + $.support.ios5 = supportIOS5(); + + if (!$.support.touch) { + warn('This device does not support touch interaction, or it has been deactivated by the developer. Some features might be unavailable.'); + } + if (!$.support.transform3d) { + warn('This device does not support 3d animation. 2d animations will be used instead.'); + } + + // Define public jQuery functions + $.fn.isExternalLink = function() { + var $el = $(this); + return ($el.attr('target') == '_blank' || $el.attr('rel') == 'external' || $el.is('a[href^="http://maps.google.com"], a[href^="mailto:"], a[href^="tel:"], a[href^="javascript:"], a[href*="youtube.com/v"], a[href*="youtube.com/watch"]')); + }; + $.fn.makeActive = function() { + return $(this).addClass('active'); + }; + $.fn.unselect = function(obj) { + if (obj) { + obj.removeClass('active'); + } else { + $('.active').removeClass('active'); + } + }; + + // Add extensions + for (var i=0, max=extensions.length; i < max; i++) { + var fn = extensions[i]; + if ($.isFunction(fn)) { + $.extend(publicObj, fn(publicObj)); + } + } + + // Add extensions tapHandlers + for (var i=0, max=extTapHandlers.length; i < max; i++) { + addTapHandler(extTapHandlers[i]); + } + // Add default tapHandlers + addDefaultTapHandlers(); + + // Add animations + for (var j=0, max_anims=defaults.animations.length; j < max_anims; j++) { + var animation = defaults.animations[j]; + if(jQTSettings[animation.name + 'Selector'] !== undefined){ + animation.selector = jQTSettings[animation.name + 'Selector']; + } + addAnimation(animation); + } + + // Create an array of stuff that needs touch event handling + touchSelectors.push(jQTSettings.touchSelector); + touchSelectors.push(jQTSettings.backSelector); + touchSelectors.push(jQTSettings.submitSelector); + $(touchSelectors.join(', ')).css('-webkit-touch-callout', 'none'); + + // Make sure we have a jqt element + $body = $('#jqt'); + var anatomy_lessons = []; + + if ($body.length === 0) { + warn('Could not find an element with the id "jqt", so the body id has been set to "jqt". If you are having any problems, wrapping your panels in a div with the id "jqt" might help.'); + $body = $(document.body).attr('id', 'jqt'); + } + + // Add some specific css if need be + if ($.support.transform3d) { + anatomy_lessons.push('supports3d'); + } + if ($.support.ios5 && jQTSettings.useTouchScroll) { + anatomy_lessons.push('touchscroll'); + } + + if (jQTSettings.fullScreenClass && window.navigator.standalone === true) { + anatomy_lessons.push(jQTSettings.fullScreenClass, jQTSettings.statusBar); + } + + // Bind events + + $body + .addClass(anatomy_lessons.join(' ')) + .bind('click', clickHandler) + .bind('orientationchange', orientationChangeHandler) + .bind('submit', submitHandler) + .bind('tap', tapHandler) + .bind( $.support.touch ? 'touchstart' : 'mousedown', touchStartHandler) + .trigger('orientationchange'); + + $(window).bind('hashchange', hashChangeHandler); + + var startHash = location.hash; + + // Determine what the initial view should be + if ($('#jqt > .current').length === 0) { + $currentPage = $('#jqt > *:first-child').addClass('current'); + } else { + $currentPage = $('#jqt > .current'); + } + + setHash($currentPage.attr('id')); + addPageToHistory($currentPage); + + if ($(startHash).length === 1) { + goTo(startHash); + } + }); + + // Expose public methods and properties + publicObj = { + addAnimation: addAnimation, + animations: animations, + getOrientation: getOrientation, + goBack: goBack, + insertPages: insertPages, + goTo: goTo, + history: history, + settings: jQTSettings, + submitForm: submitHandler + }; + return publicObj; + }; + + $.jQTouch.prototype.extensions = []; + $.jQTouch.prototype.tapHandlers = []; + + // Extensions directly manipulate the jQTouch object, before it's initialized. + $.jQTouch.addExtension = function(extension) { + $.jQTouch.prototype.extensions.push(extension); + }; + + // Experimental tap hanlders that can bypass default jQTouch tap handling + $.jQTouch.addTapHandler = function(extension) { + $.jQTouch.prototype.tapHandlers.push(extension); + }; + +})(); // Double closure, ALL THE WAY ACROSS THE SKY diff --git a/frontend/gamma/js/Zepto/ajax.js b/frontend/gamma/js/Zepto/ajax.js new file mode 100644 index 0000000..f4da150 --- a/dev/null +++ b/frontend/gamma/js/Zepto/ajax.js @@ -0,0 +1,285 @@ +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(function($){ + var jsonpID = 0, + isObject = $.isObject, + document = window.document, + key, + name, + rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, + scriptTypeRE = /^(?:text|application)\/javascript/i, + xmlTypeRE = /^(?:text|application)\/xml/i, + jsonType = 'application/json', + htmlType = 'text/html', + blankRE = /^\s*$/ + + // trigger a custom event and return false if it was cancelled + function triggerAndReturn(context, eventName, data) { + var event = $.Event(eventName) + $(context).trigger(event, data) + return !event.defaultPrevented + } + + // trigger an Ajax "global" event + function triggerGlobal(settings, context, eventName, data) { + if (settings.global) return triggerAndReturn(context || document, eventName, data) + } + + // Number of active Ajax requests + $.active = 0 + + function ajaxStart(settings) { + if (settings.global && $.active++ === 0) triggerGlobal(settings, null, 'ajaxStart') + } + function ajaxStop(settings) { + if (settings.global && !(--$.active)) triggerGlobal(settings, null, 'ajaxStop') + } + + // triggers an extra global event "ajaxBeforeSend" that's like "ajaxSend" but cancelable + function ajaxBeforeSend(xhr, settings) { + var context = settings.context + if (settings.beforeSend.call(context, xhr, settings) === false || + triggerGlobal(settings, context, 'ajaxBeforeSend', [xhr, settings]) === false) + return false + + triggerGlobal(settings, context, 'ajaxSend', [xhr, settings]) + } + function ajaxSuccess(data, xhr, settings) { + var context = settings.context, status = 'success' + settings.success.call(context, data, status, xhr) + triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data]) + ajaxComplete(status, xhr, settings) + } + // type: "timeout", "error", "abort", "parsererror" + function ajaxError(error, type, xhr, settings) { + var context = settings.context + settings.error.call(context, xhr, type, error) + triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error]) + ajaxComplete(type, xhr, settings) + } + // status: "success", "notmodified", "error", "timeout", "abort", "parsererror" + function ajaxComplete(status, xhr, settings) { + var context = settings.context + settings.complete.call(context, xhr, status) + triggerGlobal(settings, context, 'ajaxComplete', [xhr, settings]) + ajaxStop(settings) + } + + // Empty function, used as default callback + function empty() {} + + $.ajaxJSONP = function(options){ + if (!('type' in options)) return $.ajax(options) + + var callbackName = 'jsonp' + (++jsonpID), + script = document.createElement('script'), + abort = function(){ + $(script).remove() + if (callbackName in window) window[callbackName] = empty + ajaxComplete('abort', xhr, options) + }, + xhr = { abort: abort }, abortTimeout + + if (options.error) script.onerror = function() { + xhr.abort() + options.error() + } + + window[callbackName] = function(data){ + clearTimeout(abortTimeout) + $(script).remove() + delete window[callbackName] + ajaxSuccess(data, xhr, options) + } + + serializeData(options) + script.src = options.url.replace(/=\?/, '=' + callbackName) + $('head').append(script) + + if (options.timeout > 0) abortTimeout = setTimeout(function(){ + xhr.abort() + ajaxComplete('timeout', xhr, options) + }, options.timeout) + + return xhr + } + + $.ajaxSettings = { + // Default type of request + type: 'GET', + // Callback that is executed before request + beforeSend: empty, + // Callback that is executed if the request succeeds + success: empty, + // Callback that is executed the the server drops error + error: empty, + // Callback that is executed on request complete (both: error and success) + complete: empty, + // The context for the callbacks + context: null, + // Whether to trigger "global" Ajax events + global: true, + // Transport + xhr: function () { + return new window.XMLHttpRequest() + }, + // MIME types mapping + accepts: { + script: 'text/javascript, application/javascript', + json: jsonType, + xml: 'application/xml, text/xml', + html: htmlType, + text: 'text/plain' + }, + // Whether the request is to another domain + crossDomain: false, + // Default timeout + timeout: 0, + // Whether data should be serialized to string + processData: true + } + + function mimeToDataType(mime) { + return mime && ( mime == htmlType ? 'html' : + mime == jsonType ? 'json' : + scriptTypeRE.test(mime) ? 'script' : + xmlTypeRE.test(mime) && 'xml' ) || 'text' + } + + function appendQuery(url, query) { + return (url + '&' + query).replace(/[&?]{1,2}/, '?') + } + + // serialize payload and append it to the URL for GET requests + function serializeData(options) { + if (options.processData && isObject(options.data)) + options.data = $.param(options.data, options.traditional) + if (options.data && (!options.type || options.type.toUpperCase() == 'GET')) + options.url = appendQuery(options.url, options.data) + } + + $.ajax = function(options){ + var settings = $.extend({}, options || {}) + for (key in $.ajaxSettings) if (settings[key] === undefined) settings[key] = $.ajaxSettings[key] + + ajaxStart(settings) + + if (!settings.crossDomain) settings.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(settings.url) && + RegExp.$2 != window.location.host + + var dataType = settings.dataType, hasPlaceholder = /=\?/.test(settings.url) + if (dataType == 'jsonp' || hasPlaceholder) { + if (!hasPlaceholder) settings.url = appendQuery(settings.url, 'callback=?') + return $.ajaxJSONP(settings) + } + + if (!settings.url) settings.url = window.location.toString() + serializeData(settings) + + var mime = settings.accepts[dataType], + baseHeaders = { }, + protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol, + xhr = $.ajaxSettings.xhr(), abortTimeout + + if (!settings.crossDomain) baseHeaders['X-Requested-With'] = 'XMLHttpRequest' + if (mime) { + baseHeaders['Accept'] = mime + if (mime.indexOf(',') > -1) mime = mime.split(',', 2)[0] + xhr.overrideMimeType && xhr.overrideMimeType(mime) + } + if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() != 'GET')) + baseHeaders['Content-Type'] = (settings.contentType || 'application/x-www-form-urlencoded') + settings.headers = $.extend(baseHeaders, settings.headers || {}) + + xhr.onreadystatechange = function(){ + if (xhr.readyState == 4) { + xhr.onreadystatechange = empty; + clearTimeout(abortTimeout) + var result, error = false + if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && protocol == 'file:')) { + dataType = dataType || mimeToDataType(xhr.getResponseHeader('content-type')) + result = xhr.responseText + + try { + if (dataType == 'script') (1,eval)(result) + else if (dataType == 'xml') result = xhr.responseXML + else if (dataType == 'json') result = blankRE.test(result) ? null : $.parseJSON(result) + } catch (e) { error = e } + + if (error) ajaxError(error, 'parsererror', xhr, settings) + else ajaxSuccess(result, xhr, settings) + } else { + ajaxError(null, xhr.status ? 'error' : 'abort', xhr, settings) + } + } + } + + var async = 'async' in settings ? settings.async : true + xhr.open(settings.type, settings.url, async) + + for (name in settings.headers) xhr.setRequestHeader(name, settings.headers[name]) + + if (ajaxBeforeSend(xhr, settings) === false) { + xhr.abort() + return false + } + + if (settings.timeout > 0) abortTimeout = setTimeout(function(){ + xhr.onreadystatechange = empty + xhr.abort() + ajaxError(null, 'timeout', xhr, settings) + }, settings.timeout) + + // avoid sending empty string (#319) + xhr.send(settings.data ? settings.data : null) + return xhr + } + + $.get = function(url, success){ return $.ajax({ url: url, success: success }) } + + $.post = function(url, data, success, dataType){ + if ($.isFunction(data)) dataType = dataType || success, success = data, data = null + return $.ajax({ type: 'POST', url: url, data: data, success: success, dataType: dataType }) + } + + $.getJSON = function(url, success){ + return $.ajax({ url: url, success: success, dataType: 'json' }) + } + + $.fn.load = function(url, success){ + if (!this.length) return this + var self = this, parts = url.split(/\s/), selector + if (parts.length > 1) url = parts[0], selector = parts[1] + $.get(url, function(response){ + self.html(selector ? + $('<div>').html(response.replace(rscript, "")).find(selector) + : response) + success && success.apply(self, arguments) + }) + return this + } + + var escape = encodeURIComponent + + function serialize(params, obj, traditional, scope){ + var array = $.isArray(obj) + $.each(obj, function(key, value) { + if (scope) key = traditional ? scope : scope + '[' + (array ? '' : key) + ']' + // handle data in serializeArray() format + if (!scope && array) params.add(value.name, value.value) + // recurse into nested objects + else if (traditional ? $.isArray(value) : isObject(value)) + serialize(params, value, traditional, key) + else params.add(key, value) + }) + } + + $.param = function(obj, traditional){ + var params = [] + params.add = function(k, v){ this.push(escape(k) + '=' + escape(v)) } + serialize(params, obj, traditional) + return params.join('&').replace(/%20/g, '+') + } +})(Zepto) diff --git a/frontend/gamma/js/Zepto/assets.js b/frontend/gamma/js/Zepto/assets.js new file mode 100644 index 0000000..b5a5712 --- a/dev/null +++ b/frontend/gamma/js/Zepto/assets.js @@ -0,0 +1,21 @@ +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(function($){ + var cache = [], timeout + + $.fn.remove = function(){ + return this.each(function(){ + if(this.parentNode){ + if(this.tagName === 'IMG'){ + cache.push(this) + this.src = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=' + if (timeout) clearTimeout(timeout) + timeout = setTimeout(function(){ cache = [] }, 60000) + } + this.parentNode.removeChild(this) + } + }) + } +})(Zepto) diff --git a/frontend/gamma/js/Zepto/data.js b/frontend/gamma/js/Zepto/data.js new file mode 100644 index 0000000..b4c289f --- a/dev/null +++ b/frontend/gamma/js/Zepto/data.js @@ -0,0 +1,67 @@ +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +// The following code is heavily inspired by jQuery's $.fn.data() + +;(function($) { + var data = {}, dataAttr = $.fn.data, camelize = $.camelCase, + exp = $.expando = 'Zepto' + (+new Date()) + + // Get value from node: + // 1. first try key as given, + // 2. then try camelized key, + // 3. fall back to reading "data-*" attribute. + function getData(node, name) { + var id = node[exp], store = id && data[id] + if (name === undefined) return store || setData(node) + else { + if (store) { + if (name in store) return store[name] + var camelName = camelize(name) + if (camelName in store) return store[camelName] + } + return dataAttr.call($(node), name) + } + } + + // Store value under camelized key on node + function setData(node, name, value) { + var id = node[exp] || (node[exp] = ++$.uuid), + store = data[id] || (data[id] = attributeData(node)) + if (name !== undefined) store[camelize(name)] = value + return store + } + + // Read all "data-*" attributes from a node + function attributeData(node) { + var store = {} + $.each(node.attributes, function(i, attr){ + if (attr.name.indexOf('data-') == 0) + store[camelize(attr.name.replace('data-', ''))] = + $.zepto.deserializeValue(attr.value) + }) + return store + } + + $.fn.data = function(name, value) { + return value === undefined ? + // set multiple values via object + $.isPlainObject(name) ? + this.each(function(i, node){ + $.each(name, function(key, value){ setData(node, key, value) }) + }) : + // get value from first element + this.length == 0 ? undefined : getData(this[0], name) : + // set value on all elements + this.each(function(){ setData(this, name, value) }) + } + + $.fn.removeData = function(names) { + if (typeof names == 'string') names = names.split(/\s+/) + return this.each(function(){ + var id = this[exp], store = id && data[id] + if (store) $.each(names, function(){ delete store[camelize(this)] }) + }) + } +})(Zepto) diff --git a/frontend/gamma/js/Zepto/detect.js b/frontend/gamma/js/Zepto/detect.js new file mode 100644 index 0000000..22c0386 --- a/dev/null +++ b/frontend/gamma/js/Zepto/detect.js @@ -0,0 +1,42 @@ +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(function($){ + function detect(ua){ + var os = this.os = {}, browser = this.browser = {}, + webkit = ua.match(/WebKit\/([\d.]+)/), + android = ua.match(/(Android)\s+([\d.]+)/), + ipad = ua.match(/(iPad).*OS\s([\d_]+)/), + iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/), + webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/), + touchpad = webos && ua.match(/TouchPad/), + kindle = ua.match(/Kindle\/([\d.]+)/), + silk = ua.match(/Silk\/([\d._]+)/), + blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/), + chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/) + + // todo clean this up with a better OS/browser + // separation. we need to discern between multiple + // browsers on android, and decide if kindle fire in + // silk mode is android or not + + if (browser.webkit = !!webkit) browser.version = webkit[1] + + if (android) os.android = true, os.version = android[2] + if (iphone) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.') + if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.') + if (webos) os.webos = true, os.version = webos[2] + if (touchpad) os.touchpad = true + if (blackberry) os.blackberry = true, os.version = blackberry[2] + if (kindle) os.kindle = true, os.version = kindle[1] + if (silk) browser.silk = true, browser.version = silk[1] + if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true + if (chrome) browser.chrome = true, browser.version = chrome[1] + } + + detect.call($, navigator.userAgent) + // make available to unit tests + $.__detect = detect + +})(Zepto) diff --git a/frontend/gamma/js/Zepto/event.js b/frontend/gamma/js/Zepto/event.js new file mode 100644 index 0000000..b40af22 --- a/dev/null +++ b/frontend/gamma/js/Zepto/event.js @@ -0,0 +1,248 @@ +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(function($){ + var $$ = $.zepto.qsa, handlers = {}, _zid = 1, specialEvents={}, + hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' } + + specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents' + + function zid(element) { + return element._zid || (element._zid = _zid++) + } + function findHandlers(element, event, fn, selector) { + event = parse(event) + if (event.ns) var matcher = matcherFor(event.ns) + return (handlers[zid(element)] || []).filter(function(handler) { + return handler + && (!event.e || handler.e == event.e) + && (!event.ns || matcher.test(handler.ns)) + && (!fn || zid(handler.fn) === zid(fn)) + && (!selector || handler.sel == selector) + }) + } + function parse(event) { + var parts = ('' + event).split('.') + return {e: parts[0], ns: parts.slice(1).sort().join(' ')} + } + function matcherFor(ns) { + return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)') + } + + function eachEvent(events, fn, iterator){ + if ($.isObject(events)) $.each(events, iterator) + else events.split(/\s/).forEach(function(type){ iterator(type, fn) }) + } + + function eventCapture(handler, captureSetting) { + return handler.del && + (handler.e == 'focus' || handler.e == 'blur') || + !!captureSetting + } + + function realEvent(type) { + return hover[type] || type + } + + function add(element, events, fn, selector, getDelegate, capture){ + var id = zid(element), set = (handlers[id] || (handlers[id] = [])) + eachEvent(events, fn, function(event, fn){ + var handler = parse(event) + handler.fn = fn + handler.sel = selector + // emulate mouseenter, mouseleave + if (handler.e in hover) fn = function(e){ + var related = e.relatedTarget + if (!related || (related !== this && !$.contains(this, related))) + return handler.fn.apply(this, arguments) + } + handler.del = getDelegate && getDelegate(fn, event) + var callback = handler.del || fn + handler.proxy = function (e) { + var result = callback.apply(element, [e].concat(e.data)) + if (result === false) e.preventDefault(), e.stopPropagation() + return result + } + handler.i = set.length + set.push(handler) + element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + } + function remove(element, events, fn, selector, capture){ + var id = zid(element) + eachEvent(events || '', fn, function(event, fn){ + findHandlers(element, event, fn, selector).forEach(function(handler){ + delete handlers[id][handler.i] + element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + }) + } + + $.event = { add: add, remove: remove } + + $.proxy = function(fn, context) { + if ($.isFunction(fn)) { + var proxyFn = function(){ return fn.apply(context, arguments) } + proxyFn._zid = zid(fn) + return proxyFn + } else if (typeof context == 'string') { + return $.proxy(fn[context], fn) + } else { + throw new TypeError("expected function") + } + } + + $.fn.bind = function(event, callback){ + return this.each(function(){ + add(this, event, callback) + }) + } + $.fn.unbind = function(event, callback){ + return this.each(function(){ + remove(this, event, callback) + }) + } + $.fn.one = function(event, callback){ + return this.each(function(i, element){ + add(this, event, callback, null, function(fn, type){ + return function(){ + var result = fn.apply(element, arguments) + remove(element, type, fn) + return result + } + }) + }) + } + + var returnTrue = function(){return true}, + returnFalse = function(){return false}, + ignoreProperties = /^([A-Z]|layer[XY]$)/, + eventMethods = { + preventDefault: 'isDefaultPrevented', + stopImmediatePropagation: 'isImmediatePropagationStopped', + stopPropagation: 'isPropagationStopped' + } + function createProxy(event) { + var key, proxy = { originalEvent: event } + for (key in event) + if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key] + + $.each(eventMethods, function(name, predicate) { + proxy[name] = function(){ + this[predicate] = returnTrue + return event[name].apply(event, arguments) + } + proxy[predicate] = returnFalse + }) + return proxy + } + + // emulates the 'defaultPrevented' property for browsers that have none + function fix(event) { + if (!('defaultPrevented' in event)) { + event.defaultPrevented = false + var prevent = event.preventDefault + event.preventDefault = function() { + this.defaultPrevented = true + prevent.call(this) + } + } + } + + $.fn.delegate = function(selector, event, callback){ + return this.each(function(i, element){ + add(element, event, callback, selector, function(fn){ + return function(e){ + var evt, match = $(e.target).closest(selector, element).get(0) + if (match) { + evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element}) + return fn.apply(match, [evt].concat([].slice.call(arguments, 1))) + } + } + }) + }) + } + $.fn.undelegate = function(selector, event, callback){ + return this.each(function(){ + remove(this, event, callback, selector) + }) + } + + $.fn.live = function(event, callback){ + $(document.body).delegate(this.selector, event, callback) + return this + } + $.fn.die = function(event, callback){ + $(document.body).undelegate(this.selector, event, callback) + return this + } + + $.fn.on = function(event, selector, callback){ + return !selector || $.isFunction(selector) ? + this.bind(event, selector || callback) : this.delegate(selector, event, callback) + } + $.fn.off = function(event, selector, callback){ + return !selector || $.isFunction(selector) ? + this.unbind(event, selector || callback) : this.undelegate(selector, event, callback) + } + + $.fn.trigger = function(event, data){ + if (typeof event == 'string' || $.isPlainObject(event)) event = $.Event(event) + fix(event) + event.data = data + return this.each(function(){ + // items in the collection might not be DOM elements + // (todo: possibly support events on plain old objects) + if('dispatchEvent' in this) this.dispatchEvent(event) + }) + } + + // triggers event handlers on current element just as if an event occurred, + // doesn't trigger an actual event, doesn't bubble + $.fn.triggerHandler = function(event, data){ + var e, result + this.each(function(i, element){ + e = createProxy(typeof event == 'string' ? $.Event(event) : event) + e.data = data + e.target = element + $.each(findHandlers(element, event.type || event), function(i, handler){ + result = handler.proxy(e) + if (e.isImmediatePropagationStopped()) return false + }) + }) + return result + } + + // shortcut methods for `.bind(event, fn)` for each event type + ;('focusin focusout load resize scroll unload click dblclick '+ + 'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+ + 'change select keydown keypress keyup error').split(' ').forEach(function(event) { + $.fn[event] = function(callback) { + return callback ? + this.bind(event, callback) : + this.trigger(event) + } + }) + + ;['focus', 'blur'].forEach(function(name) { + $.fn[name] = function(callback) { + if (callback) this.bind(name, callback) + else this.each(function(){ + try { this[name]() } + catch(e) {} + }) + return this + } + }) + + $.Event = function(type, props) { + if (typeof type != 'string') props = type, type = props.type + var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true + if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name]) + event.initEvent(type, bubbles, true, null, null, null, null, null, null, null, null, null, null, null, null) + event.isDefaultPrevented = function(){ return this.defaultPrevented } + return event + } + +})(Zepto) diff --git a/frontend/gamma/js/Zepto/form.js b/frontend/gamma/js/Zepto/form.js new file mode 100644 index 0000000..4d562a6 --- a/dev/null +++ b/frontend/gamma/js/Zepto/form.js @@ -0,0 +1,40 @@ +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(function ($) { + $.fn.serializeArray = function () { + var result = [], el + $( Array.prototype.slice.call(this.get(0).elements) ).each(function () { + el = $(this) + var type = el.attr('type') + if (this.nodeName.toLowerCase() != 'fieldset' && + !this.disabled && type != 'submit' && type != 'reset' && type != 'button' && + ((type != 'radio' && type != 'checkbox') || this.checked)) + result.push({ + name: el.attr('name'), + value: el.val() + }) + }) + return result + } + + $.fn.serialize = function () { + var result = [] + this.serializeArray().forEach(function (elm) { + result.push( encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value) ) + }) + return result.join('&') + } + + $.fn.submit = function (callback) { + if (callback) this.bind('submit', callback) + else if (this.length) { + var event = $.Event('submit') + this.eq(0).trigger(event) + if (!event.defaultPrevented) this.get(0).submit() + } + return this + } + +})(Zepto) diff --git a/frontend/gamma/js/Zepto/fx.js b/frontend/gamma/js/Zepto/fx.js new file mode 100644 index 0000000..575449a --- a/dev/null +++ b/frontend/gamma/js/Zepto/fx.js @@ -0,0 +1,102 @@ +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(function($, undefined){ + var prefix = '', eventPrefix, endEventName, endAnimationName, + vendors = { Webkit: 'webkit', Moz: '', O: 'o', ms: 'MS' }, + document = window.document, testEl = document.createElement('div'), + supportedTransforms = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i, + transform, + transitionProperty, transitionDuration, transitionTiming, + animationName, animationDuration, animationTiming, + cssReset = {} + + function dasherize(str) { return downcase(str.replace(/([a-z])([A-Z])/, '$1-$2')) } + function downcase(str) { return str.toLowerCase() } + function normalizeEvent(name) { return eventPrefix ? eventPrefix + name : downcase(name) } + + $.each(vendors, function(vendor, event){ + if (testEl.style[vendor + 'TransitionProperty'] !== undefined) { + prefix = '-' + downcase(vendor) + '-' + eventPrefix = event + return false + } + }) + + transform = prefix + 'transform' + cssReset[transitionProperty = prefix + 'transition-property'] = + cssReset[transitionDuration = prefix + 'transition-duration'] = + cssReset[transitionTiming = prefix + 'transition-timing-function'] = + cssReset[animationName = prefix + 'animation-name'] = + cssReset[animationDuration = prefix + 'animation-duration'] = + cssReset[animationTiming = prefix + 'animation-timing-function'] = '' + + $.fx = { + off: (eventPrefix === undefined && testEl.style.transitionProperty === undefined), + speeds: { _default: 400, fast: 200, slow: 600 }, + cssPrefix: prefix, + transitionEnd: normalizeEvent('TransitionEnd'), + animationEnd: normalizeEvent('AnimationEnd') + } + + $.fn.animate = function(properties, duration, ease, callback){ + if ($.isObject(duration)) + ease = duration.easing, callback = duration.complete, duration = duration.duration + if (duration) duration = (typeof duration == 'number' ? duration : + ($.fx.speeds[duration] || $.fx.speeds._default)) / 1000 + return this.anim(properties, duration, ease, callback) + } + + $.fn.anim = function(properties, duration, ease, callback){ + var key, cssValues = {}, cssProperties, transforms = '', + that = this, wrappedCallback, endEvent = $.fx.transitionEnd + + if (duration === undefined) duration = 0.4 + if ($.fx.off) duration = 0 + + if (typeof properties == 'string') { + // keyframe animation + cssValues[animationName] = properties + cssValues[animationDuration] = duration + 's' + cssValues[animationTiming] = (ease || 'linear') + endEvent = $.fx.animationEnd + } else { + cssProperties = [] + // CSS transitions + for (key in properties) + if (supportedTransforms.test(key)) transforms += key + '(' + properties[key] + ') ' + else cssValues[key] = properties[key], cssProperties.push(dasherize(key)) + + if (transforms) cssValues[transform] = transforms, cssProperties.push(transform) + if (duration > 0 && typeof properties === 'object') { + cssValues[transitionProperty] = cssProperties.join(', ') + cssValues[transitionDuration] = duration + 's' + cssValues[transitionTiming] = (ease || 'linear') + } + } + + wrappedCallback = function(event){ + if (typeof event !== 'undefined') { + if (event.target !== event.currentTarget) return // makes sure the event didn't bubble from "below" + $(event.target).unbind(endEvent, arguments.callee) + } + $(this).css(cssReset) + callback && callback.call(this) + } + if (duration > 0) this.bind(endEvent, wrappedCallback) + + // trigger page reflow so new elements can animate + this.size() && this.get(0).clientLeft + + this.css(cssValues) + + if (duration <= 0) setTimeout(function() { + that.each(function(){ wrappedCallback.call(this) }) + }, 0) + + return this + } + + testEl = null +})(Zepto) diff --git a/frontend/gamma/js/Zepto/fx_methods.js b/frontend/gamma/js/Zepto/fx_methods.js new file mode 100644 index 0000000..23daf6e --- a/dev/null +++ b/frontend/gamma/js/Zepto/fx_methods.js @@ -0,0 +1,71 @@ +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(function($, undefined){ + var document = window.document, docElem = document.documentElement, + origShow = $.fn.show, origHide = $.fn.hide, origToggle = $.fn.toggle + + function anim(el, speed, opacity, scale, callback) { + if (typeof speed == 'function' && !callback) callback = speed, speed = undefined + var props = { opacity: opacity } + if (scale) { + props.scale = scale + el.css($.fx.cssPrefix + 'transform-origin', '0 0') + } + return el.animate(props, speed, null, callback) + } + + function hide(el, speed, scale, callback) { + return anim(el, speed, 0, scale, function(){ + origHide.call($(this)) + callback && callback.call(this) + }) + } + + $.fn.show = function(speed, callback) { + origShow.call(this) + if (speed === undefined) speed = 0 + else this.css('opacity', 0) + return anim(this, speed, 1, '1,1', callback) + } + + $.fn.hide = function(speed, callback) { + if (speed === undefined) return origHide.call(this) + else return hide(this, speed, '0,0', callback) + } + + $.fn.toggle = function(speed, callback) { + if (speed === undefined || typeof speed == 'boolean') + return origToggle.call(this, speed) + else return this.each(function(){ + var el = $(this) + el[el.css('display') == 'none' ? 'show' : 'hide'](speed, callback) + }) + } + + $.fn.fadeTo = function(speed, opacity, callback) { + return anim(this, speed, opacity, null, callback) + } + + $.fn.fadeIn = function(speed, callback) { + var target = this.css('opacity') + if (target > 0) this.css('opacity', 0) + else target = 1 + return origShow.call(this).fadeTo(speed, target, callback) + } + + $.fn.fadeOut = function(speed, callback) { + return hide(this, speed, null, callback) + } + + $.fn.fadeToggle = function(speed, callback) { + return this.each(function(){ + var el = $(this) + el[ + (el.css('opacity') == 0 || el.css('display') == 'none') ? 'fadeIn' : 'fadeOut' + ](speed, callback) + }) + } + +})(Zepto) diff --git a/frontend/gamma/js/Zepto/gesture.js b/frontend/gamma/js/Zepto/gesture.js new file mode 100644 index 0000000..035455b --- a/dev/null +++ b/frontend/gamma/js/Zepto/gesture.js @@ -0,0 +1,35 @@ +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(function($){ + if ($.os.ios) { + var gesture = {}, gestureTimeout + + function parentIfText(node){ + return 'tagName' in node ? node : node.parentNode + } + + $(document).bind('gesturestart', function(e){ + var now = Date.now(), delta = now - (gesture.last || now) + gesture.target = parentIfText(e.target) + gestureTimeout && clearTimeout(gestureTimeout) + gesture.e1 = e.scale + gesture.last = now + }).bind('gesturechange', function(e){ + gesture.e2 = e.scale + }).bind('gestureend', function(e){ + if (gesture.e2 > 0) { + Math.abs(gesture.e1 - gesture.e2) != 0 && $(gesture.target).trigger('pinch') && + $(gesture.target).trigger('pinch' + (gesture.e1 - gesture.e2 > 0 ? 'In' : 'Out')) + gesture.e1 = gesture.e2 = gesture.last = 0 + } else if ('last' in gesture) { + gesture = {} + } + }) + + ;['pinch', 'pinchIn', 'pinchOut'].forEach(function(m){ + $.fn[m] = function(callback){ return this.bind(m, callback) } + }) + } +})(Zepto) diff --git a/frontend/gamma/js/Zepto/polyfill.js b/frontend/gamma/js/Zepto/polyfill.js new file mode 100644 index 0000000..933d1f8 --- a/dev/null +++ b/frontend/gamma/js/Zepto/polyfill.js @@ -0,0 +1,36 @@ +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(function(undefined){ + if (String.prototype.trim === undefined) // fix for iOS 3.2 + String.prototype.trim = function(){ return this.replace(/^\s+/, '').replace(/\s+$/, '') } + + // For iOS 3.x + // from https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/reduce + if (Array.prototype.reduce === undefined) + Array.prototype.reduce = function(fun){ + if(this === void 0 || this === null) throw new TypeError() + var t = Object(this), len = t.length >>> 0, k = 0, accumulator + if(typeof fun != 'function') throw new TypeError() + if(len == 0 && arguments.length == 1) throw new TypeError() + + if(arguments.length >= 2) + accumulator = arguments[1] + else + do{ + if(k in t){ + accumulator = t[k++] + break + } + if(++k >= len) throw new TypeError() + } while (true) + + while (k < len){ + if(k in t) accumulator = fun.call(undefined, accumulator, t[k], k, t) + k++ + } + return accumulator + } + +})() diff --git a/frontend/gamma/js/Zepto/selector.js b/frontend/gamma/js/Zepto/selector.js new file mode 100644 index 0000000..c0b035a --- a/dev/null +++ b/frontend/gamma/js/Zepto/selector.js @@ -0,0 +1,81 @@ +;(function($){ + var zepto = $.zepto, oldQsa = zepto.qsa, oldMatches = zepto.matches + + function visible(elem){ + elem = $(elem) + return !!(elem.width() || elem.height()) && elem.css("display") !== "none" + } + + // Implements a subset from: + // http://api.jquery.com/category/selectors/jquery-selector-extensions/ + // + // Each filter function receives the current index, all nodes in the + // considered set, and a value if there were parentheses. The value + // of `this` is the node currently being considered. The function returns the + // resulting node(s), null, or undefined. + // + // Complex selectors are not supported: + // li:has(label:contains("foo")) + li:has(label:contains("bar")) + // ul.inner:first > li + var filters = $.expr[':'] = { + visible: function(){ if (visible(this)) return this }, + hidden: function(){ if (!visible(this)) return this }, + selected: function(){ if (this.selected) return this }, + checked: function(){ if (this.checked) return this }, + parent: function(){ return this.parentNode }, + first: function(idx){ if (idx === 0) return this }, + last: function(idx, nodes){ if (idx === nodes.length - 1) return this }, + eq: function(idx, _, value){ if (idx === value) return this }, + contains: function(idx, _, text){ if ($(this).text().indexOf(text) > -1) return this }, + has: function(idx, _, sel){ if (zepto.qsa(this, sel).length) return this } + } + + var filterRe = new RegExp('(.*):(\\w+)(?:\\(([^)]+)\\))?$\\s*'), + childRe = /^\s*>/, + classTag = 'Zepto' + (+new Date()) + + function process(sel, fn) { + // quote the hash in `a[href^=#]` expression + sel = sel.replace(/=#\]/g, '="#"]') + var filter, arg, match = filterRe.exec(sel) + if (match && match[2] in filters) { + var filter = filters[match[2]], arg = match[3] + sel = match[1] + if (arg) { + var num = Number(arg) + if (isNaN(num)) arg = arg.replace(/^["']|["']$/g, '') + else arg = num + } + } + return fn(sel, filter, arg) + } + + zepto.qsa = function(node, selector) { + return process(selector, function(sel, filter, arg){ + try { + var taggedParent + if (!sel && filter) sel = '*' + else if (childRe.test(sel)) + // support "> *" child queries by tagging the parent node with a + // unique class and prepending that classname onto the selector + taggedParent = $(node).addClass(classTag), sel = '.'+classTag+' '+sel + + var nodes = oldQsa(node, sel) + } catch(e) { + console.error('error performing selector: %o', selector) + throw e + } finally { + if (taggedParent) taggedParent.removeClass(classTag) + } + return !filter ? nodes : + zepto.uniq($.map(nodes, function(n, i){ return filter.call(n, i, nodes, arg) })) + }) + } + + zepto.matches = function(node, selector){ + return process(selector, function(sel, filter, arg){ + return (!sel || oldMatches(node, sel)) && + (!filter || filter.call(node, null, arg) === node) + }) + } +})(Zepto) diff --git a/frontend/gamma/js/Zepto/stack.js b/frontend/gamma/js/Zepto/stack.js new file mode 100644 index 0000000..c995285 --- a/dev/null +++ b/frontend/gamma/js/Zepto/stack.js @@ -0,0 +1,22 @@ +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(function($){ + $.fn.end = function(){ + return this.prevObject || $() + } + + $.fn.andSelf = function(){ + return this.add(this.prevObject || $()) + } + + 'filter,add,not,eq,first,last,find,closest,parents,parent,children,siblings'.split(',').forEach(function(property){ + var fn = $.fn[property] + $.fn[property] = function(){ + var ret = fn.apply(this, arguments) + ret.prevObject = this + return ret + } + }) +})(Zepto) diff --git a/frontend/gamma/js/Zepto/touch.js b/frontend/gamma/js/Zepto/touch.js new file mode 100644 index 0000000..af109b9 --- a/dev/null +++ b/frontend/gamma/js/Zepto/touch.js @@ -0,0 +1,113 @@ +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(function($){ + var touch = {}, + touchTimeout, tapTimeout, swipeTimeout, + longTapDelay = 750, longTapTimeout + + function parentIfText(node) { + return 'tagName' in node ? node : node.parentNode + } + + function swipeDirection(x1, x2, y1, y2) { + var xDelta = Math.abs(x1 - x2), yDelta = Math.abs(y1 - y2) + return xDelta >= yDelta ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down') + } + + function longTap() { + longTapTimeout = null + if (touch.last) { + touch.el.trigger('longTap') + touch = {} + } + } + + function cancelLongTap() { + if (longTapTimeout) clearTimeout(longTapTimeout) + longTapTimeout = null + } + + function cancelAll() { + if (touchTimeout) clearTimeout(touchTimeout) + if (tapTimeout) clearTimeout(tapTimeout) + if (swipeTimeout) clearTimeout(swipeTimeout) + if (longTapTimeout) clearTimeout(longTapTimeout) + touchTimeout = tapTimeout = swipeTimeout = longTapTimeout = null + touch = {} + } + + $(document).ready(function(){ + var now, delta + + $(document.body) + .bind('touchstart', function(e){ + now = Date.now() + delta = now - (touch.last || now) + touch.el = $(parentIfText(e.touches[0].target)) + touchTimeout && clearTimeout(touchTimeout) + touch.x1 = e.touches[0].pageX + touch.y1 = e.touches[0].pageY + if (delta > 0 && delta <= 250) touch.isDoubleTap = true + touch.last = now + longTapTimeout = setTimeout(longTap, longTapDelay) + }) + .bind('touchmove', function(e){ + cancelLongTap() + touch.x2 = e.touches[0].pageX + touch.y2 = e.touches[0].pageY + }) + .bind('touchend', function(e){ + cancelLongTap() + + // swipe + if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) || + (touch.y2 && Math.abs(touch.y1 - touch.y2) > 30)) + + swipeTimeout = setTimeout(function() { + touch.el.trigger('swipe') + touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2))) + touch = {} + }, 0) + + // normal tap + else if ('last' in touch) + + // delay by one tick so we can cancel the 'tap' event if 'scroll' fires + // ('tap' fires before 'scroll') + tapTimeout = setTimeout(function() { + + // trigger universal 'tap' with the option to cancelTouch() + // (cancelTouch cancels processing of single vs double taps for faster 'tap' response) + var event = $.Event('tap') + event.cancelTouch = cancelAll + touch.el.trigger(event) + + // trigger double tap immediately + if (touch.isDoubleTap) { + touch.el.trigger('doubleTap') + touch = {} + } + + // trigger single tap after 250ms of inactivity + else { + touchTimeout = setTimeout(function(){ + touchTimeout = null + touch.el.trigger('singleTap') + touch = {} + }, 250) + } + + }, 0) + + }) + .bind('touchcancel', cancelAll) + + $(window).bind('scroll', cancelAll) + }) + + ;['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(m){ + $.fn[m] = function(callback){ return this.bind(m, callback) } + }) +})(Zepto) diff --git a/frontend/gamma/js/Zepto/zepto.js b/frontend/gamma/js/Zepto/zepto.js new file mode 100644 index 0000000..e67b3a2 --- a/dev/null +++ b/frontend/gamma/js/Zepto/zepto.js @@ -0,0 +1,751 @@ +// Zepto.js +// (c) 2010-2012 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +var Zepto = (function() { + var undefined, key, $, classList, emptyArray = [], slice = emptyArray.slice, filter = emptyArray.filter, + document = window.document, + elementDisplay = {}, classCache = {}, + getComputedStyle = document.defaultView.getComputedStyle, + cssNumber = { 'column-count': 1, 'columns': 1, 'font-weight': 1, 'line-height': 1,'opacity': 1, 'z-index': 1, 'zoom': 1 }, + fragmentRE = /^\s*<(\w+|!)[^>]*>/, + tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rootNodeRE = /^(?:body|html)$/i, + + // special attributes that should be get/set via method calls + methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'], + + adjacencyOperators = [ 'after', 'prepend', 'before', 'append' ], + table = document.createElement('table'), + tableRow = document.createElement('tr'), + containers = { + 'tr': document.createElement('tbody'), + 'tbody': table, 'thead': table, 'tfoot': table, + 'td': tableRow, 'th': tableRow, + '*': document.createElement('div') + }, + readyRE = /complete|loaded|interactive/, + classSelectorRE = /^\.([\w-]+)$/, + idSelectorRE = /^#([\w-]*)$/, + tagSelectorRE = /^[\w-]+$/, + toString = {}.toString, + zepto = {}, + camelize, uniq, + tempParent = document.createElement('div') + + zepto.matches = function(element, selector) { + if (!element || element.nodeType !== 1) return false + var matchesSelector = element.webkitMatchesSelector || element.mozMatchesSelector || + element.oMatchesSelector || element.matchesSelector + if (matchesSelector) return matchesSelector.call(element, selector) + // fall back to performing a selector: + var match, parent = element.parentNode, temp = !parent + if (temp) (parent = tempParent).appendChild(element) + match = ~zepto.qsa(parent, selector).indexOf(element) + temp && tempParent.removeChild(element) + return match + } + + function isFunction(value) { return toString.call(value) == "[object Function]" } + function isObject(value) { return value instanceof Object } + function isPlainObject(value) { + return isObject(value) && value != window && value.__proto__ == Object.prototype + } + function isArray(value) { return value instanceof Array } + function likeArray(obj) { return typeof obj.length == 'number' } + + function compact(array) { return filter.call(array, function(item){ return item != null }) } + function flatten(array) { return array.length > 0 ? $.fn.concat.apply([], array) : array } + camelize = function(str){ return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) } + function dasherize(str) { + return str.replace(/::/g, '/') + .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') + .replace(/([a-z\d])([A-Z])/g, '$1_$2') + .replace(/_/g, '-') + .toLowerCase() + } + uniq = function(array){ return filter.call(array, function(item, idx){ return array.indexOf(item) == idx }) } + + function classRE(name) { + return name in classCache ? + classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)')) + } + + function maybeAddPx(name, value) { + return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value + } + + function defaultDisplay(nodeName) { + var element, display + if (!elementDisplay[nodeName]) { + element = document.createElement(nodeName) + document.body.appendChild(element) + display = getComputedStyle(element, '').getPropertyValue("display") + element.parentNode.removeChild(element) + display == "none" && (display = "block") + elementDisplay[nodeName] = display + } + return elementDisplay[nodeName] + } + + function children(element) { + return 'children' in element ? + slice.call(element.children) : + $.map(element.childNodes, function(node){ if (node.nodeType == 1) return node }) + } + + // `$.zepto.fragment` takes a html string and an optional tag name + // to generate DOM nodes nodes from the given html string. + // The generated DOM nodes are returned as an array. + // This function can be overriden in plugins for example to make + // it compatible with browsers that don't support the DOM fully. + zepto.fragment = function(html, name, properties) { + if (html.replace) html = html.replace(tagExpanderRE, "<$1></$2>") + if (name === undefined) name = fragmentRE.test(html) && RegExp.$1 + if (!(name in containers)) name = '*' + + var nodes, dom, container = containers[name] + container.innerHTML = '' + html + dom = $.each(slice.call(container.childNodes), function(){ + container.removeChild(this) + }) + if (isPlainObject(properties)) { + nodes = $(dom) + $.each(properties, function(key, value) { + if (methodAttributes.indexOf(key) > -1) nodes[key](value) + else nodes.attr(key, value) + }) + } + return dom + } + + // `$.zepto.Z` swaps out the prototype of the given `dom` array + // of nodes with `$.fn` and thus supplying all the Zepto functions + // to the array. Note that `__proto__` is not supported on Internet + // Explorer. This method can be overriden in plugins. + zepto.Z = function(dom, selector) { + dom = dom || [] + dom.__proto__ = arguments.callee.prototype + dom.selector = selector || '' + return dom + } + + // `$.zepto.isZ` should return `true` if the given object is a Zepto + // collection. This method can be overriden in plugins. + zepto.isZ = function(object) { + return object instanceof zepto.Z + } + + // `$.zepto.init` is Zepto's counterpart to jQuery's `$.fn.init` and + // takes a CSS selector and an optional context (and handles various + // special cases). + // This method can be overriden in plugins. + zepto.init = function(selector, context) { + // If nothing given, return an empty Zepto collection + if (!selector) return zepto.Z() + // If a function is given, call it when the DOM is ready + else if (isFunction(selector)) return $(document).ready(selector) + // If a Zepto collection is given, juts return it + else if (zepto.isZ(selector)) return selector + else { + var dom + // normalize array if an array of nodes is given + if (isArray(selector)) dom = compact(selector) + // Wrap DOM nodes. If a plain object is given, duplicate it. + else if (isObject(selector)) + dom = [isPlainObject(selector) ? $.extend({}, selector) : selector], selector = null + // If it's a html fragment, create nodes from it + else if (fragmentRE.test(selector)) + dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) return $(context).find(selector) + // And last but no least, if it's a CSS selector, use it to select nodes. + else dom = zepto.qsa(document, selector) + // create a new Zepto collection from the nodes found + return zepto.Z(dom, selector) + } + } + + // `$` will be the base `Zepto` object. When calling this + // function just call `$.zepto.init, which makes the implementation + // details of selecting nodes and creating Zepto collections + // patchable in plugins. + $ = function(selector, context){ + return zepto.init(selector, context) + } + + function extend(target, source, deep) { + for (key in source) + if (deep && isPlainObject(source[key])) { + if (!isPlainObject(target[key])) target[key] = {} + extend(target[key], source[key], deep) + } + else if (source[key] !== undefined) target[key] = source[key] + } + + // Copy all but undefined properties from one or more + // objects to the `target` object. + $.extend = function(target){ + var deep, args = slice.call(arguments, 1) + if (typeof target == 'boolean') { + deep = target + target = args.shift() + } + args.forEach(function(arg){ extend(target, arg, deep) }) + return target + } + + // `$.zepto.qsa` is Zepto's CSS selector implementation which + // uses `document.querySelectorAll` and optimizes for some special cases, like `#id`. + // This method can be overriden in plugins. + zepto.qsa = function(element, selector){ + var found + return (element === document && idSelectorRE.test(selector)) ? + ( (found = element.getElementById(RegExp.$1)) ? [found] : [] ) : + (element.nodeType !== 1 && element.nodeType !== 9) ? [] : + slice.call( + classSelectorRE.test(selector) ? element.getElementsByClassName(RegExp.$1) : + tagSelectorRE.test(selector) ? element.getElementsByTagName(selector) : + element.querySelectorAll(selector) + ) + } + + function filtered(nodes, selector) { + return selector === undefined ? $(nodes) : $(nodes).filter(selector) + } + + $.contains = function(parent, node) { + return parent !== node && parent.contains(node) + } + + function funcArg(context, arg, idx, payload) { + return isFunction(arg) ? arg.call(context, idx, payload) : arg + } + + function setAttribute(node, name, value) { + value == null ? node.removeAttribute(name) : node.setAttribute(name, value) + } + + // access className property while respecting SVGAnimatedString + function className(node, value){ + var klass = node.className, + svg = klass && klass.baseVal !== undefined + + if (value === undefined) return svg ? klass.baseVal : klass + svg ? (klass.baseVal = value) : (node.className = value) + } + + // "true" => true + // "false" => false + // "null" => null + // "42" => 42 + // "42.5" => 42.5 + // JSON => parse if valid + // String => self + function deserializeValue(value) { + var num + try { + return value ? + value == "true" || + ( value == "false" ? false : + value == "null" ? null : + !isNaN(num = Number(value)) ? num : + /^[\[\{]/.test(value) ? $.parseJSON(value) : + value ) + : value + } catch(e) { + return value + } + } + + $.isFunction = isFunction + $.isObject = isObject + $.isArray = isArray + $.isPlainObject = isPlainObject + + $.inArray = function(elem, array, i){ + return emptyArray.indexOf.call(array, elem, i) + } + + $.camelCase = camelize + $.trim = function(str) { return str.trim() } + + // plugin compatibility + $.uuid = 0 + $.support = { } + $.expr = { } + + $.map = function(elements, callback){ + var value, values = [], i, key + if (likeArray(elements)) + for (i = 0; i < elements.length; i++) { + value = callback(elements[i], i) + if (value != null) values.push(value) + } + else + for (key in elements) { + value = callback(elements[key], key) + if (value != null) values.push(value) + } + return flatten(values) + } + + $.each = function(elements, callback){ + var i, key + if (likeArray(elements)) { + for (i = 0; i < elements.length; i++) + if (callback.call(elements[i], i, elements[i]) === false) return elements + } else { + for (key in elements) + if (callback.call(elements[key], key, elements[key]) === false) return elements + } + + return elements + } + + $.grep = function(elements, callback){ + return filter.call(elements, callback) + } + + if (window.JSON) $.parseJSON = JSON.parse + + // Define methods that will be available on all + // Zepto collections + $.fn = { + // Because a collection acts like an array + // copy over these useful array functions. + forEach: emptyArray.forEach, + reduce: emptyArray.reduce, + push: emptyArray.push, + sort: emptyArray.sort, + indexOf: emptyArray.indexOf, + concat: emptyArray.concat, + + // `map` and `slice` in the jQuery API work differently + // from their array counterparts + map: function(fn){ + return $($.map(this, function(el, i){ return fn.call(el, i, el) })) + }, + slice: function(){ + return $(slice.apply(this, arguments)) + }, + + ready: function(callback){ + if (readyRE.test(document.readyState)) callback($) + else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false) + return this + }, + get: function(idx){ + return idx === undefined ? slice.call(this) : this[idx] + }, + toArray: function(){ return this.get() }, + size: function(){ + return this.length + }, + remove: function(){ + return this.each(function(){ + if (this.parentNode != null) + this.parentNode.removeChild(this) + }) + }, + each: function(callback){ + emptyArray.every.call(this, function(el, idx){ + return callback.call(el, idx, el) !== false + }) + return this + }, + filter: function(selector){ + if (isFunction(selector)) return this.not(this.not(selector)) + return $(filter.call(this, function(element){ + return zepto.matches(element, selector) + })) + }, + add: function(selector,context){ + return $(uniq(this.concat($(selector,context)))) + }, + is: function(selector){ + return this.length > 0 && zepto.matches(this[0], selector) + }, + not: function(selector){ + var nodes=[] + if (isFunction(selector) && selector.call !== undefined) + this.each(function(idx){ + if (!selector.call(this,idx)) nodes.push(this) + }) + else { + var excludes = typeof selector == 'string' ? this.filter(selector) : + (likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector) + this.forEach(function(el){ + if (excludes.indexOf(el) < 0) nodes.push(el) + }) + } + return $(nodes) + }, + has: function(selector){ + return this.filter(function(){ + return isObject(selector) ? + $.contains(this, selector) : + $(this).find(selector).size() + }) + }, + eq: function(idx){ + return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1) + }, + first: function(){ + var el = this[0] + return el && !isObject(el) ? el : $(el) + }, + last: function(){ + var el = this[this.length - 1] + return el && !isObject(el) ? el : $(el) + }, + find: function(selector){ + var result + if (this.length == 1) result = $(zepto.qsa(this[0], selector)) + else result = this.map(function(){ return zepto.qsa(this, selector) }) + return result + }, + closest: function(selector, context){ + var node = this[0] + while (node && !zepto.matches(node, selector)) + node = node !== context && node !== document && node.parentNode + return $(node) + }, + parents: function(selector){ + var ancestors = [], nodes = this + while (nodes.length > 0) + nodes = $.map(nodes, function(node){ + if ((node = node.parentNode) && node !== document && ancestors.indexOf(node) < 0) { + ancestors.push(node) + return node + } + }) + return filtered(ancestors, selector) + }, + parent: function(selector){ + return filtered(uniq(this.pluck('parentNode')), selector) + }, + children: function(selector){ + return filtered(this.map(function(){ return children(this) }), selector) + }, + contents: function() { + return this.map(function() { return slice.call(this.childNodes) }) + }, + siblings: function(selector){ + return filtered(this.map(function(i, el){ + return filter.call(children(el.parentNode), function(child){ return child!==el }) + }), selector) + }, + empty: function(){ + return this.each(function(){ this.innerHTML = '' }) + }, + // `pluck` is borrowed from Prototype.js + pluck: function(property){ + return $.map(this, function(el){ return el[property] }) + }, + show: function(){ + return this.each(function(){ + this.style.display == "none" && (this.style.display = null) + if (getComputedStyle(this, '').getPropertyValue("display") == "none") + this.style.display = defaultDisplay(this.nodeName) + }) + }, + replaceWith: function(newContent){ + return this.before(newContent).remove() + }, + wrap: function(structure){ + var func = isFunction(structure) + if (this[0] && !func) + var dom = $(structure).get(0), + clone = dom.parentNode || this.length > 1 + + return this.each(function(index){ + $(this).wrapAll( + func ? structure.call(this, index) : + clone ? dom.cloneNode(true) : dom + ) + }) + }, + wrapAll: function(structure){ + if (this[0]) { + $(this[0]).before(structure = $(structure)) + var children + // drill down to the inmost element + while ((children = structure.children()).length) structure = children.first() + $(structure).append(this) + } + return this + }, + wrapInner: function(structure){ + var func = isFunction(structure) + return this.each(function(index){ + var self = $(this), contents = self.contents(), + dom = func ? structure.call(this, index) : structure + contents.length ? contents.wrapAll(dom) : self.append(dom) + }) + }, + unwrap: function(){ + this.parent().each(function(){ + $(this).replaceWith($(this).children()) + }) + return this + }, + clone: function(){ + return this.map(function(){ return this.cloneNode(true) }) + }, + hide: function(){ + return this.css("display", "none") + }, + toggle: function(setting){ + return this.each(function(){ + var el = $(this) + ;(setting === undefined ? el.css("display") == "none" : setting) ? el.show() : el.hide() + }) + }, + prev: function(selector){ return $(this.pluck('previousElementSibling')).filter(selector || '*') }, + next: function(selector){ return $(this.pluck('nextElementSibling')).filter(selector || '*') }, + html: function(html){ + return html === undefined ? + (this.length > 0 ? this[0].innerHTML : null) : + this.each(function(idx){ + var originHtml = this.innerHTML + $(this).empty().append( funcArg(this, html, idx, originHtml) ) + }) + }, + text: function(text){ + return text === undefined ? + (this.length > 0 ? this[0].textContent : null) : + this.each(function(){ this.textContent = text }) + }, + attr: function(name, value){ + var result + return (typeof name == 'string' && value === undefined) ? + (this.length == 0 || this[0].nodeType !== 1 ? undefined : + (name == 'value' && this[0].nodeName == 'INPUT') ? this.val() : + (!(result = this[0].getAttribute(name)) && name in this[0]) ? this[0][name] : result + ) : + this.each(function(idx){ + if (this.nodeType !== 1) return + if (isObject(name)) for (key in name) setAttribute(this, key, name[key]) + else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name))) + }) + }, + removeAttr: function(name){ + return this.each(function(){ this.nodeType === 1 && setAttribute(this, name) }) + }, + prop: function(name, value){ + return (value === undefined) ? + (this[0] && this[0][name]) : + this.each(function(idx){ + this[name] = funcArg(this, value, idx, this[name]) + }) + }, + data: function(name, value){ + var data = this.attr('data-' + dasherize(name), value) + return data !== null ? deserializeValue(data) : undefined + }, + val: function(value){ + return (value === undefined) ? + (this[0] && (this[0].multiple ? + $(this[0]).find('option').filter(function(o){ return this.selected }).pluck('value') : + this[0].value) + ) : + this.each(function(idx){ + this.value = funcArg(this, value, idx, this.value) + }) + }, + offset: function(coordinates){ + if (coordinates) return this.each(function(index){ + var $this = $(this), + coords = funcArg(this, coordinates, index, $this.offset()), + parentOffset = $this.offsetParent().offset(), + props = { + top: coords.top - parentOffset.top, + left: coords.left - parentOffset.left + } + + if ($this.css('position') == 'static') props['position'] = 'relative' + $this.css(props) + }) + if (this.length==0) return null + var obj = this[0].getBoundingClientRect() + return { + left: obj.left + window.pageXOffset, + top: obj.top + window.pageYOffset, + width: obj.width, + height: obj.height + } + }, + css: function(property, value){ + if (arguments.length < 2 && typeof property == 'string') + return this[0] && (this[0].style[camelize(property)] || getComputedStyle(this[0], '').getPropertyValue(property)) + + var css = '' + for (key in property) + if (!property[key] && property[key] !== 0) + this.each(function(){ this.style.removeProperty(dasherize(key)) }) + else + css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';' + + if (typeof property == 'string') + if (!value && value !== 0) + this.each(function(){ this.style.removeProperty(dasherize(property)) }) + else + css = dasherize(property) + ":" + maybeAddPx(property, value) + + return this.each(function(){ this.style.cssText += ';' + css }) + }, + index: function(element){ + return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0]) + }, + hasClass: function(name){ + return emptyArray.some.call(this, function(el){ + return this.test(className(el)) + }, classRE(name)) + }, + addClass: function(name){ + return this.each(function(idx){ + classList = [] + var cls = className(this), newName = funcArg(this, name, idx, cls) + newName.split(/\s+/g).forEach(function(klass){ + if (!$(this).hasClass(klass)) classList.push(klass) + }, this) + classList.length && className(this, cls + (cls ? " " : "") + classList.join(" ")) + }) + }, + removeClass: function(name){ + return this.each(function(idx){ + if (name === undefined) return className(this, '') + classList = className(this) + funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass){ + classList = classList.replace(classRE(klass), " ") + }) + className(this, classList.trim()) + }) + }, + toggleClass: function(name, when){ + return this.each(function(idx){ + var newName = funcArg(this, name, idx, className(this)) + ;(when === undefined ? !$(this).hasClass(newName) : when) ? + $(this).addClass(newName) : $(this).removeClass(newName) + }) + }, + scrollTop: function(){ + if (!this.length) return + return ('scrollTop' in this[0]) ? this[0].scrollTop : this[0].scrollY + }, + position: function() { + if (!this.length) return + + var elem = this[0], + // Get *real* offsetParent + offsetParent = this.offsetParent(), + // Get correct offsets + offset = this.offset(), + parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset() + + // Subtract element margins + // note: when an element has margin: auto the offsetLeft and marginLeft + // are the same in Safari causing offset.left to incorrectly be 0 + offset.top -= parseFloat( $(elem).css('margin-top') ) || 0 + offset.left -= parseFloat( $(elem).css('margin-left') ) || 0 + + // Add offsetParent borders + parentOffset.top += parseFloat( $(offsetParent[0]).css('border-top-width') ) || 0 + parentOffset.left += parseFloat( $(offsetParent[0]).css('border-left-width') ) || 0 + + // Subtract the two offsets + return { + top: offset.top - parentOffset.top, + left: offset.left - parentOffset.left + } + }, + offsetParent: function() { + return this.map(function(){ + var parent = this.offsetParent || document.body + while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css("position") == "static") + parent = parent.offsetParent + return parent + }) + } + } + + // for now + $.fn.detach = $.fn.remove + + // Generate the `width` and `height` functions + ;['width', 'height'].forEach(function(dimension){ + $.fn[dimension] = function(value){ + var offset, Dimension = dimension.replace(/./, function(m){ return m[0].toUpperCase() }) + if (value === undefined) return this[0] == window ? window['inner' + Dimension] : + this[0] == document ? document.documentElement['offset' + Dimension] : + (offset = this.offset()) && offset[dimension] + else return this.each(function(idx){ + var el = $(this) + el.css(dimension, funcArg(this, value, idx, el[dimension]())) + }) + } + }) + + function traverseNode(node, fun) { + fun(node) + for (var key in node.childNodes) traverseNode(node.childNodes[key], fun) + } + + // Generate the `after`, `prepend`, `before`, `append`, + // `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods. + adjacencyOperators.forEach(function(operator, operatorIndex) { + var inside = operatorIndex % 2 //=> prepend, append + + $.fn[operator] = function(){ + // arguments can be nodes, arrays of nodes, Zepto objects and HTML strings + var nodes = $.map(arguments, function(n){ return isObject(n) ? n : zepto.fragment(n) }), + parent, copyByClone = this.length > 1 + if (nodes.length < 1) return this + + return this.each(function(_, target){ + parent = inside ? target : target.parentNode + + // convert all methods to a "before" operation + target = operatorIndex == 0 ? target.nextSibling : + operatorIndex == 1 ? target.firstChild : + operatorIndex == 2 ? target : + null + + nodes.forEach(function(node){ + if (copyByClone) node = node.cloneNode(true) + else if (!parent) return $(node).remove() + + traverseNode(parent.insertBefore(node, target), function(el){ + if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' && + (!el.type || el.type === 'text/javascript') && !el.src) + window['eval'].call(window, el.innerHTML) + }) + }) + }) + } + + // after => insertAfter + // prepend => prependTo + // before => insertBefore + // append => appendTo + $.fn[inside ? operator+'To' : 'insert'+(operatorIndex ? 'Before' : 'After')] = function(html){ + $(html)[operator](this) + return this + } + }) + + zepto.Z.prototype = $.fn + + // Export internal API functions in the `$.zepto` namespace + zepto.uniq = uniq + zepto.deserializeValue = deserializeValue + $.zepto = zepto + + return $ +})() + +// If `$` is not yet defined, point it to `Zepto` +window.Zepto = Zepto +'$' in window || (window.$ = Zepto) diff --git a/frontend/gamma/js/main_iPhone.js b/frontend/gamma/js/main.mobile.js index 0644f68..60a32fa 100644 --- a/frontend/gamma/js/main_iPhone.js +++ b/frontend/gamma/js/main.mobile.js @@ -47,11 +47,18 @@ Clipperz.PM.RunTime = {}; function run() { - MochiKit.DOM.removeElement('javaScriptAlert'); Clipperz.PM.Strings.Languages.initSetup(); - Clipperz.PM.RunTime.mainController = new Clipperz.PM.UI.iPhone.Controllers.MainController(); - Clipperz.PM.RunTime.mainController.run(false); + Clipperz.PM.RunTime.mainController = new Clipperz.PM.UI.Mobile.Controllers.MainController(); + Clipperz.PM.RunTime.mainController.run(); } +// if (navigator.standalone == false) { +// window.localStorage.setItem('PIN', '1234'); +// alert("Saved PIN"); +// } else { +// alert (window.localStorage.getItem('PIN')); +// } + + MochiKit.DOM.addLoadEvent(run); |