From 101482b8ccf76df848042428f91e7ff5bf7fbb7e Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 9 Nov 2017 14:23:40 +0100 Subject: [PATCH] Migrate settings to use a sandboxed iframe --- customize.dist/messages.js | 86 +-- customize.dist/pages.js | 18 +- .../src/less2/include/sidebar-layout.less | 10 +- customize.dist/src/less2/main.less | 1 + www/common/common-language.js | 81 +++ www/common/cryptpad-common.js | 22 +- www/common/feedback-main.js | 6 +- www/common/fsStore.js | 7 +- www/common/migrate-user-object.js | 17 + www/common/sframe-common-interface.js | 40 +- www/common/sframe-common-outer.js | 5 + www/common/sframe-common.js | 1 + www/common/sframe-protocol.js | 15 + www/drive/app-drive.less | 4 +- www/oldsettings/index.html | 16 + www/oldsettings/main.js | 569 ++++++++++++++++ www/{settings => oldsettings}/main.less | 0 www/profile/app-profile.less | 2 - www/settings/app-settings.less | 67 ++ www/settings/index.html | 46 +- www/settings/inner.html | 18 + www/settings/inner.js | 551 +++++++++++++++ www/settings/main.js | 626 +++--------------- www/settings/messenger-ui.js | 528 +++++++++++++++ 24 files changed, 2065 insertions(+), 671 deletions(-) create mode 100644 www/common/common-language.js create mode 100644 www/oldsettings/index.html create mode 100644 www/oldsettings/main.js rename www/{settings => oldsettings}/main.less (100%) create mode 100644 www/settings/app-settings.less create mode 100644 www/settings/inner.html create mode 100644 www/settings/inner.js create mode 100644 www/settings/messenger-ui.js diff --git a/customize.dist/messages.js b/customize.dist/messages.js index 916afe135..7230a719d 100644 --- a/customize.dist/messages.js +++ b/customize.dist/messages.js @@ -1,6 +1,4 @@ (function () { -var LS_LANG = "CRYPTPAD_LANG"; - // add your module to this map so it gets used var map = { 'fr': 'Français', @@ -12,17 +10,17 @@ var map = { 'zh': '繁體中文', }; +var messages = {}; +var LS_LANG = "CRYPTPAD_LANG"; var getStoredLanguage = function () { return localStorage.getItem(LS_LANG); }; -var getBrowserLanguage = function () { return navigator.language || navigator.userLanguage; }; -var getLanguage = function () { +var getBrowserLanguage = function () { return navigator.language || navigator.userLanguage || ''; }; +var getLanguage = messages._getLanguage = function () { if (window.cryptpadLanguage) { return window.cryptpadLanguage; } if (getStoredLanguage()) { return getStoredLanguage(); } - var l = getBrowserLanguage() || ''; - if (Object.keys(map).indexOf(l) !== -1) { - return l; - } + var l = getBrowserLanguage(); // Edge returns 'fr-FR' --> transform it to 'fr' and check again - return Object.keys(map).indexOf(l.split('-')[0]) !== -1 ? l.split('-')[0] : 'en'; + return map[l] ? l : + (map[l.split('-')[0]] ? l.split('-')[0] : 'en'); }; var language = getLanguage(); @@ -30,21 +28,18 @@ var req = ['jquery', '/customize/translations/messages.js']; if (language && map[language]) { req.push('/customize/translations/messages.' + language + '.js'); } define(req, function($, Default, Language) { - - var externalMap = JSON.parse(JSON.stringify(map)); - map.en = 'English'; var defaultLanguage = 'en'; +console.log(messages); - var messages; - - if (!Language || !language || language === defaultLanguage || language === 'default' || !map[language]) { - messages = Default; + if (!Language || language === defaultLanguage || !map[language]) { + messages = $.extend(true, messages, Default); } else { // Add the translated keys to the returned object - messages = $.extend(true, {}, Default, Language); + messages = $.extend(true, messages, Default, Language); } +console.log(messages); messages._languages = map; messages._languageUsed = language; @@ -53,12 +48,12 @@ define(req, function($, Default, Language) { if (typeof(cb) !== "function") { return; } var missing = []; var reqs = []; - Object.keys(externalMap).forEach(function (code) { + Object.keys(map).forEach(function (code) { reqs.push('/customize/translations/messages.' + code + '.js'); }); require(reqs, function () { var langs = arguments; - Object.keys(externalMap).forEach(function (code, i) { + Object.keys(map).forEach(function (code, i) { var translation = langs[i]; var updated = {}; Object.keys(Default).forEach(function (k) { @@ -107,59 +102,6 @@ define(req, function($, Default, Language) { } }; - // Add handler to the language selector - var storeLanguage = function (l) { - localStorage.setItem(LS_LANG, l); - }; - messages._initSelector = function ($select) { - var selector = $select || $('#language-selector'); - - if (!selector.length) { return; } - - // Select the current language in the list - selector.setValue(language || 'English'); - - // Listen for language change - $(selector).find('a.languageValue').on('click', function () { - var newLanguage = $(this).attr('data-value'); - storeLanguage(newLanguage); - if (newLanguage !== language) { - window.location.reload(); - } - }); - }; - - var translateText = function (i, e) { - var $el = $(e); - var key = $el.data('localization'); - $el.html(messages[key]); - }; - var translateAppend = function (i, e) { - var $el = $(e); - var key = $el.data('localization-append'); - $el.append(messages[key]); - }; - var translateTitle = function () { - var $el = $(this); - var key = $el.data('localization-title'); - $el.attr('title', messages[key]); - }; - var translatePlaceholder = function () { - var $el = $(this); - var key = $el.data('localization-placeholder'); - $el.attr('placeholder', messages[key]); - }; - messages._applyTranslation = function () { - $('[data-localization]').each(translateText); - $('[data-localization-append]').each(translateAppend); - $('[data-localization-title]').each(translateTitle); - $('[data-localization-placeholder]').each(translatePlaceholder); - $('#pad-iframe').contents().find('[data-localization]').each(translateText); - $('#pad-iframe').contents().find('[data-localization-append]').each(translateAppend); - $('#pad-iframe').contents().find('[data-localization-title]').each(translateTitle); - $('#pad-iframe').contents().find('[data-localization-placeholder]').each(translatePlaceholder); - }; - messages.driveReadme = '["BODY",{"class":"cke_editable cke_editable_themed cke_contents_ltr cke_show_borders","contenteditable":"true","spellcheck":"false","style":"color: rgb(51, 51, 51);"},' + '[["H1",{},["'+messages.readme_welcome+'"]],["P",{},["'+messages.readme_p1+'"]],["P",{},["'+messages.readme_p2+'"]],["HR",{},[]],["H2",{},["'+messages.readme_cat1+'",["BR",{},[]]]],["UL",{},[["LI",{},["'+messages._getKey("readme_cat1_l1", ['",["STRONG",{},["'+messages.newButton+'"]],"', '",["STRONG",{},["'+messages.type.pad+'"]],"'])+'"]],["LI",{},["'+messages.readme_cat1_l2+'"]],["LI",{},["'+messages._getKey("readme_cat1_l3", ['",["STRONG",{},["'+messages.fm_unsortedName+'"]],"'])+'",["UL",{},[["LI",{},["'+messages._getKey("readme_cat1_l3_l1", ['",["STRONG",{},["'+messages.fm_rootName+'"]],"'])+'"]],["LI",{},["'+messages.readme_cat1_l3_l2+'"]]]]]],["LI",{},["'+messages._getKey("readme_cat1_l4", ['",["STRONG",{},["'+messages.fm_trashName+'"]],"'])+'",["BR",{},[]]]]]],["P",{},[["BR",{},[]]]],["H2",{},["'+messages.readme_cat2+'",["BR",{},[]]]],["UL",{},[["LI",{},["'+messages._getKey("readme_cat2_l1", ['",["STRONG",{},["'+messages.shareButton+'"]],"', '",["STRONG",{},["'+messages.edit+'"]],"', '",["STRONG",{},["'+messages.view+'"]],"'])+'"]],["LI",{},["'+messages.readme_cat2_l2+'"]]]],["P",{},[["BR",{},[]]]],["H2",{},["'+messages.readme_cat3+'"]],["UL",{},[["LI",{},["'+messages.readme_cat3_l1+'"]],["LI",{},["'+messages.readme_cat3_l2+'"]],["LI",{},["'+messages.readme_cat3_l3+'",["BR",{},[]]]]]]],' + '{"metadata":{"defaultTitle":"' + messages.driveReadmeTitle + '","title":"' + messages.driveReadmeTitle + '"}}]'; diff --git a/customize.dist/pages.js b/customize.dist/pages.js index cc11f1be2..e342f4f1c 100644 --- a/customize.dist/pages.js +++ b/customize.dist/pages.js @@ -719,27 +719,15 @@ define([ }; Pages['/settings/'] = Pages['/settings/index.html'] = function () { - return [ - h('div#toolbar'), - h('div#container'), - loadingScreen() - ]; + return loadingScreen(); }; Pages['/profile/'] = Pages['/profile/index.html'] = function () { - return [ - h('div#cp-toolbar'), - h('div#container'), - loadingScreen() - ]; + return loadingScreen(); }; Pages['/todo/'] = Pages['/todo/index.html'] = function () { - return [ - h('div#toolbar'), - h('div#container'), - loadingScreen() - ]; + return loadingScreen(); }; return Pages; diff --git a/customize.dist/src/less2/include/sidebar-layout.less b/customize.dist/src/less2/include/sidebar-layout.less index e0bec9dcf..2d667cee5 100644 --- a/customize.dist/src/less2/include/sidebar-layout.less +++ b/customize.dist/src/less2/include/sidebar-layout.less @@ -6,7 +6,7 @@ @rightside-color: @colortheme_sidebar-right-fg; @description-color: @colortheme_sidebar-description; -@button-width: 400px; +@sidebar_button-width: 400px; .sidebar-layout_main() { @@ -38,13 +38,13 @@ overflow: auto; // Following rules are only in settings - .element { + .cp-sidebarlayout-element { label:not(.noTitle), .label { display: block; font-weight: bold; margin-bottom: 0; } - .description { + .cp-sidebarlayout-description { display: block; color: @description-color; margin-bottom: 5px; @@ -56,9 +56,9 @@ height: 40px; box-sizing: border-box; } - .inputBlock { + .cp-sidebarlayout-input-block { display: inline-flex; - width: @button-width; + width: @sidebar_button-width; input { flex: 1; border-radius: 0.25em 0 0 0.25em; diff --git a/customize.dist/src/less2/main.less b/customize.dist/src/less2/main.less index 38c242b10..c7b425f8c 100644 --- a/customize.dist/src/less2/main.less +++ b/customize.dist/src/less2/main.less @@ -35,4 +35,5 @@ body.cp-app-poll { @import "../../../poll/app-poll.less"; } body.cp-app-whiteboard { @import "../../../whiteboard/app-whiteboard.less"; } body.cp-app-todo { @import "../../../todo/app-todo.less"; } body.cp-app-profile { @import "../../../profile/app-profile.less"; } +body.cp-app-settings { @import "../../../settings/app-settings.less"; } diff --git a/www/common/common-language.js b/www/common/common-language.js new file mode 100644 index 000000000..1af06df33 --- /dev/null +++ b/www/common/common-language.js @@ -0,0 +1,81 @@ +define([ + 'jquery', + '/customize/messages.js' +], function($, Messages) { + var LS_LANG = "CRYPTPAD_LANG"; + + var Msg = {}; + + Msg.getLanguage = Messages._getLanguage; + + // Add handler to the language selector + Msg.setLanguage = function (l, sframeChan, cb) { + console.log(sframeChan); + if (sframeChan) { + // We're in the sandbox + sframeChan.query("Q_LANGUAGE_SET", l, cb); + return; + } + localStorage.setItem(LS_LANG, l); + cb(); + }; + + Msg.initSelector = function ($select, sfcommon) { + var selector = $select || $('#cp-language-selector'); + + if (!selector.length) { return; } + + var language = Messages._getLanguage(); + + // Select the current language in the list + selector.setValue(language || 'en'); + + // Listen for language change + $(selector).find('a.cp-language-value').on('click', function () { + var newLanguage = $(this).attr('data-value'); + Msg.setLanguage(newLanguage, sfcommon && sfcommon.getSframeChannel(), function () { + if (newLanguage !== language) { + if (sfcommon) { + sfcommon.gotoURL(); + return; + } + window.location.reload(); + } + }); + }); + }; + + Msg.applyTranslation = function () { + var translateText = function (i, e) { + var $el = $(e); + var key = $el.data('localization'); + $el.html(Messages[key]); + }; + var translateAppend = function (i, e) { + var $el = $(e); + var key = $el.data('localization-append'); + $el.append(Messages[key]); + }; + var translateTitle = function () { + var $el = $(this); + var key = $el.data('localization-title'); + $el.attr('title', Messages[key]); + }; + var translatePlaceholder = function () { + var $el = $(this); + var key = $el.data('localization-placeholder'); + $el.attr('placeholder', Messages[key]); + }; + $('[data-localization]').each(translateText); + $('[data-localization-append]').each(translateAppend); + $('[data-localization-title]').each(translateTitle); + $('[data-localization-placeholder]').each(translatePlaceholder); + $('#pad-iframe').contents().find('[data-localization]').each(translateText); + $('#pad-iframe').contents().find('[data-localization-append]').each(translateAppend); + $('#pad-iframe').contents().find('[data-localization-title]').each(translateTitle); + $('#pad-iframe').contents().find('[data-localization-placeholder]').each(translatePlaceholder); + }; + + return Msg; + +}); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 8a5b38c66..db820cddd 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -15,6 +15,7 @@ define([ '/common/common-file.js', '/file/file-crypto.js', '/common/common-realtime.js', + '/common/common-language.js', '/common/clipboard.js', '/common/pinpad.js', @@ -23,7 +24,7 @@ define([ '/bower_components/nthen/index.js', '/bower_components/localforage/dist/localforage.min.js', ], function ($, Config, Messages, Store, Util, Hash, UI, History, UserList, Title, Metadata, - Messaging, CodeMirror, Files, FileCrypto, Realtime, Clipboard, + Messaging, CodeMirror, Files, FileCrypto, Realtime, Language, Clipboard, Pinpad, AppConfig, MediaTag, Nthen, localForage) { // Configure MediaTags to use our local viewer @@ -188,6 +189,9 @@ define([ common.getLanguage = function () { return Messages._languageUsed; }; + common.setLanguage = function (l, cb) { + Language.setLanguage(l, null, cb); + }; common.getUserlist = function () { if (store) { if (store.getProxy() && store.getProxy().info) { @@ -225,7 +229,12 @@ define([ common.isFeedbackAllowed = function () { try { - if (!getStore().getProxy().proxy.allowUserFeedback) { return false; } + var entry = common.find(getProxy(), [ + 'settings', + 'general', + 'allowUserFeedback' + ]); + if (!entry) { return false; } return true; } catch (e) { console.error(e); @@ -499,7 +508,7 @@ define([ if (getProxy()) { getProxy()[common.displayNameKey] = value; } - if (typeof cb === "function") { cb(); } + if (typeof cb === "function") { whenRealtimeSyncs(getRealtime(), cb); } }; common.setAttribute = function (attr, value, cb) { getStore().setAttribute(attr, value, function (err, data) { @@ -527,6 +536,9 @@ define([ common.getThumbnail = function (key, cb) { localForage.getItem(key, cb); }; + common.clearThumbnail = function (cb) { + localForage.clear(cb); + }; /* this returns a reference to your proxy. changing it will change your drive. */ @@ -1901,7 +1913,7 @@ define([ $block.appendTo($container); } - Messages._initSelector($block); + Language.initSelector($block); return $block; }; @@ -2315,7 +2327,7 @@ define([ // MAGIC that happens implicitly $(function () { - Messages._applyTranslation(); + Language.applyTranslation(); }); return common; diff --git a/www/common/feedback-main.js b/www/common/feedback-main.js index e81dabbc2..f9726c689 100644 --- a/www/common/feedback-main.js +++ b/www/common/feedback-main.js @@ -1,5 +1,5 @@ define([ - '/customize/messages.js', -], function (Messages) { - Messages._applyTranslation(); + '/common/common-language.js', +], function (Language) { + Language.applyTranslation(); }); diff --git a/www/common/fsStore.js b/www/common/fsStore.js index f24409d8b..56764dc6b 100644 --- a/www/common/fsStore.js +++ b/www/common/fsStore.js @@ -237,8 +237,11 @@ define([ } } - if (typeof(proxy.allowUserFeedback) !== 'boolean') { - proxy.allowUserFeedback = true; + if (!proxy.settings || !proxy.settings.general || + typeof(proxy.settings.general.allowUserFeedback) !== 'boolean') { + proxy.settings = proxy.settings || {}; + proxy.settings.general = proxy.settings.general || {}; + proxy.settings.general.allowUserFeedback = true; } if (typeof(proxy.uid) !== 'string' || proxy.uid.length !== 32) { diff --git a/www/common/migrate-user-object.js b/www/common/migrate-user-object.js index c9c3bbd01..8dbd5f038 100644 --- a/www/common/migrate-user-object.js +++ b/www/common/migrate-user-object.js @@ -63,5 +63,22 @@ define([], function () { Cryptpad.feedback('Migrate-3', true); userObject.version = version = 3; } + + + + // Migration 4: allowUserFeedback to settings + var migrateLanguage = function () { + var settings = userObject.settings = userObject.settings || {}; + if (typeof(userObject['allowUserFeedback']) !== "undefined") { + settings.general = settings.general || {}; + settings.general.allowUserFeedback = userObject['allowUserFeedback']; + delete userObject['allowUserFeedback']; + } + }; + if (version < 4) { + migrateLanguage(); + Cryptpad.feedback('Migrate-4', true); + userObject.version = version = 4; + } }; }); diff --git a/www/common/sframe-common-interface.js b/www/common/sframe-common-interface.js index d4a0e01d3..33e7be295 100644 --- a/www/common/sframe-common-interface.js +++ b/www/common/sframe-common-interface.js @@ -3,12 +3,13 @@ define([ '/api/config', '/common/cryptpad-common.js', '/common/common-util.js', + '/common/common-language.js', '/common/media-tag.js', '/common/tippy.min.js', '/customize/application_config.js', 'css!/common/tippy.css', -], function ($, Config, Cryptpad, Util, MediaTag, Tippy, AppConfig) { +], function ($, Config, Cryptpad, Util, Language, MediaTag, Tippy, AppConfig) { var UI = {}; var Messages = Cryptpad.Messages; @@ -574,6 +575,43 @@ define([ return $userAdmin; }; + // Provide $container if you want to put the generated block in another element + // Provide $initBlock if you already have the menu block and you want the content inserted in it + UI.createLanguageSelector = function (common, $container, $initBlock) { + var options = []; + var languages = Messages._languages; + var keys = Object.keys(languages).sort(); + keys.forEach(function (l) { + options.push({ + tag: 'a', + attributes: { + 'class': 'cp-language-value', + 'data-value': l, + 'href': '#', + }, + content: languages[l] // Pretty name of the language value + }); + }); + var dropdownConfig = { + text: Messages.language, // Button initial text + options: options, // Entries displayed in the menu + //left: true, // Open to the left of the button + container: $initBlock, // optional + isSelect: true + }; + var $block = Cryptpad.createDropdown(dropdownConfig); + $block.attr('id', 'cp-language-selector'); + + if ($container) { + $block.appendTo($container); + } + + Language.initSelector($block, common); + + return $block; + }; + + UI.initFilePicker = function (common, cfg) { var onSelect = cfg.onSelect || $.noop; var sframeChan = common.getSframeChannel(); diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index abab4761b..119ae4373 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -118,6 +118,7 @@ define([ netfluxId: Cryptpad.getNetwork().webChannels[0].myID, }, priv: { + edPublic: proxy.edPublic, accountName: Cryptpad.getAccountName(), origin: window.location.origin, pathname: window.location.pathname, @@ -452,6 +453,10 @@ define([ }); }); + sframeChan.on('Q_LANGUAGE_SET', function (data, cb) { + Cryptpad.setLanguage(data, cb); + }); + if (cfg.addRpc) { cfg.addRpc(sframeChan, Cryptpad); } diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 1fd8981fb..0dc974682 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -83,6 +83,7 @@ define([ funcs.createButton = callWithCommon(UI.createButton); funcs.createUsageBar = callWithCommon(UI.createUsageBar); funcs.updateTags = callWithCommon(UI.updateTags); + funcs.createLanguageSelector = callWithCommon(UI.createLanguageSelector); // Thumb funcs.displayThumbnail = callWithCommon(Thumb.displayThumbnail); diff --git a/www/common/sframe-protocol.js b/www/common/sframe-protocol.js index e41bc129f..120dade8d 100644 --- a/www/common/sframe-protocol.js +++ b/www/common/sframe-protocol.js @@ -176,4 +176,19 @@ define({ // Store outside and get thumbnails inside (stored with localForage (indexedDB) outside) 'Q_THUMBNAIL_SET': true, 'Q_THUMBNAIL_GET': true, + + // Settings app only + // Clear all thumbnails + 'Q_THUMBNAIL_CLEAR': true, + // Backup and restore a drive + 'Q_SETTINGS_DRIVE_GET': true, + 'Q_SETTINGS_DRIVE_SET': true, + 'Q_SETTINGS_DRIVE_RESET': true, + // Logout from all the devices where the account is logged in + 'Q_SETTINGS_LOGOUT': true, + // Import pads from this computer's anon session into the current user account + 'Q_SETTINGS_IMPORT_LOCAL': true, + + // Store the language selected in the iframe into localStorage outside + 'Q_LANGUAGE_SET': true, }); diff --git a/www/drive/app-drive.less b/www/drive/app-drive.less index 2cc04be9c..cad82bc2f 100644 --- a/www/drive/app-drive.less +++ b/www/drive/app-drive.less @@ -280,8 +280,8 @@ span { .cp-app-drive-tree-category:last-child { margin-bottom: 20px; } - .limit-container { - margin-top: 0; + .cp-limit-container { + margin-top: 5px; } #cp-app-drive-tree-search { text-align: center; diff --git a/www/oldsettings/index.html b/www/oldsettings/index.html new file mode 100644 index 000000000..31d4c99f8 --- /dev/null +++ b/www/oldsettings/index.html @@ -0,0 +1,16 @@ + + + + + CryptPad: Zero Knowledge, Collaborative Real Time Editing + + + + + + + + diff --git a/www/oldsettings/main.js b/www/oldsettings/main.js new file mode 100644 index 000000000..57b61268d --- /dev/null +++ b/www/oldsettings/main.js @@ -0,0 +1,569 @@ +define([ + 'jquery', + '/common/cryptpad-common.js', + '/common/cryptget.js', + '/common/mergeDrive.js', + '/common/toolbar2.js', + '/bower_components/file-saver/FileSaver.min.js', + + 'less!/customize/src/less/cryptpad.less', + 'less!/bower_components/components-font-awesome/css/font-awesome.min.css', + 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', + 'less!/customize/src/less/toolbar.less', + 'less!/settings/main.less', +], function ($, Cryptpad, Crypt, Merge, Toolbar) { + var saveAs = window.saveAs; + + var USERNAME_KEY = 'cryptpad.username'; + + var APP = window.APP = { + Cryptpad: Cryptpad, + _onRefresh: [] + }; + + var Messages = Cryptpad.Messages; + + // Manage changes in the realtime object made from another page + var onRefresh = function (h) { + if (typeof(h) !== "function") { return; } + if (APP._onRefresh.indexOf(h) !== -1) { return; } + APP._onRefresh.push(h); + }; + var refresh = APP.refresh = function () { + APP._onRefresh.forEach(function (h) { + h(); + }); + }; + + var categories = { + 'account': [ + 'infoBlock', + 'displayName', + 'languageSelector', + 'logoutEverywhere', + 'resetTips', + 'thumbnails', + 'userFeedback' + ], + 'drive': [ + 'backupDrive', + 'importLocalPads', + 'resetDrive' + ], + 'code': [ + 'indentUnit', + 'indentType' + ] + }; + + var createInfoBlock = function (store) { + var obj = store.proxy; + var $div = $('
', {'class': 'infoBlock'}); + + var $account = $('
', {'class': 'element'}).appendTo($div); + var accountName = obj.login_name || localStorage[Cryptpad.userNameKey]; + var $label = $('', {'class': 'label'}).text(Messages.user_accountName); + var $name = $('').text(accountName || ''); + if (!accountName) { + $label.text(''); + $name.text(Messages.settings_anonymous); + } + $account.append($label).append($name); + + var publicKey = obj.edPublic; + if (publicKey) { + var $key = $('
', {'class': 'element'}).appendTo($div); + var userHref = Cryptpad.getUserHrefFromKeys(accountName, publicKey); + var $pubLabel = $('', {'class': 'label'}) + .text(Messages.settings_publicSigningKey); + $key.append($pubLabel).append(Cryptpad.dialog.selectable(userHref)); + } + + return $div; + }; + + // Create the block containing the display name field + var createDisplayNameInput = function (store) { + var obj = store.proxy; + var $div = $('
', {'class': 'displayName element'}); + $('