mirror of
http://git.whoc.org.uk/git/password-manager.git
synced 2026-08-11 15:00:23 +02:00
Updated /delta
Switched from less to scss. Still no build script to update the final CSS, though. Added preliminary support for storing account data on browser's local storage for offline viewing. No public backend currently support this feature.
This commit is contained in:
+1201
-911
File diff suppressed because one or more lines are too long
@@ -21,7 +21,7 @@ refer to http://www.clipperz.com.
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<html>
|
<html manifest="manifest.appcache">
|
||||||
<head>
|
<head>
|
||||||
<title>@page.title@</title>
|
<title>@page.title@</title>
|
||||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||||
@@ -84,7 +84,7 @@ Clipperz_normalizedNewLine = '\x0d\x0a';
|
|||||||
<div class="page right" id="cardListPage"></div>
|
<div class="page right" id="cardListPage"></div>
|
||||||
<div class="page right" id="cardDetailPage"></div>
|
<div class="page right" id="cardDetailPage"></div>
|
||||||
<div class="page right" id="accountPage"></div>
|
<div class="page right" id="accountPage"></div>
|
||||||
<div class="page right" id="preferencesPage"></div>
|
<div class="page right" id="preferencePage"></div>
|
||||||
<div class="page right" id="errorPage"></div>
|
<div class="page right" id="errorPage"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overlay" id="overlay">
|
<div class="overlay" id="overlay">
|
||||||
@@ -120,6 +120,7 @@ Clipperz_normalizedNewLine = '\x0d\x0a';
|
|||||||
MochiKit.DOM.addLoadEvent(function () {
|
MochiKit.DOM.addLoadEvent(function () {
|
||||||
Clipperz.Crypto.PRNG.defaultRandomGenerator().fastEntropyAccumulationForTestingPurpose();
|
Clipperz.Crypto.PRNG.defaultRandomGenerator().fastEntropyAccumulationForTestingPurpose();
|
||||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', {username:'joe', passphrase:'clipperz'});
|
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', {username:'joe', passphrase:'clipperz'});
|
||||||
|
// MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', {username:'jj', passphrase:'jj'});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Live Reload hoock
|
// Live Reload hoock
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2008-2013 Clipperz Srl
|
||||||
|
|
||||||
|
This file is part of Clipperz, the online password manager.
|
||||||
|
For further information about its features and functionalities please
|
||||||
|
refer to http://www.clipperz.com.
|
||||||
|
|
||||||
|
* Clipperz is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
* Clipperz is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Affero General Public
|
||||||
|
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
Clipperz.PM.DataModel.DevicePreferences = function (args) {
|
||||||
|
args = args || {};
|
||||||
|
|
||||||
|
this._data = null;
|
||||||
|
|
||||||
|
Clipperz.PM.DataModel.DevicePreferences.superclass.constructor.apply(this, arguments);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Clipperz.Base.extend(Clipperz.PM.DataModel.DevicePreferences, Object, {
|
||||||
|
|
||||||
|
toString: function () {
|
||||||
|
return "Clipperz.PM.DataModel.DevicePreferences";
|
||||||
|
},
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
shouldStoreDataLocally: function () {
|
||||||
|
return (localStorage.getItem('shouldStoreDataLocally') === 'true');
|
||||||
|
},
|
||||||
|
|
||||||
|
setShouldStoreDataLocally: function (aValue) {
|
||||||
|
localStorage.setItem('shouldStoreDataLocally', aValue);
|
||||||
|
},
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
setAccountDataWityResponse: function (aResponse) {
|
||||||
|
localStorage.setItem('clipperz_dump_data', aResponse['data']);
|
||||||
|
localStorage.setItem('clipperz_dump_version', aResponse['version']);
|
||||||
|
localStorage.setItem('clipperz_dump_date', new Date());
|
||||||
|
|
||||||
|
this._data = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
accountData: function () {
|
||||||
|
if (this._data == null) {
|
||||||
|
var data;
|
||||||
|
|
||||||
|
data = localStorage.getItem('clipperz_dump_data');
|
||||||
|
if (data != null) {
|
||||||
|
this._data = JSON.parse(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._data;
|
||||||
|
},
|
||||||
|
|
||||||
|
latestDownload: function () {
|
||||||
|
var result;
|
||||||
|
var date;
|
||||||
|
|
||||||
|
date = localStorage.getItem('clipperz_dump_date');
|
||||||
|
if (date != null) {
|
||||||
|
result = new Date(date);
|
||||||
|
} else {
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
__syntaxFix__: "syntax fix"
|
||||||
|
});
|
||||||
|
|
||||||
@@ -152,6 +152,7 @@ Clipperz.PM.Proxy.prototype = MochiKit.Base.update(null, {
|
|||||||
'sendMessage': function (aFunctionName, someParameters) {
|
'sendMessage': function (aFunctionName, someParameters) {
|
||||||
var deferredResult;
|
var deferredResult;
|
||||||
|
|
||||||
|
console.log("PROXY.sendMessage", aFunctionName, someParameters);
|
||||||
// TODO: read actual application version for a property set at build time
|
// TODO: read actual application version for a property set at build time
|
||||||
deferredResult = new Clipperz.Async.Deferred("Proxy.sendMessage", {trace:false});
|
deferredResult = new Clipperz.Async.Deferred("Proxy.sendMessage", {trace:false});
|
||||||
deferredResult.addMethod(this, '_sendMessage', aFunctionName, 'fake-app-version');
|
deferredResult.addMethod(this, '_sendMessage', aFunctionName, 'fake-app-version');
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ Clipperz.Base.extend(Clipperz.PM.Proxy.JSON, Clipperz.PM.Proxy, {
|
|||||||
version: aVersion,
|
version: aVersion,
|
||||||
parameters: Clipperz.Base.serializeJSON(someParameters)
|
parameters: Clipperz.Base.serializeJSON(someParameters)
|
||||||
};
|
};
|
||||||
|
console.log("PROXY.JSON._sendMessage", parameters);
|
||||||
deferredResult = new Clipperz.Async.Deferred("Proxy.JSON.sendMessage", {trace:false});
|
deferredResult = new Clipperz.Async.Deferred("Proxy.JSON._sendMessage", {trace:false});
|
||||||
deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'remoteRequestSent');
|
deferredResult.addCallbackPass(MochiKit.Signal.signal, Clipperz.Signal.NotificationCenter, 'remoteRequestSent');
|
||||||
deferredResult.addCallback(MochiKit.Async.doXHR, this.url(), {
|
deferredResult.addCallback(MochiKit.Async.doXHR, this.url(), {
|
||||||
method:'POST',
|
method:'POST',
|
||||||
|
|||||||
@@ -30,7 +30,9 @@ try { if (typeof(Clipperz.PM.Proxy.Offline.DataStore) == 'undefined') { throw ""
|
|||||||
Clipperz.PM.Proxy.Offline.LocalStorageDataStore = function(args) {
|
Clipperz.PM.Proxy.Offline.LocalStorageDataStore = function(args) {
|
||||||
args = args || {};
|
args = args || {};
|
||||||
|
|
||||||
this._data = args.data || (typeof(_clipperz_dump_data_) != 'undefined' ? _clipperz_dump_data_ : null);
|
// this._data = args.data || (typeof(_clipperz_dump_data_) != 'undefined' ? _clipperz_dump_data_ : null);
|
||||||
|
this._data = JSON.parse(localStorage.getItem('clipperz_dump_data'));
|
||||||
|
|
||||||
this._isReadOnly = (typeof(args.readOnly) == 'undefined' ? true : args.readOnly);
|
this._isReadOnly = (typeof(args.readOnly) == 'undefined' ? true : args.readOnly);
|
||||||
this._shouldPayTolls = args.shouldPayTolls || false;
|
this._shouldPayTolls = args.shouldPayTolls || false;
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ Clipperz.PM.UI.Components.CardDetail = React.createClass({
|
|||||||
return {
|
return {
|
||||||
// showSearch: false,
|
// showSearch: false,
|
||||||
// searchTimer: null,
|
// searchTimer: null,
|
||||||
|
unmaskedFields: new Clipperz.Set(),
|
||||||
starred: false
|
starred: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -45,6 +46,32 @@ Clipperz.PM.UI.Components.CardDetail = React.createClass({
|
|||||||
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'runDirectLogin', {record:this.props.card['reference'], directLogin:aDirectLoginReference});
|
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'runDirectLogin', {record:this.props.card['reference'], directLogin:aDirectLoginReference});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
toggleFieldVisibility: function (aField, anEvent) {
|
||||||
|
var unmaskedFields;
|
||||||
|
var fieldReference;
|
||||||
|
|
||||||
|
unmaskedFields = this.state['unmaskedFields'];
|
||||||
|
fieldReference = aField['reference']
|
||||||
|
if (unmaskedFields.contains(fieldReference)) {
|
||||||
|
unmaskedFields.remove(fieldReference)
|
||||||
|
} else {
|
||||||
|
unmaskedFields.add(fieldReference)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({'unmaskedFields': unmaskedFields});
|
||||||
|
},
|
||||||
|
|
||||||
|
handleGoAction: function (aField, anEvent) {
|
||||||
|
var newWindow;
|
||||||
|
|
||||||
|
newWindow = MochiKit.DOM.currentWindow().open(aField['value'], '_blank');
|
||||||
|
newWindow.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
handleEmailAction: function (aField, anEvent) {
|
||||||
|
MochiKit.DOM.currentWindow().location = 'mailto:' + aField['value'];
|
||||||
|
},
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|
||||||
normalizeFieldValue: function (aValue) {
|
normalizeFieldValue: function (aValue) {
|
||||||
@@ -61,30 +88,56 @@ Clipperz.PM.UI.Components.CardDetail = React.createClass({
|
|||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
renderField: function (aField) {
|
renderFieldActionButton: function (aField) {
|
||||||
//console.log("FIELD", aField);
|
// var actionLabel;
|
||||||
var actionLabel;
|
var result;
|
||||||
|
|
||||||
if (aField['actionType'] == 'URL') {
|
if (aField['actionType'] == 'URL') {
|
||||||
actionLabel = "go";
|
result = React.DOM.div({className:'actionWrapper', onClick:MochiKit.Base.method(this, 'handleGoAction', aField)}, [
|
||||||
|
React.DOM.a({className:aField['actionType']}, "go")
|
||||||
|
]);
|
||||||
} else if (aField['actionType'] == 'PASSWORD') {
|
} else if (aField['actionType'] == 'PASSWORD') {
|
||||||
actionLabel = "locked";
|
var icon;
|
||||||
|
|
||||||
|
if (this.state['unmaskedFields'].contains(aField['reference'])) {
|
||||||
|
icon = "unlocked";
|
||||||
|
} else {
|
||||||
|
icon = "locked";
|
||||||
|
}
|
||||||
|
result = React.DOM.div({className:'actionWrapper', onClick:MochiKit.Base.method(this, 'toggleFieldVisibility', aField)}, [
|
||||||
|
React.DOM.a({className:aField['actionType']}, icon)
|
||||||
|
]);
|
||||||
} else if (aField['actionType'] == 'EMAIL') {
|
} else if (aField['actionType'] == 'EMAIL') {
|
||||||
actionLabel = "email";
|
result = React.DOM.div({className:'actionWrapper', onClick:MochiKit.Base.method(this, 'handleEmailAction', aField)}, [
|
||||||
|
React.DOM.a({className:aField['actionType']}, "email")
|
||||||
|
]);
|
||||||
} else {
|
} else {
|
||||||
actionLabel = "";
|
result = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return React.DOM.div({className:'listItem ' + aField['actionType']}, [
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
renderField: function (aField) {
|
||||||
|
//console.log("FIELD", aField);
|
||||||
|
var fieldExtraClass;
|
||||||
|
|
||||||
|
fieldExtraClass = aField['actionType'];
|
||||||
|
if (this.state['unmaskedFields'].contains(aField['reference'])) {
|
||||||
|
fieldExtraClass = fieldExtraClass + ' unlocked';
|
||||||
|
}
|
||||||
|
|
||||||
|
return React.DOM.div({className:'listItem ' + fieldExtraClass, key:aField['reference']}, [
|
||||||
React.DOM.div({className:'fieldWrapper'}, [
|
React.DOM.div({className:'fieldWrapper'}, [
|
||||||
React.DOM.div({className:'fieldInnerWrapper'}, [
|
React.DOM.div({className:'fieldInnerWrapper'}, [
|
||||||
React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aField['label'])),
|
React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aField['label'])),
|
||||||
React.DOM.div({className:'valueWrapper'}, React.DOM.span({className:'value ' + aField['actionType']}, this.normalizeFieldValue(aField['value'])))
|
React.DOM.div({className:'valueWrapper'}, React.DOM.span({className:'value ' + fieldExtraClass}, this.normalizeFieldValue(aField['value'])))
|
||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
React.DOM.div({className:'actionWrapper'}, [
|
this.renderFieldActionButton(aField)
|
||||||
React.DOM.div({className:aField['actionType']}, actionLabel)
|
// React.DOM.div({className:'actionWrapper'}, [
|
||||||
])
|
// React.DOM.div({className:aField['actionType']}, actionLabel)
|
||||||
|
// ])
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -98,7 +151,8 @@ Clipperz.PM.UI.Components.CardDetail = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleBackClick: function (anEvent) {
|
handleBackClick: function (anEvent) {
|
||||||
window.history.back();
|
// window.history.back();
|
||||||
|
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'goBack');
|
||||||
},
|
},
|
||||||
|
|
||||||
handleStarClick: function (anEvent) {
|
handleStarClick: function (anEvent) {
|
||||||
@@ -109,7 +163,7 @@ Clipperz.PM.UI.Components.CardDetail = React.createClass({
|
|||||||
|
|
||||||
render: function () {
|
render: function () {
|
||||||
var card = this.props.card;
|
var card = this.props.card;
|
||||||
var starredStatus = (this.state['starred'] ? "starred" : "unstarred");
|
// var starredStatus = (this.state['starred'] ? "starred" : "unstarred");
|
||||||
|
|
||||||
if ((typeof(card['fields']) != 'undefined') && (card['notes'] != '')) {
|
if ((typeof(card['fields']) != 'undefined') && (card['notes'] != '')) {
|
||||||
card['fields'].push({ 'actionType': 'NOTES', 'isHidden': false, 'label': "notes", 'reference': "notes", 'value': card['notes'] })
|
card['fields'].push({ 'actionType': 'NOTES', 'isHidden': false, 'label': "notes", 'reference': "notes", 'value': card['notes'] })
|
||||||
@@ -118,9 +172,8 @@ Clipperz.PM.UI.Components.CardDetail = React.createClass({
|
|||||||
return React.DOM.div({className:'cardDetail'}, [
|
return React.DOM.div({className:'cardDetail'}, [
|
||||||
React.DOM.div({className:'header'}, [
|
React.DOM.div({className:'header'}, [
|
||||||
React.DOM.div({className:'titleWrapper'}, React.DOM.div({className:'title'}, card.title)),
|
React.DOM.div({className:'titleWrapper'}, React.DOM.div({className:'title'}, card.title)),
|
||||||
// React.DOM.div({className:'titleWrapper'}, React.DOM.div({className:'title'}, card.title + ' ' + card.title + ' ' + card.title + ' ' + card.title)),
|
|
||||||
React.DOM.div({className:'backWrapper'}, React.DOM.a({className:'button back', onClick:this.handleBackClick}, "back")),
|
React.DOM.div({className:'backWrapper'}, React.DOM.a({className:'button back', onClick:this.handleBackClick}, "back")),
|
||||||
React.DOM.div({className:'starWrapper'}, React.DOM.a({className:'star', onClick:this.handleStarClick}, starredStatus))
|
// React.DOM.div({className:'starWrapper'}, React.DOM.a({className:'star', onClick:this.handleStarClick}, starredStatus))
|
||||||
]),
|
]),
|
||||||
React.DOM.div({className:'content'}, [
|
React.DOM.div({className:'content'}, [
|
||||||
card.fields ? React.DOM.div({className:'fields'}, MochiKit.Base.map(this.renderField, card.fields)) : null,
|
card.fields ? React.DOM.div({className:'fields'}, MochiKit.Base.map(this.renderField, card.fields)) : null,
|
||||||
|
|||||||
@@ -97,11 +97,18 @@ console.log("focusOnSearchField", this.refs['searchField']);
|
|||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|
||||||
|
showPreferences: function (anEvent) {
|
||||||
|
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'showPreferences', anEvent);
|
||||||
|
},
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
|
||||||
cardItem: function (aRecordReference) {
|
cardItem: function (aRecordReference) {
|
||||||
var reference = aRecordReference['_reference'];
|
var reference = aRecordReference['_reference'];
|
||||||
var selectedCard = (reference == this.props.selectedCard);
|
var selectedCard = (reference == this.props.selectedCard);
|
||||||
|
|
||||||
return React.DOM.div({className:'listItem', onClick:MochiKit.Base.method(this, 'handleClickOnCardDetail', reference)}, [
|
// TODO: verify if it is possible to put the onClick handler on the container 'div', instead of adding it to each 'div' item.
|
||||||
|
return React.DOM.div({className:'listItem', key:reference, onClick:MochiKit.Base.method(this, 'handleClickOnCardDetail', reference)}, [
|
||||||
React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aRecordReference.label)),
|
React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aRecordReference.label)),
|
||||||
// React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label)),
|
// React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label + ' ' + aRecordReference.label)),
|
||||||
React.DOM.div({className:'faviconWrapper'}, aRecordReference.favicon ? React.DOM.img({className:'favicon', src:aRecordReference.favicon}) : React.DOM.div({className:'favicon'}, '\u00A0')),
|
React.DOM.div({className:'faviconWrapper'}, aRecordReference.favicon ? React.DOM.img({className:'favicon', src:aRecordReference.favicon}) : React.DOM.div({className:'favicon'}, '\u00A0')),
|
||||||
@@ -146,9 +153,9 @@ console.log("focusOnSearchField", this.refs['searchField']);
|
|||||||
React.DOM.div({className:'header'}, [
|
React.DOM.div({className:'header'}, [
|
||||||
React.DOM.a({className:'account'}, 'clipperz'),
|
React.DOM.a({className:'account'}, 'clipperz'),
|
||||||
React.DOM.div({className:'features'}, [
|
React.DOM.div({className:'features'}, [
|
||||||
React.DOM.a({className:'addCard'}, 'add'),
|
// React.DOM.a({className:'addCard'}, 'add'),
|
||||||
React.DOM.a({className:'search ' + (this.state.showSearch ? 'selected' : ''), onClick:this.toggleSearch}, 'search'),
|
React.DOM.a({className:'search ' + (this.state.showSearch ? 'selected' : ''), onClick:this.toggleSearch}, 'search'),
|
||||||
React.DOM.a({className:'settings'}, 'settings')
|
React.DOM.a({className:'settings', onClick:this.showPreferences}, 'settings')
|
||||||
]),
|
]),
|
||||||
// this.searchBox()
|
// this.searchBox()
|
||||||
]),
|
]),
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2008-2013 Clipperz Srl
|
||||||
|
|
||||||
|
This file is part of Clipperz, the online password manager.
|
||||||
|
For further information about its features and functionalities please
|
||||||
|
refer to http://www.clipperz.com.
|
||||||
|
|
||||||
|
* Clipperz is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
* Clipperz is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Affero General Public
|
||||||
|
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
Clipperz.PM.UI.Components.Checkbox = React.createClass({
|
||||||
|
// http://development.tobypitman.com/iphoneCheckboxes/iphoneCheckboxes2.html
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
'checked': React.PropTypes.bool.isRequired,
|
||||||
|
'id': React.PropTypes.string.isRequired,
|
||||||
|
'eventHandler': React.PropTypes.func.isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
|
||||||
|
render: function () {
|
||||||
|
return React.DOM.div({className:'checkbox', onClick:this.props['eventHandler']}, [
|
||||||
|
React.DOM.input({name:this.props['id'], id:this.props['id'], value:this.props['id'], type:'checkbox', checked:this.props['checked']}),
|
||||||
|
React.DOM.label({className:'check', 'for':this.props['id']}),
|
||||||
|
React.DOM.label({className:'info', 'for':this.props['id']}, "enable local storage")
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
});
|
||||||
@@ -92,14 +92,14 @@ Clipperz.PM.UI.Components.LoginForm = React.createClass({
|
|||||||
|
|
||||||
loginForm: function () {
|
loginForm: function () {
|
||||||
registrationLink = React.DOM.div({'className':'registrationLink'}, [
|
registrationLink = React.DOM.div({'className':'registrationLink'}, [
|
||||||
React.DOM.a({'onClick':this.handleRegistrationLinkClick}, "Need an account")
|
React.DOM.a({'onClick':this.handleRegistrationLinkClick}, "Sign up")
|
||||||
]);
|
]);
|
||||||
return React.DOM.div({'className':'loginForm credentials'},[
|
return React.DOM.div({'className':'loginForm credentials'},[
|
||||||
React.DOM.form({onChange: this.handleChange, onSubmit:this.handleCredentialSubmit}, [
|
React.DOM.form({onChange: this.handleChange, onSubmit:this.handleCredentialSubmit}, [
|
||||||
React.DOM.div(null,[
|
React.DOM.div(null,[
|
||||||
React.DOM.label({'for':'name'}, "username"),
|
React.DOM.label({'for' :'name'}, "username"),
|
||||||
React.DOM.input({'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'key':'username', 'autoCapitalize':'none'}),
|
React.DOM.input({'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'key':'username', 'autoCapitalize':'none'}),
|
||||||
React.DOM.label({'for':'passphrase'}, "passphrase"),
|
React.DOM.label({'for' :'passphrase'}, "passphrase"),
|
||||||
React.DOM.input({'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase", 'key':'passphrase'})
|
React.DOM.input({'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase", 'key':'passphrase'})
|
||||||
]),
|
]),
|
||||||
React.DOM.button({'type':'submit', 'disabled':!this.shouldEnableLoginButton(), 'className':'button'}, "login")
|
React.DOM.button({'type':'submit', 'disabled':!this.shouldEnableLoginButton(), 'className':'button'}, "login")
|
||||||
|
|||||||
@@ -94,9 +94,10 @@ Clipperz.Base.extend(Clipperz.PM.UI.Components.Overlay, Object, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
'hide': function () {
|
'hide': function () {
|
||||||
MochiKit.DOM.removeElementClass(this.element(), 'ios-overlay-show');
|
var element = this.element();
|
||||||
MochiKit.DOM.addElementClass(this.element(), 'ios-overlay-hide');
|
MochiKit.DOM.removeElementClass(element, 'ios-overlay-show');
|
||||||
MochiKit.Async.callLater(1, MochiKit.Style.hideElement, this.element());
|
MochiKit.DOM.addElementClass(element, 'ios-overlay-hide');
|
||||||
|
MochiKit.Async.callLater(1, MochiKit.Style.hideElement, element);
|
||||||
},
|
},
|
||||||
|
|
||||||
'hideSpinner': function () {
|
'hideSpinner': function () {
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright 2008-2013 Clipperz Srl
|
||||||
|
|
||||||
|
This file is part of Clipperz, the online password manager.
|
||||||
|
For further information about its features and functionalities please
|
||||||
|
refer to http://www.clipperz.com.
|
||||||
|
|
||||||
|
* Clipperz is free software: you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
* Clipperz is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Affero General Public
|
||||||
|
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
Clipperz.PM.UI.Components.PreferencePage = React.createClass({
|
||||||
|
|
||||||
|
getDefaultProps: function () {
|
||||||
|
return {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
// card: React.PropTypes.object.isRequired
|
||||||
|
// checked: React.PropTypes.boolean.isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
getInitialState: function () {
|
||||||
|
// return {
|
||||||
|
// shouldStoreDataLocally: false
|
||||||
|
// };
|
||||||
|
},
|
||||||
|
|
||||||
|
handleBackClick: function (anEvent) {
|
||||||
|
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'goBack');
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleShouldStoreDataLocally: function (anEvent) {
|
||||||
|
// this.setState({shouldStoreDataLocally: !this.state['shouldStoreDataLocally']});
|
||||||
|
Clipperz.PM.DataModel.devicePreferences.setShouldStoreDataLocally(!Clipperz.PM.DataModel.devicePreferences.shouldStoreDataLocally());
|
||||||
|
this.setState({});
|
||||||
|
},
|
||||||
|
|
||||||
|
shouldStoreDataLocally: function () {
|
||||||
|
return Clipperz.PM.DataModel.devicePreferences.shouldStoreDataLocally();
|
||||||
|
},
|
||||||
|
|
||||||
|
syncNow: function (anEvent) {
|
||||||
|
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'synchronizeLocalData');
|
||||||
|
},
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
|
||||||
|
render: function () {
|
||||||
|
return React.DOM.div({className:'preferences'}, [
|
||||||
|
React.DOM.div({className:'header'}, [
|
||||||
|
React.DOM.div({className:'titleWrapper'}, React.DOM.div({className:'title'}, "Preferences")),
|
||||||
|
React.DOM.div({className:'backWrapper'}, React.DOM.a({className:'button back', onClick:this.handleBackClick}, "back")),
|
||||||
|
]),
|
||||||
|
React.DOM.div({className:'content'}, [
|
||||||
|
React.DOM.form(null, [
|
||||||
|
React.DOM.div({className:'section'}, [
|
||||||
|
React.DOM.h4(null, "Local storage"),
|
||||||
|
React.DOM.p(null, "Store you account data locally for offline viewing"),
|
||||||
|
new Clipperz.PM.UI.Components.Checkbox({'id':'shouldStoreLocally_checkbox', 'checked':this.shouldStoreDataLocally(), 'eventHandler':this.toggleShouldStoreDataLocally}),
|
||||||
|
this.shouldStoreDataLocally() ? React.DOM.div({className:'syncInfo'}, [
|
||||||
|
// React.DOM.h5(null, "data were never synchronized before"),
|
||||||
|
React.DOM.a({className:'button', onClick:this.syncNow}, "Sync now")
|
||||||
|
]) : null
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
React.DOM.div({className:'footer'}, [
|
||||||
|
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
});
|
||||||
@@ -26,7 +26,7 @@ Clipperz.Base.module('Clipperz.PM.UI');
|
|||||||
Clipperz.PM.UI.MainController = function() {
|
Clipperz.PM.UI.MainController = function() {
|
||||||
var pages;
|
var pages;
|
||||||
|
|
||||||
this._proxy = null;
|
// this._proxy = null;
|
||||||
this._user = null;
|
this._user = null;
|
||||||
this._filter = '';
|
this._filter = '';
|
||||||
|
|
||||||
@@ -39,12 +39,14 @@ Clipperz.PM.UI.MainController = function() {
|
|||||||
'registrationPage': new Clipperz.PM.UI.Components.RegistrationWizard(),
|
'registrationPage': new Clipperz.PM.UI.Components.RegistrationWizard(),
|
||||||
'cardListPage': new Clipperz.PM.UI.Components.CardList(),
|
'cardListPage': new Clipperz.PM.UI.Components.CardList(),
|
||||||
'cardDetailPage': new Clipperz.PM.UI.Components.CardDetail({card: {}}),
|
'cardDetailPage': new Clipperz.PM.UI.Components.CardDetail({card: {}}),
|
||||||
|
'preferencePage': new Clipperz.PM.UI.Components.PreferencePage(),
|
||||||
'errorPage': new Clipperz.PM.UI.Components.ErrorPage({message:''})
|
'errorPage': new Clipperz.PM.UI.Components.ErrorPage({message:''})
|
||||||
};
|
};
|
||||||
|
|
||||||
MochiKit.Base.map(function (anId) {React.renderComponent(pages[anId], MochiKit.DOM.getElement(anId))}, MochiKit.Base.keys(pages));
|
MochiKit.Base.map(function (anId) {React.renderComponent(pages[anId], MochiKit.DOM.getElement(anId))}, MochiKit.Base.keys(pages));
|
||||||
this._pages = pages;
|
this._pages = pages;
|
||||||
this.registerForNotificationCenterEvents();
|
this.registerForNotificationCenterEvents();
|
||||||
|
MochiKit.Signal.connect(MochiKit.DOM.currentDocument(), 'onselectionchange', this, 'selectionChangeHandler');
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -73,10 +75,12 @@ MochiKit.Base.update(Clipperz.PM.UI.MainController.prototype, {
|
|||||||
|
|
||||||
isOnline: function() {
|
isOnline: function() {
|
||||||
return navigator.onLine;
|
return navigator.onLine;
|
||||||
|
// return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
hasLocalData: function() {
|
hasLocalData: function() {
|
||||||
return false;
|
// return false;
|
||||||
|
return (Clipperz.PM.DataModel.devicePreferences.accountData() != null);
|
||||||
},
|
},
|
||||||
|
|
||||||
loginMode: function () {
|
loginMode: function () {
|
||||||
@@ -98,26 +102,41 @@ MochiKit.Base.update(Clipperz.PM.UI.MainController.prototype, {
|
|||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|
||||||
|
showOfflineError: function () {
|
||||||
|
console.log("THE BROWSER IS OFFLINE");
|
||||||
|
},
|
||||||
|
|
||||||
selectInitialProxy: function () {
|
selectInitialProxy: function () {
|
||||||
if (this.isOnline()) {
|
if (this.isOnline()) {
|
||||||
this._proxy = Clipperz.PM.Proxy.defaultProxy;
|
// this._proxy = Clipperz.PM.Proxy.defaultProxy;
|
||||||
} else {
|
} else {
|
||||||
if (this.hasLocalData()) {
|
if (this.hasLocalData()) {
|
||||||
this._proxy = new Clipperz.PM.Proxy.Offline({dataStore: new Clipperz.PM.Proxy.Offline.LocalStorageDataStore(), shouldPayTolls:false});
|
// this._proxy = new Clipperz.PM.Proxy.Offline({dataStore: new Clipperz.PM.Proxy.Offline.LocalStorageDataStore(), shouldPayTolls:false});
|
||||||
|
Clipperz.PM.Proxy.defaultProxy = new Clipperz.PM.Proxy.Offline({dataStore: new Clipperz.PM.Proxy.Offline.LocalStorageDataStore(), shouldPayTolls:false});
|
||||||
} else {
|
} else {
|
||||||
this.showOfflineError();
|
this.showOfflineError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
proxy: function () {
|
// proxy: function () {
|
||||||
return this._proxy;
|
// return this._proxy;
|
||||||
},
|
// },
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|
||||||
registerForNotificationCenterEvents: function () {
|
registerForNotificationCenterEvents: function () {
|
||||||
var events = ['doLogin', 'registerNewUser', 'showRegistrationForm', 'goBack', 'showRecord', 'searchCards', 'runDirectLogin'];
|
var events = [
|
||||||
|
'doLogin',
|
||||||
|
'registerNewUser',
|
||||||
|
'showRegistrationForm',
|
||||||
|
'goBack',
|
||||||
|
'showRecord',
|
||||||
|
'searchCards',
|
||||||
|
'showPreferences',
|
||||||
|
'runDirectLogin',
|
||||||
|
'synchronizeLocalData'
|
||||||
|
];
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
MochiKit.Base.map(function (anEvent) {
|
MochiKit.Base.map(function (anEvent) {
|
||||||
@@ -130,12 +149,53 @@ MochiKit.Base.update(Clipperz.PM.UI.MainController.prototype, {
|
|||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
selectionChangeHandler: function (anEvent) {
|
||||||
|
var selection;
|
||||||
|
var selectionRange;
|
||||||
|
var selectionNode;
|
||||||
|
var valueElement;
|
||||||
|
// other hints: http://www.bearpanther.com/2013/05/27/easy-text-selection-in-mobile-safari/
|
||||||
|
// SELECTION: https://developer.mozilla.org/en-US/docs/Web/API/Selection
|
||||||
|
// RANGE: https://developer.mozilla.org/en-US/docs/Web/API/Range
|
||||||
|
// NODE TYPES: https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeType
|
||||||
|
|
||||||
|
selection = MochiKit.DOM.currentWindow().getSelection();
|
||||||
|
//console.log("-- selection", selection);
|
||||||
|
selectionRange = selection.getRangeAt(0);
|
||||||
|
selectionNode = selectionRange.startContainer.childNodes[selectionRange.startOffset];
|
||||||
|
//console.log("-- selectionNode", selectionNode);
|
||||||
|
|
||||||
|
if (selectionNode != undefined) {
|
||||||
|
valueElement = MochiKit.DOM.getFirstElementByTagAndClassName('*', 'value', selectionNode);
|
||||||
|
//console.log("-- valueElement", valueElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((valueElement != null) && (valueElement != selectionNode)) {
|
||||||
|
var range;
|
||||||
|
range = MochiKit.DOM.currentDocument().createRange();
|
||||||
|
range.selectNodeContents(valueElement);
|
||||||
|
selection.removeAllRanges();
|
||||||
|
selection.addRange(range);
|
||||||
|
|
||||||
|
anEvent.preventDefault();
|
||||||
|
anEvent.stopPropagation();
|
||||||
|
|
||||||
|
//console.log("updated selection", MochiKit.DOM.currentWindow().getSelection());
|
||||||
|
}
|
||||||
|
//console.log("-----------");
|
||||||
|
},
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
run: function (parameters) {
|
run: function (parameters) {
|
||||||
var shouldShowRegistrationForm;
|
var shouldShowRegistrationForm;
|
||||||
|
var canRegisterNewUsers;
|
||||||
|
|
||||||
|
canRegisterNewUsers = Clipperz.PM.Proxy.defaultProxy.canRegisterNewUsers();
|
||||||
|
|
||||||
this.selectInitialProxy();
|
this.selectInitialProxy();
|
||||||
shouldShowRegistrationForm = parameters['shouldShowRegistrationForm'] && this.proxy().canRegisterNewUsers();
|
shouldShowRegistrationForm = parameters['shouldShowRegistrationForm'] && canRegisterNewUsers;
|
||||||
this.pages()['loginPage'].setProps({'mode':this.loginMode(), 'isNewUserRegistrationAvailable': this.proxy().canRegisterNewUsers()});
|
this.pages()['loginPage'].setProps({'mode':this.loginMode(), 'isNewUserRegistrationAvailable':canRegisterNewUsers});
|
||||||
|
|
||||||
if (shouldShowRegistrationForm) {
|
if (shouldShowRegistrationForm) {
|
||||||
this.showRegistrationForm();
|
this.showRegistrationForm();
|
||||||
@@ -151,7 +211,7 @@ MochiKit.Base.update(Clipperz.PM.UI.MainController.prototype, {
|
|||||||
var loginFormPage;
|
var loginFormPage;
|
||||||
|
|
||||||
loginFormPage = this.pages()['loginPage'];
|
loginFormPage = this.pages()['loginPage'];
|
||||||
loginFormPage.setProps({'mode':this.loginMode(), 'isNewUserRegistrationAvailable': this.proxy().canRegisterNewUsers()});
|
loginFormPage.setProps({'mode':this.loginMode(), 'isNewUserRegistrationAvailable':Clipperz.PM.Proxy.defaultProxy.canRegisterNewUsers()});
|
||||||
this.moveInPage(this.currentPage(), 'loginPage');
|
this.moveInPage(this.currentPage(), 'loginPage');
|
||||||
MochiKit.Async.callLater(0.5, MochiKit.Base.method(loginFormPage, 'setInitialFocus'));
|
MochiKit.Async.callLater(0.5, MochiKit.Base.method(loginFormPage, 'setInitialFocus'));
|
||||||
},
|
},
|
||||||
@@ -202,9 +262,9 @@ MochiKit.Base.update(Clipperz.PM.UI.MainController.prototype, {
|
|||||||
deferredResult.addErrback(MochiKit.Base.bind(function (anEvent, anError) {
|
deferredResult.addErrback(MochiKit.Base.bind(function (anEvent, anError) {
|
||||||
if (anError['isPermanent'] != true) {
|
if (anError['isPermanent'] != true) {
|
||||||
this.pages()['loginPage'].setProps({disabled:false, 'mode':this.loginMode()});
|
this.pages()['loginPage'].setProps({disabled:false, 'mode':this.loginMode()});
|
||||||
this.pages()['loginPage'].setInitialFocus();
|
this.pages()['loginPage'].setInitialFocus();
|
||||||
}
|
}
|
||||||
return anError;
|
return anError;
|
||||||
}, this, event))
|
}, this, event))
|
||||||
deferredResult.callback();
|
deferredResult.callback();
|
||||||
|
|
||||||
@@ -323,8 +383,11 @@ MochiKit.Base.update(Clipperz.PM.UI.MainController.prototype, {
|
|||||||
|
|
||||||
runApplication: function () {
|
runApplication: function () {
|
||||||
MochiKit.Signal.connect(window, 'onpopstate', MochiKit.Base.method(this, 'historyGoBack'));
|
MochiKit.Signal.connect(window, 'onpopstate', MochiKit.Base.method(this, 'historyGoBack'));
|
||||||
|
/// TODO: remove this TEST HACK
|
||||||
this.moveInPage(this.currentPage(), 'cardListPage');
|
this.moveInPage(this.currentPage(), 'cardListPage');
|
||||||
return this.showRecordList();
|
return this.showRecordList();
|
||||||
|
|
||||||
|
// this.moveInPage(this.currentPage(), 'preferencePage');
|
||||||
},
|
},
|
||||||
|
|
||||||
showRecord: function (aRecordReference) {
|
showRecord: function (aRecordReference) {
|
||||||
@@ -333,7 +396,6 @@ MochiKit.Base.update(Clipperz.PM.UI.MainController.prototype, {
|
|||||||
|
|
||||||
this.pages()['cardListPage'].setProps({selectedCard:aRecordReference});
|
this.pages()['cardListPage'].setProps({selectedCard:aRecordReference});
|
||||||
deferredResult = new Clipperz.Async.Deferred('MainController.runApplication', {trace:false});
|
deferredResult = new Clipperz.Async.Deferred('MainController.runApplication', {trace:false});
|
||||||
// deferredResult.addMethod(this.user(), 'getRecord', aRecordReference['_reference']);
|
|
||||||
deferredResult.addMethod(this.user(), 'getRecord', aRecordReference);
|
deferredResult.addMethod(this.user(), 'getRecord', aRecordReference);
|
||||||
deferredResult.addMethodcaller('content');
|
deferredResult.addMethodcaller('content');
|
||||||
deferredResult.addCallback(MochiKit.Base.bind(function (aCard) {
|
deferredResult.addCallback(MochiKit.Base.bind(function (aCard) {
|
||||||
@@ -348,12 +410,10 @@ MochiKit.Base.update(Clipperz.PM.UI.MainController.prototype, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
runDirectLogin: function (someParameters) {
|
runDirectLogin: function (someParameters) {
|
||||||
console.log("RUN DIRECT LOGIN", someParameters);
|
//console.log("RUN DIRECT LOGIN", someParameters);
|
||||||
var deferredResult;
|
var deferredResult;
|
||||||
|
|
||||||
// this.pages()['cardListPage'].setProps({selectedCard:aRecordReference});
|
|
||||||
deferredResult = new Clipperz.Async.Deferred('MainController.runDirectLogin', {trace:false});
|
deferredResult = new Clipperz.Async.Deferred('MainController.runDirectLogin', {trace:false});
|
||||||
// deferredResult.addMethod(this.user(), 'getRecord', aRecordReference['_reference']);
|
|
||||||
deferredResult.addMethod(this.user(), 'getRecord', someParameters['record']);
|
deferredResult.addMethod(this.user(), 'getRecord', someParameters['record']);
|
||||||
deferredResult.addMethodcaller('directLoginWithReference', someParameters['directLogin']);
|
deferredResult.addMethodcaller('directLoginWithReference', someParameters['directLogin']);
|
||||||
deferredResult.addCallback(Clipperz.PM.UI.DirectLoginRunner.openDirectLogin);
|
deferredResult.addCallback(Clipperz.PM.UI.DirectLoginRunner.openDirectLogin);
|
||||||
@@ -363,13 +423,26 @@ console.log("RUN DIRECT LOGIN", someParameters);
|
|||||||
},
|
},
|
||||||
|
|
||||||
shouldExitApp: function (anEvent) {
|
shouldExitApp: function (anEvent) {
|
||||||
console.log("SHOULD EXIT APP");
|
//console.log("SHOULD EXIT APP");
|
||||||
anEvent.preventDefault();
|
anEvent.preventDefault();
|
||||||
anEvent.stopPropagation();
|
anEvent.stopPropagation();
|
||||||
},
|
},
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|
||||||
|
showPreferences: function (anEvent) {
|
||||||
|
var deferredResult;
|
||||||
|
|
||||||
|
this.pages()['preferencePage'].setProps({});
|
||||||
|
deferredResult = new Clipperz.Async.Deferred('MainController.showPreferences', {trace:false});
|
||||||
|
deferredResult.addMethod(this, 'moveInPage', this.currentPage(), 'preferencePage', true);
|
||||||
|
deferredResult.callback();
|
||||||
|
|
||||||
|
return deferredResult;
|
||||||
|
},
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
|
||||||
genericErrorHandler: function (anEvent, anError) {
|
genericErrorHandler: function (anEvent, anError) {
|
||||||
var errorMessage;
|
var errorMessage;
|
||||||
var result;
|
var result;
|
||||||
@@ -480,6 +553,25 @@ console.log("SHOULD EXIT APP");
|
|||||||
},
|
},
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|
||||||
|
synchronizeLocalData: function (anEvent) {
|
||||||
|
var deferredResult;
|
||||||
|
|
||||||
|
deferredResult = new Clipperz.Async.Deferred('MainController.synchronizeLocalData', {trace:true});
|
||||||
|
// deferredResult.addMethod(this.proxy(), 'message', 'downloadAccountData', {});
|
||||||
|
deferredResult.addMethod(this.user().connection(), 'message', 'downloadAccountData', {});
|
||||||
|
deferredResult.addCallback(function (aResult) {
|
||||||
|
Clipperz.PM.DataModel.devicePreferences.setAccountDataWityResponse(aResult);
|
||||||
|
// localStorage.setItem('clipperz_dump_data', aResult['data']);
|
||||||
|
// localStorage.setItem('clipperz_dump_version', aResult['version']);
|
||||||
|
// localStorage.setItem('clipperz_dump_date', new Date());
|
||||||
|
})
|
||||||
|
deferredResult.callback();
|
||||||
|
|
||||||
|
return deferredResult;
|
||||||
|
},
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
/*
|
/*
|
||||||
wrongAppVersion: function (anError) {
|
wrongAppVersion: function (anError) {
|
||||||
// this.pages()['errorPage'].setProps({message:anError.message});
|
// this.pages()['errorPage'].setProps({message:anError.message});
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -41,6 +41,7 @@ MochiKit.Logging.logError("## MainController - GENERIC ERROR" + "\n" + "==>> " +
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
React.initializeTouchEvents(true);
|
||||||
|
|
||||||
Clipperz.PM.RunTime = {};
|
Clipperz.PM.RunTime = {};
|
||||||
function run() {
|
function run() {
|
||||||
@@ -55,6 +56,8 @@ function run() {
|
|||||||
parameters['shouldShowRegistrationForm'] = false;
|
parameters['shouldShowRegistrationForm'] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Clipperz.PM.DataModel.devicePreferences = new Clipperz.PM.DataModel.DevicePreferences({});
|
||||||
|
|
||||||
Clipperz.PM.RunTime.mainController = new Clipperz.PM.UI.MainController();
|
Clipperz.PM.RunTime.mainController = new Clipperz.PM.UI.MainController();
|
||||||
Clipperz.PM.RunTime.mainController.run(parameters);
|
Clipperz.PM.RunTime.mainController.run(parameters);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
.border-radius (@radius) {
|
|
||||||
border-radius: @radius;
|
|
||||||
-moz-border-radius: @radius;
|
|
||||||
-webkit-border-radius: @radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
.font-feature-settings(@foo, @bar) {
|
|
||||||
-webkit-font-feature-settings:"@foo","@bar";
|
|
||||||
-moz-font-feature-settings:"@foo=1, @bar=1";
|
|
||||||
-moz-font-feature-settings:"@foo","@bar";
|
|
||||||
-ms-font-feature-settings:"@foo","@bar";
|
|
||||||
-o-font-feature-settings:"@foo","@bar";
|
|
||||||
font-feature-settings:"@foo","@bar";
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-font() {
|
|
||||||
font-family: 'clipperz-icons';
|
|
||||||
.font-feature-settings("liga", "dlig");
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
text-rendering:optimizeLegibility;
|
|
||||||
}
|
|
||||||
|
|
||||||
.password-font() {
|
|
||||||
font-family: 'clipperz-password';
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
text-rendering:optimizeLegibility;
|
|
||||||
}
|
|
||||||
|
|
||||||
.animation (@animation, @duration, @fill-mode:none, @iteration-count:1) {
|
|
||||||
-webkit-animation-name: @animation;
|
|
||||||
-webkit-animation-duration: @duration;
|
|
||||||
-webkit-animation-fill-mode: @fill-mode;
|
|
||||||
-webkit-animation-iteration-count: @iteration-count;
|
|
||||||
|
|
||||||
-moz-animation-name: @animation;
|
|
||||||
-moz-animation-duration: @duration;
|
|
||||||
-moz-animation-fill-mode: @fill-mode;
|
|
||||||
-moz-animation-iteration-count: @iteration-count;
|
|
||||||
|
|
||||||
-ms-animation-name: @animation;
|
|
||||||
-ms-animation-duration: @duration;
|
|
||||||
-ms-animation-fill-mode: @fill-mode;
|
|
||||||
-ms-animation-iteration-count: @iteration-count;
|
|
||||||
|
|
||||||
-o-animation-name: @animation;
|
|
||||||
-o-animation-duration: @duration;
|
|
||||||
-o-animation-fill-mode: @fill-mode;
|
|
||||||
-o-animation-iteration-count: @iteration-count;
|
|
||||||
|
|
||||||
animation-name: @animation;
|
|
||||||
animation-duration: @duration;
|
|
||||||
animation-fill-mode: @fill-mode;
|
|
||||||
animation-iteration-count: @iteration-count;
|
|
||||||
}
|
|
||||||
|
|
||||||
.transition (@item, @time, @function) {
|
|
||||||
-webkit-transition: @item @time @function;
|
|
||||||
-moz-transition: @item @time @function;
|
|
||||||
-o-transition: @item @time @function;
|
|
||||||
-ms-transition: @item @time @function;
|
|
||||||
transition: @item @time @function;
|
|
||||||
}
|
|
||||||
|
|
||||||
.transform (@rotateAngle, @translateX, @translateY) {
|
|
||||||
-webkit-transform: rotate( @rotateAngle) translate(@translateX, @translateY);
|
|
||||||
-moz-transform: rotate( @rotateAngle) translate(@translateX, @translateY);
|
|
||||||
-ms-transform: rotate( @rotateAngle) translate(@translateX, @translateY);
|
|
||||||
-o-transform: rotate( @rotateAngle) translate(@translateX, @translateY);
|
|
||||||
transform: rotate( @rotateAngle) translate(@translateX, @translateY);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.animation-delay (@delay) {
|
|
||||||
-webkit-animation-delay: @delay;
|
|
||||||
-moz-animation-delay: @delay;
|
|
||||||
-ms-animation-delay: @delay;
|
|
||||||
-o-animation-delay: @delay;
|
|
||||||
animation-delay: @delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
.box-shadow (@xOffset, @yOffset, @size, @color) {
|
|
||||||
-webkit-box-shadow: @xOffset @yOffset @size @color;
|
|
||||||
-moz-box-shadow: @xOffset @yOffset @size @color;
|
|
||||||
-ms-box-shadow: @xOffset @yOffset @size @color;
|
|
||||||
-o-box-shadow: @xOffset @yOffset @size @color;
|
|
||||||
box-shadow: @xOffset @yOffset @size @color;
|
|
||||||
}
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
@import "mixin";
|
|
||||||
|
|
||||||
div.overlay {
|
|
||||||
z-index: 99999;
|
|
||||||
position: fixed;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
width: 200px;
|
|
||||||
height: 200px;
|
|
||||||
margin-left: -100px;
|
|
||||||
margin-top: -100px;
|
|
||||||
background: rgba(0,0,0,0.8);
|
|
||||||
.border-radius(20px);
|
|
||||||
|
|
||||||
.title {
|
|
||||||
color: #FFF;
|
|
||||||
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
|
|
||||||
font-weight: bold;
|
|
||||||
text-align: center;
|
|
||||||
display: block;
|
|
||||||
font-size: 26px;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 30px;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
width: 128px;
|
|
||||||
height: 128px;
|
|
||||||
top: 40%;
|
|
||||||
left: 50%;
|
|
||||||
margin-left: -64px;
|
|
||||||
margin-top: -64px;
|
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
vertical-align: middle;
|
|
||||||
|
|
||||||
.icon-font();
|
|
||||||
font-size: 96pt;
|
|
||||||
color: white;
|
|
||||||
text-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.ios-overlay-show {
|
|
||||||
.animation(ios-overlay-show, 750ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
&.ios-overlay-hide {
|
|
||||||
.animation(ios-overlay-hide, 750ms, forwards);
|
|
||||||
}
|
|
||||||
|
|
||||||
// http://37signals.com/svn/posts/2577-loading-spinner-animation-using-css-and-webkit
|
|
||||||
div.spinner {
|
|
||||||
position: relative;
|
|
||||||
width: 100px;
|
|
||||||
height: 100px;
|
|
||||||
left: 50% !important;
|
|
||||||
top: 40% !important;
|
|
||||||
|
|
||||||
margin-left: -50px;
|
|
||||||
margin-top: -50px;
|
|
||||||
|
|
||||||
// display: inline-block;
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
div {
|
|
||||||
width: 12%;
|
|
||||||
height: 26%;
|
|
||||||
background: #ffffff;
|
|
||||||
position: absolute;
|
|
||||||
left: 44.5%;
|
|
||||||
top: 37%;
|
|
||||||
opacity: 0;
|
|
||||||
.animation(fade, 1s, linear, infinite);
|
|
||||||
.border-radius(50px);
|
|
||||||
.box-shadow(0, 0, 3px, rgba(0,0,0,0.2));
|
|
||||||
}
|
|
||||||
|
|
||||||
div.bar01 {.transform( 0deg, 0, -142%); .animation-delay(-0.00000s);}
|
|
||||||
div.bar02 {.transform( 30deg, 0, -142%); .animation-delay(-0.91670s);}
|
|
||||||
div.bar03 {.transform( 60deg, 0, -142%); .animation-delay(-0.83300s);}
|
|
||||||
div.bar04 {.transform( 90deg, 0, -142%); .animation-delay(-0.75000s);}
|
|
||||||
div.bar05 {.transform(120deg, 0, -142%); .animation-delay(-0.66700s);}
|
|
||||||
div.bar06 {.transform(150deg, 0, -142%); .animation-delay(-0.58330s);}
|
|
||||||
div.bar07 {.transform(180deg, 0, -142%); .animation-delay(-0.50000s);}
|
|
||||||
div.bar08 {.transform(210deg, 0, -142%); .animation-delay(-0.41667s);}
|
|
||||||
div.bar09 {.transform(240deg, 0, -142%); .animation-delay(-0.33300s);}
|
|
||||||
div.bar10 {.transform(270deg, 0, -142%); .animation-delay(-0.25000s);}
|
|
||||||
div.bar11 {.transform(300deg, 0, -142%); .animation-delay(-0.16670s);}
|
|
||||||
div.bar12 {.transform(330deg, 0, -142%); .animation-delay(-0.08330s);}
|
|
||||||
|
|
||||||
@-webkit-keyframes fade {
|
|
||||||
from {opacity: 1;}
|
|
||||||
to {opacity: 0.25;}
|
|
||||||
}
|
|
||||||
@-o-keyframes fade {
|
|
||||||
from {opacity: 1;}
|
|
||||||
to {opacity: 0.25;}
|
|
||||||
}
|
|
||||||
@keyframes fade {
|
|
||||||
from {opacity: 1;}
|
|
||||||
to {opacity: 0.25;}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//========================================================
|
|
||||||
|
|
||||||
@-webkit-keyframes ios-overlay-show {
|
|
||||||
0% { opacity: 0; }
|
|
||||||
100% { opacity: 1; }
|
|
||||||
}
|
|
||||||
@-moz-keyframes ios-overlay-show {
|
|
||||||
0% { opacity: 0; }
|
|
||||||
100% { opacity: 1; }
|
|
||||||
}
|
|
||||||
@-ms-keyframes ios-overlay-show {
|
|
||||||
0% { opacity: 0; }
|
|
||||||
100% { opacity: 1; }
|
|
||||||
}
|
|
||||||
@-o-keyframes ios-overlay-show {
|
|
||||||
0% { opacity: 0; }
|
|
||||||
100% { opacity: 1; }
|
|
||||||
}
|
|
||||||
@keyframes ios-overlay-show {
|
|
||||||
0% { opacity: 0; }
|
|
||||||
100% { opacity: 1; }
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------
|
|
||||||
|
|
||||||
@-webkit-keyframes ios-overlay-hide {
|
|
||||||
0% { opacity: 1; }
|
|
||||||
100% { opacity: 0; }
|
|
||||||
}
|
|
||||||
@-moz-keyframes ios-overlay-hide {
|
|
||||||
0% { opacity: 1; }
|
|
||||||
100% { opacity: 0; }
|
|
||||||
}
|
|
||||||
@-ms-keyframes ios-overlay-hide {
|
|
||||||
0% { opacity: 1; }
|
|
||||||
100% { opacity: 0; }
|
|
||||||
}
|
|
||||||
@-o-keyframes ios-overlay-hide {
|
|
||||||
0% { opacity: 1; }
|
|
||||||
100% { opacity: 0; }
|
|
||||||
}
|
|
||||||
@keyframes ios-overlay-hide {
|
|
||||||
0% { opacity: 1; }
|
|
||||||
100% { opacity: 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
//========================================================
|
|
||||||
@@ -31,7 +31,11 @@
|
|||||||
"MochiKit/Selector.js",
|
"MochiKit/Selector.js",
|
||||||
"-- MochiKit/Visual.js",
|
"-- MochiKit/Visual.js",
|
||||||
|
|
||||||
"React/react-0.4.1.js",
|
"-- React/react-0.4.1.js",
|
||||||
|
"React/react-0.5.0-alpha.js",
|
||||||
|
|
||||||
|
"-- Hammer/hammer-1.0.5.js",
|
||||||
|
|
||||||
"Cubiq/add2home.js",
|
"Cubiq/add2home.js",
|
||||||
|
|
||||||
"Clipperz/YUI/Utils.js",
|
"Clipperz/YUI/Utils.js",
|
||||||
@@ -110,6 +114,8 @@
|
|||||||
"Clipperz/PM/DataModel/DirectLoginFormValue.js",
|
"Clipperz/PM/DataModel/DirectLoginFormValue.js",
|
||||||
"Clipperz/PM/DataModel/OneTimePassword.js",
|
"Clipperz/PM/DataModel/OneTimePassword.js",
|
||||||
|
|
||||||
|
"Clipperz/PM/DataModel/DevicePreferences.js",
|
||||||
|
|
||||||
"-- Clipperz/PM/UI/Web/Components/BaseComponent.js",
|
"-- Clipperz/PM/UI/Web/Components/BaseComponent.js",
|
||||||
"-- Clipperz/PM/UI/Web/Components/Overlay.js",
|
"-- Clipperz/PM/UI/Web/Components/Overlay.js",
|
||||||
"-- Clipperz/PM/UI/Web/Components/LoginForm.js",
|
"-- Clipperz/PM/UI/Web/Components/LoginForm.js",
|
||||||
@@ -118,11 +124,13 @@
|
|||||||
"-- Clipperz/PM/UI/Web/Controllers/MainController.js",
|
"-- Clipperz/PM/UI/Web/Controllers/MainController.js",
|
||||||
|
|
||||||
"Clipperz/PM/UI/Components/Overlay.js",
|
"Clipperz/PM/UI/Components/Overlay.js",
|
||||||
|
"Clipperz/PM/UI/Components/Checkbox.js",
|
||||||
"Clipperz/PM/UI/Components/PageTemplate.js",
|
"Clipperz/PM/UI/Components/PageTemplate.js",
|
||||||
"Clipperz/PM/UI/Components/LoginForm.js",
|
"Clipperz/PM/UI/Components/LoginForm.js",
|
||||||
"Clipperz/PM/UI/Components/RegistrationWizard.js",
|
"Clipperz/PM/UI/Components/RegistrationWizard.js",
|
||||||
"Clipperz/PM/UI/Components/CardList.js",
|
"Clipperz/PM/UI/Components/CardList.js",
|
||||||
"Clipperz/PM/UI/Components/CardDetail.js",
|
"Clipperz/PM/UI/Components/CardDetail.js",
|
||||||
|
"Clipperz/PM/UI/Components/PreferencePage.js",
|
||||||
"Clipperz/PM/UI/Components/ErrorPage.js",
|
"Clipperz/PM/UI/Components/ErrorPage.js",
|
||||||
|
|
||||||
"Clipperz/PM/UI/MainController.js",
|
"Clipperz/PM/UI/MainController.js",
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
CACHE MANIFEST
|
||||||
|
# 2013-10-01:v0.0.1
|
||||||
|
|
||||||
|
CACHE:
|
||||||
|
# - Explicitly cached 'master entries'.
|
||||||
|
index.html
|
||||||
|
|
||||||
|
NETWORK:
|
||||||
|
# - Resources that require the user to be online.
|
||||||
|
#login.php
|
||||||
|
#/myapi
|
||||||
|
#http://api.twitter.com
|
||||||
|
|
||||||
|
FALLBACK:
|
||||||
|
# - static.html will be served if main.py is inaccessible
|
||||||
|
# - offline.jpg will be served in place of all images in images/large/
|
||||||
|
# - offline.html will be served in place of all other .html files
|
||||||
|
# /main.py /static.html
|
||||||
|
# images/large/ images/offline.jpg
|
||||||
|
# *.html /offline.html
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Clipperz",
|
|
||||||
"description": "Keep it to yourself: store and manage your password and online credentials",
|
|
||||||
"launch_path": "/delta/index.html",
|
|
||||||
"icons": {
|
|
||||||
"16": "https://www.clipperz.com/manifests/logo/16.png",
|
|
||||||
"32": "https://www.clipperz.com/manifests/logo/32.png",
|
|
||||||
"30": "https://www.clipperz.com/manifests/logo/30.png",
|
|
||||||
"60": "https://www.clipperz.com/manifests/logo/60.png",
|
|
||||||
"128": "https://www.clipperz.com/manifests/logo/128.png"
|
|
||||||
},
|
|
||||||
"developer": {
|
|
||||||
"name": "Clipperz",
|
|
||||||
"url": "https://www.clipperz.com"
|
|
||||||
},
|
|
||||||
"default_locale": "en"
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
@import "web/overlay";
|
@import "web/overlay";
|
||||||
@import "web/behavior";
|
@import "web/behavior";
|
||||||
@import "web/style";
|
@import "web/style";
|
||||||
|
@import "web/checkbox";
|
||||||
@import "web/480";
|
@import "web/480";
|
||||||
@import "web/768";
|
@import "web/768";
|
||||||
@import "web/992";
|
@import "web/992";
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// https://github.com/h5bp/Effeckt.css
|
// https://github.com/h5bp/Effeckt.css
|
||||||
|
|
||||||
|
|
||||||
.slide () {
|
@mixin slide () {
|
||||||
-webkit-transform: translate3d(0, 0, 0);
|
-webkit-transform: translate3d(0, 0, 0);
|
||||||
transform: translate3d(0, 0, 0);
|
transform: translate3d(0, 0, 0);
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
.slide();
|
@include slide();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
div.checkbox {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
@include border-radius(4px);
|
||||||
|
border: 2px solid white;
|
||||||
|
background-color: white;
|
||||||
|
width: 80px;
|
||||||
|
position: relative;
|
||||||
|
height: 32px;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: "ON";
|
||||||
|
padding-left: 9px;
|
||||||
|
line-height: 32px;
|
||||||
|
color: $solarize-Accent-Cyan;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: "OFF";
|
||||||
|
// padding-left: 12px;
|
||||||
|
padding-left: 25px;
|
||||||
|
line-height: 32px;
|
||||||
|
color: $solarize-Accent-Cyan;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
label.check {
|
||||||
|
display: block;
|
||||||
|
width: 40px;
|
||||||
|
height: 30px;
|
||||||
|
@include border-radius(3px);
|
||||||
|
background-color: $solarize-Accent-Magenta;
|
||||||
|
border: 1px solid $solarize-Accent-Magenta;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
input[type=checkbox] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=checkbox]:checked + label.check {
|
||||||
|
top: 0px;
|
||||||
|
left: 38px;
|
||||||
|
@include animation(labelON, .2s, ease-in, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=checkbox] + label.check {
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
@include animation(labelOFF, .2s, ease-in, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
label.info {
|
||||||
|
position: absolute;
|
||||||
|
color: white;
|
||||||
|
top: 0px;
|
||||||
|
left: 100px;
|
||||||
|
line-height: 32px;
|
||||||
|
width: 200px;
|
||||||
|
font-size: 16pt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include keyframes(labelON) {
|
||||||
|
0% {
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
top: 0px;
|
||||||
|
left: 38px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include keyframes(labelOFF) {
|
||||||
|
0% {
|
||||||
|
top: 0px;
|
||||||
|
left: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
// --------------------------------------------------
|
||||||
|
// Flexbox LESS mixins
|
||||||
|
// The spec: http://www.w3.org/TR/css3-flexbox
|
||||||
|
//
|
||||||
|
// Other info:
|
||||||
|
// - http://philipwalton.github.io/solved-by-flexbox/
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
// Flexbox display
|
||||||
|
// flex or inline-flex
|
||||||
|
.flex-display(@display: flex) {
|
||||||
|
display: ~"-webkit-@{display}";
|
||||||
|
display: ~"-moz-@{display}";
|
||||||
|
display: ~"-ms-@{display}box"; // IE10 uses -ms-flexbox
|
||||||
|
display: ~"-ms-@{display}"; // IE11
|
||||||
|
display: @display;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The 'flex' shorthand
|
||||||
|
// - applies to: flex items
|
||||||
|
// <positive-number>, initial, auto, or none
|
||||||
|
.flex(@columns: initial) {
|
||||||
|
-webkit-flex: @columns;
|
||||||
|
-moz-flex: @columns;
|
||||||
|
-ms-flex: @columns;
|
||||||
|
flex: @columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flex Flow Direction
|
||||||
|
// - applies to: flex containers
|
||||||
|
// row | row-reverse | column | column-reverse
|
||||||
|
.flex-direction(@direction: row) {
|
||||||
|
-webkit-flex-direction: @direction;
|
||||||
|
-moz-flex-direction: @direction;
|
||||||
|
-ms-flex-direction: @direction;
|
||||||
|
flex-direction: @direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flex Line Wrapping
|
||||||
|
// - applies to: flex containers
|
||||||
|
// nowrap | wrap | wrap-reverse
|
||||||
|
.flex-wrap(@wrap: nowrap) {
|
||||||
|
-webkit-flex-wrap: @wrap;
|
||||||
|
-moz-flex-wrap: @wrap;
|
||||||
|
-ms-flex-wrap: @wrap;
|
||||||
|
flex-wrap: @wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flex Direction and Wrap
|
||||||
|
// - applies to: flex containers
|
||||||
|
// <flex-direction> || <flex-wrap>
|
||||||
|
.flex-flow(@flow) {
|
||||||
|
-webkit-flex-flow: @flow;
|
||||||
|
-moz-flex-flow: @flow;
|
||||||
|
-ms-flex-flow: @flow;
|
||||||
|
flex-flow: @flow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display Order
|
||||||
|
// - applies to: flex items
|
||||||
|
// <integer>
|
||||||
|
.flex-order(@order: 0) {
|
||||||
|
-webkit-order: @order;
|
||||||
|
-moz-order: @order;
|
||||||
|
-ms-order: @order;
|
||||||
|
order: @order;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flex grow factor
|
||||||
|
// - applies to: flex items
|
||||||
|
// <number>
|
||||||
|
.flex-grow(@grow: 0) {
|
||||||
|
-webkit-flex-grow: @grow;
|
||||||
|
-moz-flex-grow: @grow;
|
||||||
|
-ms-flex-grow: @grow;
|
||||||
|
flex-grow: @grow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flex shr
|
||||||
|
// - applies to: flex itemsink factor
|
||||||
|
// <number>
|
||||||
|
.flex-shrink(@shrink: 1) {
|
||||||
|
-webkit-flex-shrink: @shrink;
|
||||||
|
-moz-flex-shrink: @shrink;
|
||||||
|
-ms-flex-shrink: @shrink;
|
||||||
|
flex-shrink: @shrink;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flex basis
|
||||||
|
// - the initial main size of the flex item
|
||||||
|
// - applies to: flex itemsnitial main size of the flex item
|
||||||
|
// <width>
|
||||||
|
.flex-basis(@width: auto) {
|
||||||
|
-webkit-flex-basis: @width;
|
||||||
|
-moz-flex-basis: @width;
|
||||||
|
-ms-flex-basis: @width;
|
||||||
|
flex-basis: @width;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Axis Alignment
|
||||||
|
// - applies to: flex containers
|
||||||
|
// flex-start | flex-end | center | space-between | space-around
|
||||||
|
.justify-content(@justify: flex-start) {
|
||||||
|
-webkit-justify-content: @justify;
|
||||||
|
-moz-justify-content: @justify;
|
||||||
|
-ms-justify-content: @justify;
|
||||||
|
justify-content: @justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Packing Flex Lines
|
||||||
|
// - applies to: multi-line flex containers
|
||||||
|
// flex-start | flex-end | center | space-between | space-around | stretch
|
||||||
|
.align-content(@align: stretch) {
|
||||||
|
-webkit-align-content: @align;
|
||||||
|
-moz-align-content: @align;
|
||||||
|
-ms-align-content: @align;
|
||||||
|
align-content: @align;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cross-axis Alignment
|
||||||
|
// - applies to: flex containers
|
||||||
|
// flex-start | flex-end | center | baseline | stretch
|
||||||
|
.align-items(@align: stretch) {
|
||||||
|
-webkit-align-items: @align;
|
||||||
|
-moz-align-items: @align;
|
||||||
|
-ms-align-items: @align;
|
||||||
|
align-items: @align;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cross-axis Alignment
|
||||||
|
// - applies to: flex items
|
||||||
|
// auto | flex-start | flex-end | center | baseline | stretch
|
||||||
|
.align-self(@align: auto) {
|
||||||
|
-webkit-align-self: @align;
|
||||||
|
-moz-align-self: @align;
|
||||||
|
-ms-align-self: @align;
|
||||||
|
align-self: @align;
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
@mixin border-radius ($radius) {
|
||||||
|
border-radius: $radius;
|
||||||
|
-moz-border-radius: $radius;
|
||||||
|
-webkit-border-radius: $radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin font-feature-settings($foo, $bar) {
|
||||||
|
-webkit-font-feature-settings:"$foo","$bar";
|
||||||
|
-moz-font-feature-settings:"$foo=1, $bar=1";
|
||||||
|
-moz-font-feature-settings:"$foo","$bar";
|
||||||
|
-ms-font-feature-settings:"$foo","$bar";
|
||||||
|
-o-font-feature-settings:"$foo","$bar";
|
||||||
|
font-feature-settings:"$foo","$bar";
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin icon-font() {
|
||||||
|
font-family: 'clipperz-icons';
|
||||||
|
@include font-feature-settings("liga", "dlig");
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
text-rendering:optimizeLegibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin password-font() {
|
||||||
|
font-family: 'clipperz-password';
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
text-rendering:optimizeLegibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin animation ($animation, $duration, $timing-function:linear, $iteration-count:1, $fill-mode:none) {
|
||||||
|
-webkit-animation-name: $animation;
|
||||||
|
-webkit-animation-duration: $duration;
|
||||||
|
-webkit-animation-timing-function: $timing-function;
|
||||||
|
-webkit-animation-iteration-count: $iteration-count;
|
||||||
|
-webkit-animation-fill-mode: $fill-mode;
|
||||||
|
|
||||||
|
-moz-animation-name: $animation;
|
||||||
|
-moz-animation-duration: $duration;
|
||||||
|
-moz-animation-timing-function: $timing-function;
|
||||||
|
-moz-animation-iteration-count: $iteration-count;
|
||||||
|
-moz-animation-fill-mode: $fill-mode;
|
||||||
|
|
||||||
|
-ms-animation-name: $animation;
|
||||||
|
-ms-animation-duration: $duration;
|
||||||
|
-ms-animation-timing-function: $timing-function;
|
||||||
|
-ms-animation-iteration-count: $iteration-count;
|
||||||
|
-ms-animation-fill-mode: $fill-mode;
|
||||||
|
|
||||||
|
-o-animation-name: $animation;
|
||||||
|
-o-animation-duration: $duration;
|
||||||
|
-o-animation-timing-function: $timing-function;
|
||||||
|
-o-animation-iteration-count: $iteration-count;
|
||||||
|
-o-animation-fill-mode: $fill-mode;
|
||||||
|
|
||||||
|
animation-name: $animation;
|
||||||
|
animation-duration: $duration;
|
||||||
|
animation-timing-function: $timing-function;
|
||||||
|
animation-iteration-count: $iteration-count;
|
||||||
|
animation-fill-mode: $fill-mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin transition ($item, $time, $function) {
|
||||||
|
-webkit-transition: $item $time $function;
|
||||||
|
-moz-transition: $item $time $function;
|
||||||
|
-o-transition: $item $time $function;
|
||||||
|
-ms-transition: $item $time $function;
|
||||||
|
transition: $item $time $function;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin transform ($rotateAngle, $translateX, $translateY) {
|
||||||
|
-webkit-transform: rotate( $rotateAngle) translate($translateX, $translateY);
|
||||||
|
-moz-transform: rotate( $rotateAngle) translate($translateX, $translateY);
|
||||||
|
-ms-transform: rotate( $rotateAngle) translate($translateX, $translateY);
|
||||||
|
-o-transform: rotate( $rotateAngle) translate($translateX, $translateY);
|
||||||
|
transform: rotate( $rotateAngle) translate($translateX, $translateY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@mixin animation-delay ($delay) {
|
||||||
|
-webkit-animation-delay: $delay;
|
||||||
|
-moz-animation-delay: $delay;
|
||||||
|
-ms-animation-delay: $delay;
|
||||||
|
-o-animation-delay: $delay;
|
||||||
|
animation-delay: $delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin box-shadow ($xOffset, $yOffset, $size, $color) {
|
||||||
|
-webkit-box-shadow: $xOffset $yOffset $size $color;
|
||||||
|
-moz-box-shadow: $xOffset $yOffset $size $color;
|
||||||
|
-ms-box-shadow: $xOffset $yOffset $size $color;
|
||||||
|
-o-box-shadow: $xOffset $yOffset $size $color;
|
||||||
|
box-shadow: $xOffset $yOffset $size $color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin keyframes($name) {
|
||||||
|
@-webkit-keyframes #{$name} {
|
||||||
|
@content;
|
||||||
|
}
|
||||||
|
@-moz-keyframes #{$name} {
|
||||||
|
@content;
|
||||||
|
}
|
||||||
|
@-ms-keyframes #{$name} {
|
||||||
|
@content;
|
||||||
|
}
|
||||||
|
@keyframes #{$name} {
|
||||||
|
@content;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
@import "mixin";
|
||||||
|
|
||||||
|
div.overlay {
|
||||||
|
z-index: 99999;
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
margin-left: -100px;
|
||||||
|
margin-top: -100px;
|
||||||
|
background: rgba(0,0,0,0.8);
|
||||||
|
@include border-radius(20px);
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: #FFF;
|
||||||
|
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
display: block;
|
||||||
|
font-size: 26px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 30px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 128px;
|
||||||
|
height: 128px;
|
||||||
|
top: 40%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -64px;
|
||||||
|
margin-top: -64px;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
@include icon-font();
|
||||||
|
font-size: 96pt;
|
||||||
|
color: white;
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ios-overlay-show {
|
||||||
|
@include animation(ios-overlay-show, 750ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
&.ios-overlay-hide {
|
||||||
|
@include animation(ios-overlay-hide, 750ms, linear, 1, forwards);
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://37signals.com/svn/posts/2577-loading-spinner-animation-using-css-and-webkit
|
||||||
|
div.spinner {
|
||||||
|
position: relative;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
left: 50% !important;
|
||||||
|
top: 40% !important;
|
||||||
|
|
||||||
|
margin-left: -50px;
|
||||||
|
margin-top: -50px;
|
||||||
|
|
||||||
|
// display: inline-block;
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
div {
|
||||||
|
width: 12%;
|
||||||
|
height: 26%;
|
||||||
|
background: #ffffff;
|
||||||
|
position: absolute;
|
||||||
|
left: 44.5%;
|
||||||
|
top: 37%;
|
||||||
|
opacity: 0;
|
||||||
|
@include animation(overlay-spin, 1s, linear, infinite);
|
||||||
|
@include border-radius(50px);
|
||||||
|
@include box-shadow(0, 0, 3px, rgba(0,0,0,0.2));
|
||||||
|
}
|
||||||
|
|
||||||
|
div.bar01 {@include transform( 0deg, 0, -142%); @include animation-delay(-0.00000s);}
|
||||||
|
div.bar02 {@include transform( 30deg, 0, -142%); @include animation-delay(-0.91670s);}
|
||||||
|
div.bar03 {@include transform( 60deg, 0, -142%); @include animation-delay(-0.83300s);}
|
||||||
|
div.bar04 {@include transform( 90deg, 0, -142%); @include animation-delay(-0.75000s);}
|
||||||
|
div.bar05 {@include transform(120deg, 0, -142%); @include animation-delay(-0.66700s);}
|
||||||
|
div.bar06 {@include transform(150deg, 0, -142%); @include animation-delay(-0.58330s);}
|
||||||
|
div.bar07 {@include transform(180deg, 0, -142%); @include animation-delay(-0.50000s);}
|
||||||
|
div.bar08 {@include transform(210deg, 0, -142%); @include animation-delay(-0.41667s);}
|
||||||
|
div.bar09 {@include transform(240deg, 0, -142%); @include animation-delay(-0.33300s);}
|
||||||
|
div.bar10 {@include transform(270deg, 0, -142%); @include animation-delay(-0.25000s);}
|
||||||
|
div.bar11 {@include transform(300deg, 0, -142%); @include animation-delay(-0.16670s);}
|
||||||
|
div.bar12 {@include transform(330deg, 0, -142%); @include animation-delay(-0.08330s);}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//========================================================
|
||||||
|
|
||||||
|
@include keyframes(overlay-spin) {
|
||||||
|
from {opacity: 1;}
|
||||||
|
to {opacity: 0.25;}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include keyframes(ios-overlay-show) {
|
||||||
|
0% { opacity: 0; }
|
||||||
|
100% { opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@include keyframes(ios-overlay-hide) {
|
||||||
|
0% { opacity: 1; }
|
||||||
|
100% { opacity: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
//========================================================
|
||||||
File diff suppressed because one or more lines are too long
@@ -10,7 +10,14 @@ class DeltaBuilder(FrontendBuilder):
|
|||||||
return ['js', 'css']
|
return ['js', 'css']
|
||||||
|
|
||||||
def copyStaticResources (self, targetFolder):
|
def copyStaticResources (self, targetFolder):
|
||||||
pass
|
resourcesToCopy = [
|
||||||
|
{'folder': 'properties', 'source': 'manifest.appcache', 'target': 'manifest.appcache'}
|
||||||
|
]
|
||||||
|
|
||||||
|
for resource in resourcesToCopy:
|
||||||
|
src = self.absolutePathForSourceFile(resource['folder'], resource['source'])
|
||||||
|
dst = self.absolutePathForTargetFile(targetFolder, '', resource['target'])
|
||||||
|
shutil.copy2(src, dst)
|
||||||
|
|
||||||
def bookmarklet (self):
|
def bookmarklet (self):
|
||||||
return ""
|
return ""
|
||||||
@@ -48,6 +48,10 @@ class ClipperzTestSite(server.Site):
|
|||||||
# absoluteFilePath = os.path.join(projectTargetDir(), 'dev', version, pathParts[2])
|
# absoluteFilePath = os.path.join(projectTargetDir(), 'dev', version, pathParts[2])
|
||||||
absoluteFilePath = os.path.join(projectBaseDir(), 'frontend', version, 'properties', pathParts[2])
|
absoluteFilePath = os.path.join(projectBaseDir(), 'frontend', version, 'properties', pathParts[2])
|
||||||
result = static.File(absoluteFilePath, contentType)
|
result = static.File(absoluteFilePath, contentType)
|
||||||
|
elif pathParts[2].endswith('.appcache'):
|
||||||
|
contentType = 'text/cache-manifest'
|
||||||
|
absoluteFilePath = os.path.join(projectBaseDir(), 'frontend', version, 'properties', pathParts[2])
|
||||||
|
result = static.File(absoluteFilePath, contentType)
|
||||||
else:
|
else:
|
||||||
# http://homer.local:8888/beta/css/clipperz/images/loginInfoBackground.png
|
# http://homer.local:8888/beta/css/clipperz/images/loginInfoBackground.png
|
||||||
# pathParts: ['', 'beta', 'css', 'clipperz', 'images', 'loginInfoBackground.png']
|
# pathParts: ['', 'beta', 'css', 'clipperz', 'images', 'loginInfoBackground.png']
|
||||||
@@ -93,6 +97,7 @@ class ClipperzTestSite(server.Site):
|
|||||||
|
|
||||||
def main ():
|
def main ():
|
||||||
site = ClipperzTestSite(proxy.ReverseProxyResource('localhost', 8080, '/java-backend'))
|
site = ClipperzTestSite(proxy.ReverseProxyResource('localhost', 8080, '/java-backend'))
|
||||||
|
# site = ClipperzTestSite(proxy.ReverseProxyResource('www.clipperz.com', 443, '/'))
|
||||||
reactor.listenTCP(8888, site)
|
reactor.listenTCP(8888, site)
|
||||||
reactor.run()
|
reactor.run()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user