+ {{/each}}
+
+ {{/if}}
{{/if}}
+var VERSION="2013-09-13-155304"
@@ -3316,7 +3352,9 @@ var lang=(navigator.language)?navigator.language:navigator.userLanguage;window.l
+"this email into another asset as well.","_pop_successor":"Select a legal successor. You may use the default in which case the person selected by succesion or "
+"your general testament would receive this orders. Or enter a legal successor and select it here.","_pop_order":"Select how your successor has to manage the network asset. You may add complemental informations "
+"into the notes field below.","_aboutmenu":"About Digiproof","_about":"This is DigiProof, a JavaScript App to create a digital testament by Thomas Linden. Copyright (c) 2013. "
-+"Licensed under the terms of the General Public License Version 2."},"de":{"_successors":"Rechtsnachfolger","_successor":"Rechtsnachfolger","_addsuccessor":"Rechtsnachfolger Hinzufügen","_substitute":"Ersatzrechtsnachfolger","_assets":"Netzaccounts","_asset":"Netzaccount","_addasset":"Netzaccount hinzufügen","_add":"neu","_name":"Bezeichnung","_uri":"URL","_login":"Benutzername","_pass":"Passwort","_mail":"E-Mail","_ordered":"wird beauftragt","_preordered":"Der Rechtsnachfolger wird beauftragt, den Netzaccount","_postordered":"","_save":"Speichern","_savenext":"Speichern und Fortfahren","_cancel":"Abbrechen","_edit":"Bearbeiten","_remove":"Entfernen","_notes":"Besondere Hinweise","_birth":"Geburtsdatum","_testament":"Testament Anschauen","_address":"Adresse","_print":"Dies ist das vollständige digitale Testament.","_doprint":"Ausdrucken","_ttitle":"Mein digitales Testament","_appoint1":"Hiermit bestimme ich, ","_appoint2":", im Vollbesitz meiner geistigen Kräfte, die folgende Person als Rechtsnachfolger "
++"Licensed under the terms of the General Public License Version 2.","_devel":"Caution! This is the development version of DigiProof. It stores data to local disk using the browsers "
++"localStorage feature. So, whatever you enter, persists over sessions, is unencrypted and can be viewed by anyone "
++"with access to this device. Use for testing/developing purposes only and don't ever enter production account informations!"},"de":{"_successors":"Rechtsnachfolger","_successor":"Rechtsnachfolger","_addsuccessor":"Rechtsnachfolger Hinzufügen","_substitute":"Ersatzrechtsnachfolger","_assets":"Netzaccounts","_asset":"Netzaccount","_addasset":"Netzaccount hinzufügen","_add":"neu","_name":"Bezeichnung","_uri":"URL","_login":"Benutzername","_pass":"Passwort","_mail":"E-Mail","_ordered":"wird beauftragt","_preordered":"Der Rechtsnachfolger wird beauftragt, den Netzaccount","_postordered":"","_save":"Speichern","_savenext":"Speichern und Fortfahren","_cancel":"Abbrechen","_edit":"Bearbeiten","_remove":"Entfernen","_notes":"Besondere Hinweise","_birth":"Geburtsdatum","_testament":"Testament Anschauen","_address":"Adresse","_print":"Dies ist das vollständige digitale Testament.","_doprint":"Ausdrucken","_ttitle":"Mein digitales Testament","_appoint1":"Hiermit bestimme ich, ","_appoint2":", im Vollbesitz meiner geistigen Kräfte, die folgende Person als Rechtsnachfolger "
+"für die aufgeführten Netzwerkaccounts nach meinem Tode:","_appoint3":"Falls die oben aufgeführte Person nicht mehr leben sollte "
+"oder unauffindbar sein, so soll dies der Ersatzrechtsnachfolger "
+"sein:","_successorshall":"Mein Rechtsnachfolger soll sich um die im folgenden "
@@ -3345,7 +3383,10 @@ var lang=(navigator.language)?navigator.language:navigator.userLanguage;window.l
+"regulärer Erbe (bestimmt durch gesetzliche Erbfolge oder anderweitig durch Testament) diese Anweisungen erhalten. "
+"Oder Sie geben einen speziellen Rechtsnachfolger ein und wählen diesen hier aus.","_pop_order":"Bestimmen Sie, wie Ihr Rechtsnachfolger mit dem Netzwerkaccount umgehen soll. Sie können im Notizfeld "
+"dazugehörige Ergänzungen hinzufügen.","_aboutmenu":"Über Digiproof","_about":"Dies ist DigiProof, eine Javascript App zum Erstellen eines digitalen Testaments von Thomas Linden. Copyright (c) 2013. "
-+"Veröffentlicht unter der General Public License Version 2."}};function translate(key){var locale=window.locale[lang]||window.locale['en-US'];if(key){if(key in locale){return locale[key];}
++"Veröffentlicht unter der General Public License Version 2.","_devel":"Achtung! Dies ist die Entwicklerversion von DigiProof. Eingegebene Daten werden auf der lokalen Festplatte "
++"unter Verwendung des localStorage Features Ihres Browsers gespeichert. Was immer Sie eingeben, bleibt über Browsersitzungen "
++"hinweg erhalten, ist nicht verschlüsselt und kann von jedem mit Zugriff auf das System gelesen werden. Verwenden Sie "
++"diese Version ausschliesslich für Test- oder Entwicklungszwecke und geben Sie niemals echte Accountinformationen ein!"}};function translate(key){var locale=window.locale[lang]||window.locale['en-US'];if(key){if(key in locale){return locale[key];}
else{return'__UNTRANSLATED_STRING__('+key+')';}}
else{return'';}}
+App.IndexController=Ember.Controller.extend({has_self:App.Self.find(),has_asset:App.Asset.find(),has_successor:App.Successor.find(),isDevel:isDevel,VERSION:VERSION});App.NavView=Ember.View.extend({tagName:'li',classNameBindings:'active'.w(),didInsertElement:function(){this._super();var _this=this;this.get('parentView').on('click',function(){_this.notifyPropertyChange('active');});},active:function(){return this.get('childViews.firstObject.active');}.property()});
+
@@ -776,7 +788,31 @@
{{else}}
-
{{clear}}
+ {{#if failed}}
+
{{clear}}
+ {{else}}
+
+
{{loc _self}}:
+
{{self.name}}
+
{{clear}}
+
+
+ {{#each successor in successors}}
+
+
{{loc _successor}}:
+
{{successor.name}}
+
{{clear}}
+
+ {{/each}}
+ {{#each asset in assets}}
+
+
{{loc _asset}}:
+
{{asset.name}}
+
{{clear}}
+
+ {{/each}}
+
+ {{/if}}
{{/if}}
@@ -784,7 +820,6 @@
@@ -793,7 +828,7 @@
-
+
@@ -817,6 +852,7 @@
+
diff --git a/js/apphelpers.js b/js/apphelpers.js
index 3d3797e..a208ba7 100644
--- a/js/apphelpers.js
+++ b/js/apphelpers.js
@@ -74,3 +74,4 @@ function decode64(input) {
return unescape(output);
}
+
diff --git a/js/confirm.js b/js/confirm.js
new file mode 100644
index 0000000..a385428
--- /dev/null
+++ b/js/confirm.js
@@ -0,0 +1,21 @@
+
+function confirminit() {
+ window.onbeforeunload = function(e) {
+ if(window.confirmExit) return confirmExit();
+ };
+}
+
+var hadConfirmExit = false;
+function checkUnsavedChanges() {
+ if(App.store && App.store.isDirty && window.hadConfirmExit === false) {
+ if(confirm("unsafed changes"))
+ saveChanges();
+ }
+}
+
+function confirmExit() {
+ hadConfirmExit = true;
+ if(App.store && App.store.isDirty) {
+ return "ok";
+ }
+}
diff --git a/js/controllers_application.js b/js/controllers_application.js
new file mode 100644
index 0000000..66347e3
--- /dev/null
+++ b/js/controllers_application.js
@@ -0,0 +1,7 @@
+
+App.ApplicationController = Ember.Controller.extend({
+ isDevel: isDevel,
+ VERSION: VERSION
+});
+
+
diff --git a/js/controllers_data.js b/js/controllers_data.js
index 8da18ce..18db3c3 100644
--- a/js/controllers_data.js
+++ b/js/controllers_data.js
@@ -126,6 +126,7 @@ App.UploadFileView = Ember.TextField.extend({
App.DataImportController = Ember.ObjectController.extend({
isEditing: true,
clear: '',
+ failed: false,
errors: {},
doneEditing: function() {
@@ -197,6 +198,15 @@ App.DataImportController = Ember.ObjectController.extend({
// suck it in
ImportJSON(importobj, pass);
this.set('clear', translate('_importdone'));
+ var isuccessors = [];
+ $.each(importobj.successors, function(index, obj) {
+ if(obj.id != '0') {
+ isuccessors.pushObject(obj);
+ }
+ });
+ this.set('successors', isuccessors);
+ this.set('assets', importobj.assets);
+ this.set('self', importobj.self);
}
else {
throw 'decrypted variable $json doesnt contain anything, weird';
@@ -205,12 +215,14 @@ App.DataImportController = Ember.ObjectController.extend({
catch (e) {
// console.log("decryption exception: %o", e);
this.set('clear', translate('_error_decrypt') + " (" + e + ")");
+ this.set('failed', true);
}
}
else {
// no password given
this.set('isEditing', true);
this.set('errors', validated);
+ this.set('failed', true);
this.set('clear', translate('_error_decrypt'));
}
},
diff --git a/js/controllers_index.js b/js/controllers_index.js
index 9daf94f..2f42fc5 100644
--- a/js/controllers_index.js
+++ b/js/controllers_index.js
@@ -3,6 +3,7 @@ App.IndexController = Ember.Controller.extend({
has_self: App.Self.find(),
has_asset: App.Asset.find(),
has_successor: App.Successor.find(),
+ isDevel: isDevel,
VERSION: VERSION
});
diff --git a/js/libs/localstorage_adapter.js b/js/libs/localstorage_adapter_dev.js
similarity index 99%
rename from js/libs/localstorage_adapter.js
rename to js/libs/localstorage_adapter_dev.js
index 79d88cd..75c00af 100644
--- a/js/libs/localstorage_adapter.js
+++ b/js/libs/localstorage_adapter_dev.js
@@ -1,3 +1,5 @@
+var isDevel = true;
+
DS.LSSerializer = DS.JSONSerializer.extend({
addBelongsTo: function(data, record, key, association) {
diff --git a/js/libs/localstorage_adapter_prod.js b/js/libs/localstorage_adapter_prod.js
new file mode 100644
index 0000000..edff68e
--- /dev/null
+++ b/js/libs/localstorage_adapter_prod.js
@@ -0,0 +1,238 @@
+var isDevel = false;
+
+/*
+ * in the production actual saving to browser
+ * storage on disk is disabled here by overwriting
+ * the setItem and getItem function with dummies,
+ * which hold the data in memory only.
+ */
+localStorage.setItem = function(namespace, json) {
+ this.set('_fakestore') = { namespace: json };
+ return this;
+}
+
+localStorage.getItem = function(namespace) {
+ return this.get('_fakestore').namespace;
+}
+
+DS.LSSerializer = DS.JSONSerializer.extend({
+
+ addBelongsTo: function(data, record, key, association) {
+ data[key] = record.get(key + '.id');
+ },
+
+ addHasMany: function(data, record, key, association) {
+ data[key] = record.get(key).map(function(record) {
+ return record.get('id');
+ });
+ },
+
+ // extract expects a root key, we don't want to save all these keys to
+ // localStorage so we generate the root keys here
+ extract: function(loader, json, type, record) {
+ this._super(loader, this.rootJSON(json, type), type, record);
+ },
+
+ extractMany: function(loader, json, type, records) {
+ this._super(loader, this.rootJSON(json, type, 'pluralize'), type, records);
+ },
+
+ rootJSON: function(json, type, pluralize) {
+ var root = this.rootForType(type);
+ if (pluralize == 'pluralize') { root = this.pluralize(root); }
+ var rootedJSON = {};
+ rootedJSON[root] = json;
+ return rootedJSON;
+ }
+
+});
+
+DS.LSAdapter = DS.Adapter.extend(Ember.Evented, {
+
+ init: function() {
+ this._loadData();
+ },
+
+ generateIdForRecord: function() {
+ return Math.random().toString(32).slice(2).substr(0,5);
+ },
+
+ serializer: DS.LSSerializer.create(),
+
+ find: function(store, type, id) {
+ var namespace = this._namespaceForType(type);
+ this._async(function(){
+ var copy = Ember.copy(namespace.records[id]);
+ this.didFindRecord(store, type, copy, id);
+ });
+ },
+
+ findMany: function(store, type, ids) {
+ var namespace = this._namespaceForType(type);
+ this._async(function(){
+ var results = [];
+ for (var i = 0; i < ids.length; i++) {
+ results.push(Ember.copy(namespace.records[ids[i]]));
+ }
+ this.didFindMany(store, type, results);
+ });
+ },
+
+ // Supports queries that look like this:
+ //
+ // {
+ // : ,
+ // ...
+ // }
+ //
+ // Every property added to the query is an "AND" query, not "OR"
+ //
+ // Example:
+ //
+ // match records with "complete: true" and the name "foo" or "bar"
+ //
+ // { complete: true, name: /foo|bar/ }
+ findQuery: function(store, type, query, recordArray) {
+ var namespace = this._namespaceForType(type);
+ this._async(function() {
+ var results = this.query(namespace.records, query);
+ this.didFindQuery(store, type, results, recordArray);
+ });
+ },
+
+ query: function(records, query) {
+ var results = [];
+ var id, record, property, test, push;
+ for (id in records) {
+ record = records[id];
+ for (property in query) {
+ test = query[property];
+ push = false;
+ if (Object.prototype.toString.call(test) == '[object RegExp]') {
+ push = test.test(record[property]);
+ } else {
+ push = record[property] === test;
+ }
+ }
+ if (push) {
+ results.push(record);
+ }
+ }
+ return results;
+ },
+
+ findAll: function(store, type) {
+ var namespace = this._namespaceForType(type);
+ this._async(function() {
+ var results = [];
+ for (var id in namespace.records) {
+ results.push(Ember.copy(namespace.records[id]));
+ }
+ this.didFindAll(store, type, results);
+ });
+ },
+
+ createRecords: function(store, type, records) {
+ var namespace = this._namespaceForType(type);
+ records.forEach(function(record) {
+ this._addRecordToNamespace(namespace, record);
+ }, this);
+ this._async(function() {
+ this._didSaveRecords(store, type, records);
+ });
+ },
+
+ updateRecords: function(store, type, records) {
+ var namespace = this._namespaceForType(type);
+ this._async(function() {
+ records.forEach(function(record) {
+ var id = record.get('id');
+ namespace.records[id] = record.serialize({includeId:true});
+ }, this);
+ this._didSaveRecords(store, type, records);
+ });
+ },
+
+ deleteRecords: function(store, type, records) {
+ var namespace = this._namespaceForType(type);
+ this._async(function() {
+ records.forEach(function(record) {
+ var id = record.get('id');
+ delete namespace.records[id];
+ });
+ this._didSaveRecords(store, type, records);
+ });
+
+ },
+
+ dirtyRecordsForHasManyChange: function(dirtySet, parent, relationship) {
+ dirtySet.add(parent);
+ },
+
+ dirtyRecordsForBelongsToChange: function(dirtySet, child, relationship) {
+ dirtySet.add(child);
+ },
+
+ // private
+
+ _getNamespace: function() {
+ return this.namespace || 'DS.LSAdapter';
+ },
+
+ _loadData: function() {
+ try {
+ var storage = localStorage.getItem(this._getNamespace());
+ this._data = storage ? JSON.parse(storage) : {};
+ }
+ catch(e) {
+ this._data = {};
+ }
+ },
+
+ _didSaveRecords: function(store, type, records) {
+ var success = this._saveData();
+ if (success) {
+ store.didSaveRecords(records);
+ } else {
+ records.forEach(function(record) {
+ store.recordWasError(record);
+ });
+ this.trigger('QUOTA_EXCEEDED_ERR', records);
+ }
+ },
+
+ _saveData: function() {
+ try {
+ localStorage.setItem(this._getNamespace(), JSON.stringify(this._data));
+ return true;
+ }
+ catch(error) {
+ if (error.name == 'QUOTA_EXCEEDED_ERR') {
+ return false;
+ } else {
+ // IE, Ignore. throw new Error(error);
+ }
+ }
+ },
+
+ _namespaceForType: function(type) {
+ var namespace = type.url || type.toString();
+ return this._data[namespace] || (
+ this._data[namespace] = {records: {}}
+ );
+ },
+
+ _addRecordToNamespace: function(namespace, record) {
+ var data = record.serialize({includeId: true});
+ namespace.records[data.id] = data;
+ },
+
+ _async: function(callback) {
+ var _this = this;
+ setTimeout(function(){
+ Ember.run(_this, callback);
+ }, 1);
+ }
+
+});
+
diff --git a/js/libs/version.js b/js/libs/version.js
index 0d2c708..814532d 100644
--- a/js/libs/version.js
+++ b/js/libs/version.js
@@ -1 +1 @@
-var VERSION = "2013-09-13-080748"
+var VERSION = "2013-09-13-155304"
diff --git a/js/locale.js b/js/locale.js
index 10b84b4..6e24b9d 100644
--- a/js/locale.js
+++ b/js/locale.js
@@ -113,7 +113,10 @@ window.locale = {
+"into the notes field below.",
"_aboutmenu": "About Digiproof",
"_about": "This is DigiProof, a JavaScript App to create a digital testament by Thomas Linden. Copyright (c) 2013. "
- +"Licensed under the terms of the General Public License Version 2."
+ +"Licensed under the terms of the General Public License Version 2.",
+ "_devel": "Caution! This is the development version of DigiProof. It stores data to local disk using the browsers "
+ +"localStorage feature. So, whatever you enter, persists over sessions, is unencrypted and can be viewed by anyone "
+ +"with access to this device. Use for testing/developing purposes only and don't ever enter production account informations!"
},
"de": {
@@ -233,7 +236,11 @@ window.locale = {
+"dazugehörige Ergänzungen hinzufügen.",
"_aboutmenu": "Über Digiproof",
"_about": "Dies ist DigiProof, eine Javascript App zum Erstellen eines digitalen Testaments von Thomas Linden. Copyright (c) 2013. "
- +"Veröffentlicht unter der General Public License Version 2."
+ +"Veröffentlicht unter der General Public License Version 2.",
+ "_devel": "Achtung! Dies ist die Entwicklerversion von DigiProof. Eingegebene Daten werden auf der lokalen Festplatte "
+ +"unter Verwendung des localStorage Features Ihres Browsers gespeichert. Was immer Sie eingeben, bleibt über Browsersitzungen "
+ +"hinweg erhalten, ist nicht verschlüsselt und kann von jedem mit Zugriff auf das System gelesen werden. Verwenden Sie "
+ +"diese Version ausschliesslich für Test- oder Entwicklungszwecke und geben Sie niemals echte Accountinformationen ein!"
}
};
diff --git a/mksingleton.pl b/mksingleton.pl
index 5ceb3d4..c173074 100755
--- a/mksingleton.pl
+++ b/mksingleton.pl
@@ -3,14 +3,14 @@ use Data::Dumper;
use JavaScript::Minifier qw(minify);
use CSS::Compressor qw( css_compress );
-my $index = shift;
+my ($type, $index) = @ARGV;
if (!$index) {
- print STDERR "Usage: $0 \n";
+ print STDERR "Usage: $0 \n";
exit 1;
}
-my $out = "digiproof.html";
+my $out = "digiproof-$type.html";
print STDERR "open index\n";
open I, "<$index" or die "Could not open index: $index $!\n";
@@ -38,6 +38,9 @@ foreach (@source) {
}
elsif (/script src="([^"]*)"/) {
my $jsfile = $1;
+ if ($jsfile =~ /localstorage/) {
+ $jsfile = "js/libs/localstorage_adapter_$type.js";
+ }
print STDERR "Inserting $jsfile\n";
print qq(
- # which leads to rendering failures, those will be fixed here
- $js =~ s/<\/script>/' + Slash + 'script>/g;
- close F;
- return "/* js from $file */\n" . $js;
+ my $js;
+ my $from = "/* js from $file */\n";
+ if ($type eq 'prod') {
+ $js = minify(input => *F);
+ # ember.js (and probably others) contain strings which contain
+ # which leads to rendering failures, those will be fixed here
+ $js =~ s/<\/script>/' + Slash + 'script>/g;
+ close F;
+ return $from . $js;
+ }
+ else {
+ return $from . join '', ;
+ close F;
+ }
}
else {
+ my $from = "/* css from $file */\n";
my $src = join "", ;
close F;
- return "/* css from $file */\n" . css_compress($src);
+ if ($prod) {
+ return $from . $src;
+ }
+ else {
+ return $from . css_compress($src);
+ }
}
}
diff --git a/samples/digiproof1.png b/samples/digiproof1.png
new file mode 100644
index 0000000..4b4ccba
Binary files /dev/null and b/samples/digiproof1.png differ
diff --git a/samples/digiproof10.png b/samples/digiproof10.png
new file mode 100644
index 0000000..7bf068f
Binary files /dev/null and b/samples/digiproof10.png differ
diff --git a/samples/digiproof2.png b/samples/digiproof2.png
new file mode 100644
index 0000000..19d2a42
Binary files /dev/null and b/samples/digiproof2.png differ
diff --git a/samples/digiproof3.png b/samples/digiproof3.png
new file mode 100644
index 0000000..1036630
Binary files /dev/null and b/samples/digiproof3.png differ
diff --git a/samples/digiproof4.png b/samples/digiproof4.png
new file mode 100644
index 0000000..eeb19d5
Binary files /dev/null and b/samples/digiproof4.png differ
diff --git a/samples/digiproof5.png b/samples/digiproof5.png
new file mode 100644
index 0000000..5a0b5ac
Binary files /dev/null and b/samples/digiproof5.png differ
diff --git a/samples/digiproof6.png b/samples/digiproof6.png
new file mode 100644
index 0000000..81f944e
Binary files /dev/null and b/samples/digiproof6.png differ
diff --git a/samples/digiproof7.png b/samples/digiproof7.png
new file mode 100644
index 0000000..dd239f1
Binary files /dev/null and b/samples/digiproof7.png differ
diff --git a/samples/digiproof8.png b/samples/digiproof8.png
new file mode 100644
index 0000000..a7afa0b
Binary files /dev/null and b/samples/digiproof8.png differ
diff --git a/samples/digiproof9.png b/samples/digiproof9.png
new file mode 100644
index 0000000..ccef44e
Binary files /dev/null and b/samples/digiproof9.png differ
diff --git a/samples/sample-testament.pdf b/samples/sample-testament.pdf
new file mode 100644
index 0000000..65c7756
Binary files /dev/null and b/samples/sample-testament.pdf differ