define([ 'jquery', '/common/toolbar3.js', '/bower_components/nthen/index.js', '/common/sframe-common.js', '/common/common-interface.js', '/common/common-util.js', '/common/common-hash.js', '/customize/messages.js', '/bower_components/file-saver/FileSaver.min.js', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'less!/bower_components/components-font-awesome/css/font-awesome.min.css', 'less!/customize/src/less2/main.less', ], function ( $, Toolbar, nThen, SFCommon, UI, Util, Hash, Messages ) { var saveAs = window.saveAs; var APP = window.APP = {}; var common; var metadataMgr; var privateData; var sframeChan; var categories = { 'account': [ 'cp-settings-info-block', 'cp-settings-displayname', 'cp-settings-language-selector', 'cp-settings-logout-everywhere', 'cp-settings-resettips', 'cp-settings-thumbnails', 'cp-settings-userfeedback' ], 'drive': [ 'cp-settings-backup-drive', 'cp-settings-import-local-pads', 'cp-settings-reset-drive' ], 'code': [ 'cp-settings-indent-unit', 'cp-settings-indent-type' ] }; var createInfoBlock = function () { var $div = $('<div>', {'class': 'cp-settings-info-block'}); var $account = $('<div>', {'class': 'cp-sidebarlayout-element'}).appendTo($div); var accountName = privateData.accountName; var $label = $('<span>', {'class': 'label'}).text(Messages.user_accountName); var $name = $('<span>').text(accountName || ''); if (!accountName) { $label.text(''); $name.text(Messages.settings_anonymous); } $account.append($label).append($name); var publicKey = privateData.edPublic; if (publicKey) { var $key = $('<div>', {'class': 'cp-sidebarlayout-element'}).appendTo($div); var userHref = Hash.getUserHrefFromKeys(privateData.origin, accountName, publicKey); var $pubLabel = $('<span>', {'class': 'label'}) .text(Messages.settings_publicSigningKey); $key.append($pubLabel).append(UI.dialog.selectable(userHref)); } return $div; }; // Create the block containing the display name field var createDisplayNameInput = function () { var $div = $('<div>', {'class': 'cp-settings-displayname cp-sidebarlayout-element'}); $('<label>', {'for' : 'cp-settings-displayname'}).text(Messages.user_displayName).appendTo($div); var $inputBlock = $('<div>', {'class': 'cp-sidebarlayout-input-block'}).appendTo($div); var $input = $('<input>', { 'type': 'text', 'id': 'cp-settings-displayname', 'placeholder': Messages.anonymous}).appendTo($inputBlock); var $save = $('<button>', {'class': 'btn btn-primary'}).text(Messages.settings_save).appendTo($inputBlock); var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved}).hide().appendTo($div); var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}).hide().appendTo($div); var displayName = metadataMgr.getUserData().name || ''; $input.val(displayName); // When the display name is changed (enter or button clicked) var todo = function () { displayName = $input.val(); if (displayName === metadataMgr.getUserData().name) { return; } $spinner.show(); common.setDisplayName(displayName, function () { $spinner.hide(); $ok.show(); }); }; $input.on('keyup', function (e) { if ($input.val() !== displayName) { $ok.hide(); } if (e.which === 13) { todo(); } }); $save.click(todo); // On remote change var onChange = function () { if (metadataMgr.getUserData().name !== $input.val()) { $input.val(metadataMgr.getUserData().name); $input.focusout(); } }; metadataMgr.onChange(onChange); return $div; }; var createIndentUnitSelector = function () { var $div = $('<div>', { 'class': 'cp-settings-indent-unit cp-sidebarlayout-element' }); $('<label>').text(Messages.settings_codeIndentation).appendTo($div); var $inputBlock = $('<div>', { 'class': 'cp-sidebarlayout-input-block', }).appendTo($div); var $input = $('<input>', { 'min': 1, 'max': 8, type: 'number', }).on('change', function () { var val = parseInt($input.val()); if (typeof(val) !== 'number') { return; } common.setAttribute(['codemirror', 'indentUnit'], val); }).appendTo($inputBlock); common.getAttribute(['codemirror', 'indentUnit'], function (e, val) { if (e) { return void console.error(e); } if (typeof(val) !== 'number') { $input.val(2); } else { $input.val(val); } }); return $div; }; var createIndentTypeSelector = function () { var key = 'indentWithTabs'; var $div = $('<div>', { 'class': 'cp-settings-indent-type cp-sidebarlayout-element' }); $('<label>').text(Messages.settings_codeUseTabs).appendTo($div); var $inputBlock = $('<div>', { 'class': 'cp-sidebarlayout-input-block', }).css('flex-flow', 'column') .appendTo($div); var $input = $('<input>', { type: 'checkbox', }).on('change', function () { var val = $input.is(':checked'); if (typeof(val) !== 'boolean') { return; } common.setAttribute(['codemirror', key], val); }).appendTo($inputBlock); /*proxy.on('change', ['settings', 'codemirror', key], function (o, n) { $input[0].checked = !!n; });*/ common.getAttribute(['codemirror', key], function (e, val) { if (e) { return void console.error(e); } $input[0].checked = !!val; }); return $div; }; var createResetTips = function () { var $div = $('<div>', {'class': 'cp-settings-resettips cp-sidebarlayout-element'}); $('<label>').text(Messages.settings_resetTips).appendTo($div); $('<span>', {'class': 'cp-sidebarlayout-description'}) .text(Messages.settings_resetTipsButton).appendTo($div); var $button = $('<button>', {'id': 'cp-settings-resettips', 'class': 'btn btn-primary'}) .text(Messages.settings_resetTipsAction).appendTo($div); var localStore = window.cryptpadStore; $button.click(function () { Object.keys(localStore).forEach(function (k) { if(k.slice(0, 9) === "hide-info") { localStore.put(k, undefined); } }); UI.alert(Messages.settings_resetTipsDone); }); return $div; }; var createThumbnails = function () { var $div = $('<div>', {'class': 'cp-settings-thumbnails cp-sidebarlayout-element'}); $('<label>').text(Messages.settings_thumbnails).appendTo($div); // Disable $('<span>', {'class': 'cp-sidebarlayout-description'}) .text(Messages.settings_disableThumbnailsDescription).appendTo($div); var $label = $('<label>', { 'for': 'disableThumbnails', 'class': 'noTitle' }) .text(Messages.settings_disableThumbnailsAction); var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved}); var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}); var $checkbox = $('<input>', { 'type': 'checkbox', id: 'disableThumbnails' }).on('change', function () { $spinner.show(); $ok.hide(); var val = $checkbox.is(':checked') || false; common.setAttribute(['general', 'disableThumbnails'], val, function () { $spinner.hide(); $ok.show(); }); }); $checkbox.appendTo($div); $label.appendTo($div); $ok.hide().appendTo($div); $spinner.hide().appendTo($div); common.getAttribute(['general', 'disableThumbnails'], function (e, val) { $checkbox[0].checked = val; }); // Reset $('<span>', {'class': 'cp-sidebarlayout-description'}) .text(Messages.settings_resetThumbnailsDescription).appendTo($div); var $button = $('<button>', {'id': 'resetThumbnails', 'class': 'btn btn-primary'}) .text(Messages.settings_resetThumbnailsAction).appendTo($div); $button.click(function () { sframeChan.query("Q_THUMBNAIL_CLEAR", null, function (err) { if (err) { return void console.error("Cannot clear localForage"); } UI.alert(Messages.settings_resetThumbnailsDone); }); }); return $div; }; var createBackupDrive = function () { var $div = $('<div>', {'class': 'cp-settings-backup-drive cp-sidebarlayout-element'}); var accountName = privateData.accountName; var displayName = metadataMgr.getUserData().name || ''; var exportFile = function () { sframeChan.query("Q_SETTINGS_DRIVE_GET", null, function (err, data) { if (err) { return void console.error(err); } var sjson = JSON.stringify(data); var name = displayName || accountName || Messages.anonymous; var suggestion = name + '-' + new Date().toDateString(); UI.prompt(Messages.exportPrompt, Util.fixFileName(suggestion) + '.json', function (filename) { if (!(typeof(filename) === 'string' && filename)) { return; } var blob = new Blob([sjson], {type: "application/json;charset=utf-8"}); saveAs(blob, filename); }); }); }; var importFile = function (content) { var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}).appendTo($div); try { var data = JSON.parse(content); sframeChan.query("Q_SETTINGS_DRIVE_SET", data, function (e) { if (e) { console.error(e); } $spinner.remove(); }); } catch (e) { console.error(e); } }; $('<label>', {'for' : 'exportDrive'}).text(Messages.settings_backupCategory).appendTo($div); $('<span>', {'class': 'cp-sidebarlayout-description'}) .text(Messages.settings_backupTitle).appendTo($div); /* add an export button */ var $export = common.createButton('export', true, {}, exportFile); $export.attr('class', 'btn btn-success').text(Messages.settings_backup); $div.append($export); /* add an import button */ var $import = common.createButton('import', true, {}, importFile); $import.attr('class', 'btn btn-success').text(Messages.settings_restore); $div.append($import); return $div; }; var createResetDrive = function () { var $div = $('<div>', {'class': 'cp-settings-reset-drive cp-sidebarlayout-element'}); $('<label>').text(Messages.settings_resetNewTitle).appendTo($div); $('<span>', {'class': 'cp-sidebarlayout-description'}) .text(Messages.settings_reset).appendTo($div); var $button = $('<button>', {'id': 'cp-settings-reset-drive', 'class': 'btn btn-danger'}) .text(Messages.settings_resetButton).appendTo($div); $button.click(function () { UI.prompt(Messages.settings_resetPrompt, "", function (val) { if (val !== "I love CryptPad") { UI.alert(Messages.settings_resetError); return; } sframeChan.query("Q_SETTINGS_DRIVE_RESET", null, function (err) { if (err) { return void console.error(err); } UI.alert(Messages.settings_resetDone); }); }, undefined, true); }); return $div; }; var createUserFeedbackToggle = function () { var $div = $('<div>', { 'class': 'cp-settings-userfeedback cp-sidebarlayout-element'}); $('<span>', {'class': 'label'}).text(Messages.settings_userFeedbackTitle).appendTo($div); var $label = $('<label>', { 'for': 'cp-settings-userfeedback', 'class': 'noTitle' }) .text(Messages.settings_userFeedback); $('<span>', {'class': 'cp-sidebarlayout-description'}) .append(Messages.settings_userFeedbackHint1) .append(Messages.settings_userFeedbackHint2).appendTo($div); var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved}); var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}); var $checkbox = $('<input>', { 'type': 'checkbox', id: 'cp-settings-userfeedback' }).on('change', function () { $spinner.show(); $ok.hide(); var val = $checkbox.is(':checked') || false; common.setAttribute(['general', 'allowUserFeedback'], val, function () { $spinner.hide(); $ok.show(); }); }); $checkbox.appendTo($div); $label.appendTo($div); $ok.hide().appendTo($div); $spinner.hide().appendTo($div); if (privateData.feedbackAllowed) { $checkbox[0].checked = true; } return $div; }; var createUsageButton = function () { common.createUsageBar(function (err, $bar) { if (err) { return void console.error(err); } APP.$usage.html('').append($bar); }, true); }; var createLogoutEverywhere = function () { var $div = $('<div>', { 'class': 'cp-settings-logout-everywhere cp-sidebarlayout-element'}); $('<label>', { 'for': 'cp-settings-logout-everywhere'}) .text(Messages.settings_logoutEverywhereTitle).appendTo($div); $('<span>', {'class': 'cp-sidebarlayout-description'}) .text(Messages.settings_logoutEverywhere).appendTo($div); var $button = $('<button>', { id: 'cp-settings-logout-everywhere', 'class': 'btn btn-primary' }).text(Messages.settings_logoutEverywhereButton) .appendTo($div); var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved}).hide().appendTo($div); var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}).hide().appendTo($div); $button.click(function () { UI.confirm(Messages.settings_logoutEverywhereConfirm, function (yes) { if (!yes) { return; } $spinner.show(); $ok.hide(); sframeChan.query('Q_SETTINGS_LOGOUT', null, function () { $spinner.hide(); $ok.show(); window.setTimeout(function () { $ok.fadeOut(1500); }, 2500); }); }); }); return $div; }; var createImportLocalPads = function () { if (!common.isLoggedIn()) { return; } var $div = $('<div>', {'class': 'cp-settings-import-local-pads cp-sidebarlayout-element'}); $('<label>', {'for' : 'cp-settings-import-local-pads'}) .text(Messages.settings_import).appendTo($div); $('<span>', {'class': 'cp-sidebarlayout-description'}) .text(Messages.settings_importTitle).appendTo($div); var $button = $('<button>', { 'id': 'cp-settings-import-local-pads', 'class': 'btn btn-primary' }).text(Messages.settings_import).appendTo($div); var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved}).hide().appendTo($div); var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}).hide().appendTo($div); $button.click(function () { UI.confirm(Messages.settings_importConfirm, function (yes) { if (!yes) { return; } $spinner.show(); $ok.hide(); sframeChan.query('Q_SETTINGS_IMPORT_LOCAL', null, function () { $spinner.hide(); $ok.show(); UI.alert(Messages.settings_importDone); }); }, undefined, true); }); return $div; }; var createLanguageSelector = function () { var $div = $('<div>', {'class': 'cp-settings-language-selector cp-sidebarlayout-element'}); $('<label>').text(Messages.language).appendTo($div); var $b = common.createLanguageSelector($div); $b.find('button').addClass('btn btn-secondary'); return $div; }; var hideCategories = function () { APP.$rightside.find('> div').hide(); }; var showCategories = function (cat) { hideCategories(); cat.forEach(function (c) { APP.$rightside.find('.'+c).show(); }); }; var createLeftside = function () { var $categories = $('<div>', {'class': 'cp-sidebarlayout-categories'}) .appendTo(APP.$leftside); APP.$usage = $('<div>', {'class': 'usage'}).appendTo(APP.$leftside); var active = 'account'; Object.keys(categories).forEach(function (key) { var $category = $('<div>', {'class': 'cp-sidebarlayout-category'}).appendTo($categories); if (key === 'account') { $category.append($('<span>', {'class': 'fa fa-user-o'})); } if (key === 'drive') { $category.append($('<span>', {'class': 'fa fa-hdd-o'})); } if (key === 'code') { $category.append($('<span>', {'class': 'fa fa-file-code-o' })); } if (key === active) { $category.addClass('cp-leftside-active'); } $category.click(function () { active = key; $categories.find('.cp-leftside-active').removeClass('cp-leftside-active'); $category.addClass('cp-leftside-active'); showCategories(categories[key]); }); $category.append(Messages['settings_cat_'+key]); }); showCategories(categories[active]); }; nThen(function (waitFor) { $(waitFor(UI.addLoadingScreen)); SFCommon.create(waitFor(function (c) { APP.common = common = c; })); }).nThen(function (waitFor) { APP.$container = $('#cp-sidebarlayout-container'); APP.$toolbar = $('#cp-toolbar'); APP.$leftside = $('<div>', {id: 'cp-sidebarlayout-leftside'}).appendTo(APP.$container); APP.$rightside = $('<div>', {id: 'cp-sidebarlayout-rightside'}).appendTo(APP.$container); sframeChan = common.getSframeChannel(); sframeChan.onReady(waitFor()); }).nThen(function (/*waitFor*/) { metadataMgr = common.getMetadataMgr(); privateData = metadataMgr.getPrivateData(); // Toolbar var displayed = ['useradmin', 'newpad', 'limit', 'pageTitle']; var configTb = { displayed: displayed, sfCommon: common, $container: APP.$toolbar, pageTitle: Messages.settings_title, metadataMgr: common.getMetadataMgr(), }; APP.toolbar = Toolbar.create(configTb); APP.toolbar.$rightside.hide(); // Content var $rightside = APP.$rightside; $rightside.append(createInfoBlock()); $rightside.append(createDisplayNameInput()); $rightside.append(createLanguageSelector()); $rightside.append(createIndentUnitSelector()); $rightside.append(createIndentTypeSelector()); if (common.isLoggedIn()) { $rightside.append(createLogoutEverywhere()); } $rightside.append(createResetTips()); $rightside.append(createThumbnails()); $rightside.append(createBackupDrive()); $rightside.append(createImportLocalPads()); $rightside.append(createResetDrive()); $rightside.append(createUserFeedbackToggle()); // TODO RPC //obj.proxy.on('change', [], refresh); //obj.proxy.on('remove', [], refresh); //Cryptpad.onDisplayNameChanged(refresh); createLeftside(); createUsageButton(); UI.removeLoadingScreen(); }); });