From 299a2f4c080810faf0f6101deca5543e6c8f20a0 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 19 Feb 2018 12:09:57 +0100 Subject: [PATCH 01/21] FAQ placeholder --- config.example.js | 3 ++- customize.dist/pages.js | 36 +++++++++++++++++++++++++ customize.dist/src/less2/main.less | 1 + customize.dist/translations/messages.js | 24 +++++++++++++++++ 4 files changed, 63 insertions(+), 1 deletion(-) diff --git a/config.example.js b/config.example.js index 2c234aee4..7e728451a 100644 --- a/config.example.js +++ b/config.example.js @@ -126,7 +126,8 @@ module.exports = { 'about', 'contact', 'what-is-cryptpad', - 'features' + 'features', + 'faq' ], /* Limits, Donations, Subscriptions and Contact diff --git a/customize.dist/pages.js b/customize.dist/pages.js index a9fbeabde..37bdc5b42 100644 --- a/customize.dist/pages.js +++ b/customize.dist/pages.js @@ -373,6 +373,42 @@ define([ ]); }; + Pages['/faq.html'] = function () { + var categories = []; + var faq = Msg.faq; + Object.keys(faq).forEach(function (c) { + var questions = []; + Object.keys(faq[c]).forEach(function (q) { + var item = faq[c][q]; + if (typeof item !== "object") { return; } + var answer = h('p.cp-faq-questions-a'); + var question = h('p.cp-faq-questions-q'); + $(question).click(function () { + if ($(answer).is(':visible')) { + return void $(answer).slideUp(); + } + $(answer).slideDown(); + }); + questions.push(h('div.cp-faq-questions-items', [ + setHTML(question, item.q), + setHTML(answer, item.a) + ])); + }); + categories.push(h('div.cp-faq-category', [ + h('h3', faq[c].title), + h('div.cp-faq-category-questions', questions) + ])); + }); + return h('div#cp-main', [ + infopageTopbar(), + h('div.container.cp-container', [ + h('center', h('h1', Msg.faq_title)), + h('div.cp-faq-container', categories) + ]), + infopageFooter() + ]); + }; + Pages['/terms.html'] = function () { return h('div#cp-main', [ infopageTopbar(), diff --git a/customize.dist/src/less2/main.less b/customize.dist/src/less2/main.less index c1bb5bba4..dadbef539 100644 --- a/customize.dist/src/less2/main.less +++ b/customize.dist/src/less2/main.less @@ -10,6 +10,7 @@ body.cp-page-what-is-cryptpad { @import "./pages/page-what-is-cryptpad.less"; } body.cp-page-about { @import "./pages/page-about.less"; } body.cp-page-privacy { @import "./pages/page-privacy.less"; } body.cp-page-features { @import "./pages/page-features.less"; } +body.cp-page-faq { @import "./pages/page-faq.less"; } body.cp-page-terms { @import "./pages/page-terms.less"; } // Set the HTML style for the apps which shouldn't have a body scrollbar diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 956aa2147..eaceee812 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -759,6 +759,30 @@ define(function () { out.features_f_storage_anon = "Pads deleted after 3 months"; out.features_f_storage_registered = "Free: 50MB
Premium: 5GB/20GB/50GB"; + // faq.html + + out.faq_link = "FAQ"; + out.faq_title = "Frequently Asked Questions"; + out.faq = {}; + out.faq.cat1 = { + title: 'Category 1', + q1: { + q: 'What is a pad?', + a: 'A realtime collaborative document...' + }, + q2: { + q: 'Question 2?', + a: '42' + } + }; + out.faq.cat2 = { + title: 'Category 2', + q1: { + q: 'A new question?', + a: 'The answer' + } + }; + // terms.html out.tos_title = "CryptPad Terms of Service"; From 5d584625e4ff1109d361ed080c6903493184e388 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 19 Feb 2018 12:11:45 +0100 Subject: [PATCH 02/21] FAQ pages --- customize.dist/faq.html | 17 +++++++++++ customize.dist/src/less2/pages/page-faq.less | 30 ++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 customize.dist/faq.html create mode 100644 customize.dist/src/less2/pages/page-faq.less diff --git a/customize.dist/faq.html b/customize.dist/faq.html new file mode 100644 index 000000000..d485505dd --- /dev/null +++ b/customize.dist/faq.html @@ -0,0 +1,17 @@ + + + + + CryptPad: Zero Knowledge, Collaborative Real Time Editing + + + + + + + + + diff --git a/customize.dist/src/less2/pages/page-faq.less b/customize.dist/src/less2/pages/page-faq.less new file mode 100644 index 000000000..e24dc767c --- /dev/null +++ b/customize.dist/src/less2/pages/page-faq.less @@ -0,0 +1,30 @@ +@import (once) "../include/infopages.less"; +@import (once) "../include/colortheme-all.less"; + +.infopages_main(); +.infopages_topbar(); + +.cp-faq-container { + .cp-faq-questions-q { + color: #3a84b6; + padding: 0; + margin-bottom: 0; + margin-top: 5px; + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } + .cp-faq-questions-q:hover { + color: #2e688f; + text-decoration: underline; + } + .cp-faq-questions-a { + display: none; + padding: 0; + } +} + From 7ede2e1a07ed3d1dadb09487086ee235507c04f5 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 20 Feb 2018 18:43:14 +0100 Subject: [PATCH 03/21] Fix cursor position when editing a task in todo --- www/todo/inner.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/www/todo/inner.js b/www/todo/inner.js index f34592568..136a908e9 100644 --- a/www/todo/inner.js +++ b/www/todo/inner.js @@ -147,6 +147,8 @@ define([ $span.text($input.val().trim()); $span.show(); } + }).on('click mousedown', function (e) { + e.stopPropagation(); }).appendTo($taskDiv); $span.text(entry.task) From a0ec51dde57319b95478ec4a4336893072498821 Mon Sep 17 00:00:00 2001 From: yflory Date: Thu, 22 Feb 2018 12:43:06 +0100 Subject: [PATCH 04/21] Fix share modal with new pads --- www/common/common-ui-elements.js | 4 ++++ www/common/sframe-common-outer.js | 1 + 2 files changed, 5 insertions(+) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 1d41d8308..c8b118694 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -378,6 +378,10 @@ define([ if (val.present) { $(link).find('#cp-share-present').attr('checked', true); } $(link).find('#cp-share-link-preview').val(getLinkValue(val)); }); + common.getMetadataMgr().onChange(function () { + hashes = common.getMetadataMgr().getPrivateData().availableHashes; + $(link).find('#cp-share-link-preview').val(getLinkValue()); + }); return tabs; }; UIElements.createFileShareModal = function (config) { diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 57261372d..70d1f72ac 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -625,6 +625,7 @@ define([ // Update metadata values and send new metadata inside parsed = Utils.Hash.parsePadUrl(window.location.href); defaultTitle = Utils.Hash.getDefaultName(parsed); + hashes = Utils.Hash.getHashes(secret.channel, secret); readOnly = false; updateMeta(); From 22f130d94814828a60cc5442ae4ec3de3c8f218a Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 26 Feb 2018 10:41:37 +0100 Subject: [PATCH 05/21] Remove lag when displaying loading screen in login and register --- customize.dist/login.js | 6 ++++-- www/login/main.js | 4 ---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/customize.dist/login.js b/customize.dist/login.js index 5511637e8..fde218d21 100644 --- a/customize.dist/login.js +++ b/customize.dist/login.js @@ -191,8 +191,10 @@ define([ window.location.href = '/drive/'; }; + var hashing; Exports.loginOrRegisterUI = function (uname, passwd, isRegister, shouldImport, testing, test) { - var hashing = true; + if (hashing) { return void console.log("hashing is already in progress"); } + hashing = true; var proceed = function (result) { hashing = false; @@ -275,7 +277,7 @@ define([ proceed(result); }); - }, 0); + }, 500); }, 200); }; diff --git a/www/login/main.js b/www/login/main.js index f0c6c7d22..b3f08a0cf 100644 --- a/www/login/main.js +++ b/www/login/main.js @@ -53,12 +53,8 @@ define([ $('button.login').click(); }); - var hashing = false; var test; $('button.login').click(function () { - if (hashing) { return void console.log("hashing is already in progress"); } - - hashing = true; var shouldImport = $checkImport[0].checked; var uname = $uname.val(); var passwd = $passwd.val(); From 329fd61bb1ce4efee93245d21ec13b6239d1214d Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 26 Feb 2018 10:49:35 +0100 Subject: [PATCH 06/21] Remove lag when creating a pad from the pad creation screen --- www/common/common-ui-elements.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 27c583e08..2a892cae6 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1764,6 +1764,7 @@ define([ // Create the pad var create = function (template) { + $creationContainer.remove(); // Type of pad var ownedVal = parseInt($('input[name="cp-creation-owned"]:checked').val()); // Life time @@ -1784,7 +1785,6 @@ define([ expire: expireVal, template: template }, function () { - $creationContainer.remove(); cb(); }); }; From 5c53868c3bbd6bca0541c1ea44ff767af56c6da1 Mon Sep 17 00:00:00 2001 From: yflory Date: Mon, 26 Feb 2018 18:23:12 +0100 Subject: [PATCH 07/21] Delete pads after 3 months of inactivity --- config.example.js | 8 + .../src/less2/include/colortheme.less | 6 +- customize.dist/src/less2/include/toolbar.less | 2 + customize.dist/translations/messages.fr.js | 3 +- customize.dist/translations/messages.js | 3 +- delete-inactive.js | 40 ++++ expire-channels.js | 1 - pinneddata.js | 207 ++++++++++-------- www/common/common-interface.js | 8 +- www/common/sframe-app-framework.js | 10 +- www/common/sframe-common-outer.js | 7 +- www/common/sframe-common.js | 24 ++ www/common/toolbar3.js | 2 +- www/poll/inner.js | 11 +- www/whiteboard/inner.js | 10 +- 15 files changed, 212 insertions(+), 130 deletions(-) create mode 100644 delete-inactive.js diff --git a/config.example.js b/config.example.js index 7e728451a..3aace0d4a 100644 --- a/config.example.js +++ b/config.example.js @@ -249,6 +249,14 @@ module.exports = { */ pinPath: './pins', + /* Pads that are not 'pinned' by any registered user can be set to expire + * after a configurable number of days of inactivity (default 90 days). + * The value can be changed or set to false to remove expiration. + * Expired pads can then be removed using a cron job calling the + * `delete-inactive.js` script with node + */ + inactiveTime: 90, // days + /* CryptPad allows logged in users to upload encrypted files. Files/blobs * are stored in a 'blob-store'. Set its location here. */ diff --git a/customize.dist/src/less2/include/colortheme.less b/customize.dist/src/less2/include/colortheme.less index c8848d02b..1a2b143e5 100644 --- a/customize.dist/src/less2/include/colortheme.less +++ b/customize.dist/src/less2/include/colortheme.less @@ -44,11 +44,11 @@ @colortheme_pad-bg: #1c4fa0; @colortheme_pad-color: #fff; @colortheme_pad-toolbar-bg: #c1e7ff; -@colortheme_pad-warn: #F83A3A; +@colortheme_pad-warn: #ffae00; @colortheme_slide-bg: #e57614; @colortheme_slide-color: #fff; -@colortheme_slide-warn: #58D697; +@colortheme_slide-warn: #005868; @colortheme_code-bg: #ffae00; @colortheme_code-color: #000; @@ -59,7 +59,7 @@ @colortheme_poll-help-bg: #bbffbb; @colortheme_poll-th-bg: #005bef; @colortheme_poll-th-fg: #fff; -@colortheme_poll-warn: #ffae00; +@colortheme_poll-warn: #ffade3; @colortheme_whiteboard-bg: #800080; @colortheme_whiteboard-color: #fff; diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less index 435476090..f8cd43fd0 100644 --- a/customize.dist/src/less2/include/toolbar.less +++ b/customize.dist/src/less2/include/toolbar.less @@ -505,6 +505,7 @@ font-size: @colortheme_app-font-size; a { font-size: @colortheme_app-font-size; + font-family: @colortheme_font; font-weight: bold; color: @warn-color; &:hover { @@ -792,6 +793,7 @@ } .cp-toolbar-share-button { width: 50px; + text-align: center; } } .cp-toolbar-rightside { diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 2d21cf9a6..5e681e699 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -29,11 +29,12 @@ define(function () { out.typeError = "Ce pad n'est pas compatible avec l'application sélectionnée"; out.onLogout = 'Vous êtes déconnecté de votre compte utilisateur, cliquez ici pour vous authentifier
ou appuyez sur Échap pour accéder au pad en mode lecture seule.'; out.wrongApp = "Impossible d'afficher le contenu de ce document temps-réel dans votre navigateur. Vous pouvez essayer de recharger la page."; - out.padNotPinned = 'Ce pad va expirer dans 3 mois, {0}connectez-vous{1} ou {2}enregistrez-vous{3} pour le préserver.'; + out.padNotPinned = 'Ce pad va expirer après 3 mois d\'inactivité, {0}connectez-vous{1} ou {2}enregistrez-vous{3} pour le préserver.'; out.anonymousStoreDisabled = "L'administrateur de cette instance de CryptPad a désactivé le drive pour les utilisateurs non enregistrés. Vous devez vous connecter pour pouvoir utiliser CryptDrive."; out.expiredError = "Ce pad a atteint sa date d'expiration est n'est donc plus disponible."; out.expiredErrorCopy = ' Vous pouvez toujours copier son contenu ailleurs en appuyant sur Échap.
Dés que vous aurez quitté la page, il sera impossible de le récupérer.'; out.deletedError = 'Ce pad a été supprimé par son propriétaire et n\'est donc plus disponible.'; + out.inactiveError = 'Ce pad a été supprimé en raison de son inactivité. Appuyez sur Échap pour créer un nouveau pad.'; out.loading = "Chargement..."; out.error = "Erreur"; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index eaceee812..c5f7bcd8c 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -30,11 +30,12 @@ define(function () { out.typeError = "This pad is not compatible with the selected application"; out.onLogout = 'You are logged out, click here to log in
or press Escape to access your pad in read-only mode.'; out.wrongApp = "Unable to display the content of that realtime session in your browser. Please try to reload that page."; - out.padNotPinned = 'This pad will expire in 3 months, {0}login{1} or {2}register{3} to preserve it.'; + out.padNotPinned = 'This pad will expire after 3 months of inactivity, {0}login{1} or {2}register{3} to preserve it.'; out.anonymousStoreDisabled = "The webmaster of this CryptPad instance has disabled the store for anonymous users. You have to log in to be able to use CryptDrive."; out.expiredError = 'This pad has reached its expiration time and is no longer available.'; out.expiredErrorCopy = ' You can still copy the content to another location by pressing Esc.
Once you leave this page, it will disappear forever!'; out.deletedError = 'This pad has been deleted by its owner and is no longer available.'; + out.inactiveError = 'This pad has been deleted due to inactivity. Press Esc to create a new pad.'; out.loading = "Loading..."; out.error = "Error"; diff --git a/delete-inactive.js b/delete-inactive.js new file mode 100644 index 000000000..16f41da45 --- /dev/null +++ b/delete-inactive.js @@ -0,0 +1,40 @@ +/* jshint esversion: 6, node: true */ +const Fs = require("fs"); +const nThen = require("nthen"); +const Saferphore = require("saferphore"); +const PinnedData = require('./pinneddata'); +let config; +try { + config = require('./config'); +} catch (e) { + config = require('./config.example'); +} + +if (!config.inactiveTime || typeof(config.inactiveTime) !== "number") { return; } + +let inactiveTime = +new Date() - (config.inactiveTime * 24 * 3600 * 1000); +let inactiveConfig = { + unpinned: true, + olderthan: inactiveTime, + blobsolderthan: inactiveTime +}; +let toDelete; +nThen(function (waitFor) { + PinnedData.load(inactiveConfig, waitFor(function (err, data) { + if (err) { + waitFor.abort(); + throw new Error(err); + } + toDelete = data; + })); +}).nThen(function () { + var sem = Saferphore.create(10); + toDelete.forEach(function (f) { + sem.take(function (give) { + Fs.unlink(f.filename, give(function (err) { + if (err) { return void console.error(err + " " + f.filename); } + console.log(f.filename + " " + f.size + " " + (+f.atime) + " " + (+new Date())); + })); + }); + }); +}); diff --git a/expire-channels.js b/expire-channels.js index 4e22dfce4..a42a3af58 100644 --- a/expire-channels.js +++ b/expire-channels.js @@ -7,7 +7,6 @@ var config; try { config = require('./config'); } catch (e) { - console.log("You can customize the configuration by copying config.example.js to config.js"); config = require('./config.example'); } diff --git a/pinneddata.js b/pinneddata.js index d7848c7df..378f34ad7 100644 --- a/pinneddata.js +++ b/pinneddata.js @@ -47,103 +47,126 @@ const dsFileStats = {}; const out = []; const pinned = {}; -nThen((waitFor) => { - Fs.readdir('./datastore', waitFor((err, list) => { - if (err) { throw err; } - dirList = list; - })); -}).nThen((waitFor) => { - dirList.forEach((f) => { - sema.take((returnAfter) => { - Fs.readdir('./datastore/' + f, waitFor(returnAfter((err, list2) => { - if (err) { throw err; } - list2.forEach((ff) => { fileList.push('./datastore/' + f + '/' + ff); }); - }))); +module.exports.load = function (config, cb) { + nThen((waitFor) => { + Fs.readdir('./datastore', waitFor((err, list) => { + if (err) { throw err; } + dirList = list; + })); + }).nThen((waitFor) => { + dirList.forEach((f) => { + sema.take((returnAfter) => { + Fs.readdir('./datastore/' + f, waitFor(returnAfter((err, list2) => { + if (err) { throw err; } + list2.forEach((ff) => { fileList.push('./datastore/' + f + '/' + ff); }); + }))); + }); }); - }); -}).nThen((waitFor) => { + }).nThen((waitFor) => { - Fs.readdir('./blob', waitFor((err, list) => { - if (err) { throw err; } - dirList = list; - })); -}).nThen((waitFor) => { - dirList.forEach((f) => { - sema.take((returnAfter) => { - Fs.readdir('./blob/' + f, waitFor(returnAfter((err, list2) => { - if (err) { throw err; } - list2.forEach((ff) => { fileList.push('./blob/' + f + '/' + ff); }); - }))); + Fs.readdir('./blob', waitFor((err, list) => { + if (err) { throw err; } + dirList = list; + })); + }).nThen((waitFor) => { + dirList.forEach((f) => { + sema.take((returnAfter) => { + Fs.readdir('./blob/' + f, waitFor(returnAfter((err, list2) => { + if (err) { throw err; } + list2.forEach((ff) => { fileList.push('./blob/' + f + '/' + ff); }); + }))); + }); }); - }); -}).nThen((waitFor) => { - fileList.forEach((f) => { - sema.take((returnAfter) => { - Fs.stat(f, waitFor(returnAfter((err, st) => { - if (err) { throw err; } - st.filename = f; - dsFileStats[f.replace(/^.*\/([^\/\.]*)(\.ndjson)?$/, (all, a) => (a))] = st; - }))); + }).nThen((waitFor) => { + fileList.forEach((f) => { + sema.take((returnAfter) => { + Fs.stat(f, waitFor(returnAfter((err, st) => { + if (err) { throw err; } + st.filename = f; + dsFileStats[f.replace(/^.*\/([^\/\.]*)(\.ndjson)?$/, (all, a) => (a))] = st; + }))); + }); }); - }); -}).nThen((waitFor) => { - Fs.readdir('./pins', waitFor((err, list) => { - if (err) { throw err; } - dirList = list; - })); -}).nThen((waitFor) => { - fileList.splice(0, fileList.length); - dirList.forEach((f) => { - sema.take((returnAfter) => { - Fs.readdir('./pins/' + f, waitFor(returnAfter((err, list2) => { - if (err) { throw err; } - list2.forEach((ff) => { fileList.push('./pins/' + f + '/' + ff); }); - }))); + }).nThen((waitFor) => { + Fs.readdir('./pins', waitFor((err, list) => { + if (err) { throw err; } + dirList = list; + })); + }).nThen((waitFor) => { + fileList.splice(0, fileList.length); + dirList.forEach((f) => { + sema.take((returnAfter) => { + Fs.readdir('./pins/' + f, waitFor(returnAfter((err, list2) => { + if (err) { throw err; } + list2.forEach((ff) => { fileList.push('./pins/' + f + '/' + ff); }); + }))); + }); }); - }); -}).nThen((waitFor) => { - fileList.forEach((f) => { - sema.take((returnAfter) => { - Fs.readFile(f, waitFor(returnAfter((err, content) => { - if (err) { throw err; } - const hashes = hashesFromPinFile(content.toString('utf8'), f); - const size = sizeForHashes(hashes, dsFileStats); - if (process.argv.indexOf('--unpinned') > -1) { - hashes.forEach((x) => { pinned[x] = 1; }); - } else { - out.push([f, Math.floor(size / (1024 * 1024))]); + }).nThen((waitFor) => { + fileList.forEach((f) => { + sema.take((returnAfter) => { + Fs.readFile(f, waitFor(returnAfter((err, content) => { + if (err) { throw err; } + const hashes = hashesFromPinFile(content.toString('utf8'), f); + const size = sizeForHashes(hashes, dsFileStats); + if (config.unpinned) { + hashes.forEach((x) => { pinned[x] = 1; }); + } else { + out.push([f, Math.floor(size / (1024 * 1024))]); + } + }))); + }); + }); + }).nThen(() => { + if (config.unpinned) { + let before = Infinity; + if (config.olderthan) { + before = config.olderthan; + if (isNaN(before)) { + return void cb('--olderthan error [' + config.olderthan + '] not a valid date'); } - }))); - }); + } + let blobsbefore = before; + if (config.blobsolderthan) { + blobsbefore = config.blobsolderthan; + if (isNaN(blobsbefore)) { + return void cb('--blobsolderthan error [' + config.blobsolderthan + '] not a valid date'); + } + } + let files = []; + Object.keys(dsFileStats).forEach((f) => { + if (!(f in pinned)) { + const isBlob = dsFileStats[f].filename.indexOf('.ndjson') === -1; + if ((+dsFileStats[f].atime) >= ((isBlob) ? blobsbefore : before)) { return; } + files.push({ + filename: dsFileStats[f].filename, + size: dsFileStats[f].size, + atime: dsFileStats[f].atime + }); + } + }); + cb(null, files); + } else { + out.sort((a,b) => (a[1] - b[1])); + cb(null, out.slice()); + } }); -}).nThen(() => { - if (process.argv.indexOf('--unpinned') > -1) { - const ot = process.argv.indexOf('--olderthan'); - let before = Infinity; - if (ot > -1) { - before = new Date(process.argv[ot+1]); - if (isNaN(before)) { - throw new Error('--olderthan error [' + process.argv[ot+1] + '] not a valid date'); - } +}; + +if (!module.parent) { + let config = {}; + if (process.argv.indexOf('--unpinned') > -1) { config.unpinned = true; } + const ot = process.argv.indexOf('--olderthan'); + config.olderthan = ot > -1 && new Date(process.argv[ot+1]); + const bot = process.argv.indexOf('--blobsolderthan'); + config.blobsolderthan = bot > -1 && new Date(process.argv[bot+1]); + module.exports.load(config, function (err, data) { + if (err) { throw new Error(err); } + if (!Array.isArray(data)) { return; } + if (config.unpinned) { + data.forEach((f) => { console.log(f.filename + " " + f.size + " " + (+f.atime)); }); + } else { + data.forEach((x) => { console.log(x[0] + ' ' + x[1] + ' MB'); }); } - const bot = process.argv.indexOf('--blobsolderthan'); - let blobsbefore = before; - if (bot > -1) { - blobsbefore = new Date(process.argv[bot+1]); - if (isNaN(blobsbefore)) { - throw new Error('--blobsolderthan error [' + process.argv[bot+1] + '] not a valid date'); - } - } - Object.keys(dsFileStats).forEach((f) => { - if (!(f in pinned)) { - const isBlob = dsFileStats[f].filename.indexOf('.ndjson') === -1; - if ((+dsFileStats[f].mtime) >= ((isBlob) ? blobsbefore : before)) { return; } - console.log(dsFileStats[f].filename + " " + dsFileStats[f].size + " " + - (+dsFileStats[f].mtime)); - } - }); - } else { - out.sort((a,b) => (a[1] - b[1])); - out.forEach((x) => { console.log(x[0] + ' ' + x[1] + ' MB'); }); - } -}); + }); +} diff --git a/www/common/common-interface.js b/www/common/common-interface.js index d0c0e1961..4822e357b 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -555,8 +555,11 @@ define([ $loading = $('#' + LOADING); //.show(); $loading.css('display', ''); $loading.removeClass('cp-loading-hidden'); + $('.cp-loading-spinner-container').show(); if (loadingText) { $('#' + LOADING).find('p').text(loadingText); + } else { + $('#' + LOADING).find('p').text(''); } $container = $loading.find('.cp-loading-container'); } else { @@ -612,7 +615,10 @@ define([ if (exitable) { $(window).focus(); $(window).keydown(function (e) { - if (e.which === 27) { $('#' + LOADING).hide(); } + if (e.which === 27) { + $('#' + LOADING).hide(); + if (typeof(exitable) === "function") { exitable(); } + } }); } }; diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index 7540f4a0b..d612387fa 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -426,15 +426,7 @@ define([ common.getSframeChannel().onReady(waitFor()); }).nThen(function (waitFor) { Test.registerInner(common.getSframeChannel()); - if (!AppConfig.displayCreationScreen) { return; } - var priv = common.getMetadataMgr().getPrivateData(); - if (priv.isNewFile) { - var c = (priv.settings.general && priv.settings.general.creation) || {}; - if (c.skip && !priv.forceCreationScreen) { - return void common.createPad(c, waitFor()); - } - common.getPadCreationScreen(c, waitFor()); - } + common.handleNewFile(waitFor); }).nThen(function (waitFor) { cpNfInner = common.startRealtime({ // really basic operational transform diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 260efeda9..10fd2e9f9 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -187,7 +187,7 @@ define([ upgradeURL: Cryptpad.upgradeURL }, isNewFile: isNewFile, - isDeleted: window.location.hash.length > 0, + isDeleted: isNewFile && window.location.hash.length > 0, forceCreationScreen: forceCreationScreen }; for (var k in additionalPriv) { metaObj.priv[k] = additionalPriv[k]; } @@ -666,8 +666,9 @@ define([ Utils.Feedback.reportAppUsage(); if (!realtime) { return; } - if (isNewFile && Utils.LocalStore.isLoggedIn() - && AppConfig.displayCreationScreen && cfg.useCreationScreen) { return; } + if (isNewFile && cfg.useCreationScreen) { return; } + //if (isNewFile && Utils.LocalStore.isLoggedIn() + // && AppConfig.displayCreationScreen && cfg.useCreationScreen) { return; } startRealtime(); }); diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 3f4070eaf..df6f77e87 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -167,6 +167,30 @@ define([ }; // Store + funcs.handleNewFile = function (waitFor) { + var priv = ctx.metadataMgr.getPrivateData(); + if (priv.isNewFile) { + var c = (priv.settings.general && priv.settings.general.creation) || {}; + var skip = !AppConfig.displayCreationScreen || (c.skip && !priv.forceCreationScreen); + // If this is a new file but we have a hash in the URL and pad creation screen is + // not displayed, then display an error... + if (priv.isDeleted && (!funcs.isLoggedIn() || skip)) { + UI.errorLoadingScreen(Messages.inactiveError, false, function () { + UI.addLoadingScreen(); + return void funcs.createPad({}, waitFor()); + }); + return; + } + // Otherwise, if we don't display the screen, it means it is not a deleted pad + // so we can continue and start realtime... + if (!funcs.isLoggedIn() || skip) { + return void funcs.createPad(c, waitFor()); + } + // If we display the pad creation screen, it will handle deleted pads directly + console.log('here'); + funcs.getPadCreationScreen(c, waitFor()); + } + }; funcs.createPad = function (cfg, cb) { ctx.sframeChan.query("Q_CREATE_PAD", { owned: cfg.owned, diff --git a/www/common/toolbar3.js b/www/common/toolbar3.js index e014503c6..df97cf072 100644 --- a/www/common/toolbar3.js +++ b/www/common/toolbar3.js @@ -593,7 +593,7 @@ define([ }; var createUnpinnedWarning0 = function (toolbar, config) { - if (true) { return; } // stub this call since it won't make it into the next release + //if (true) { return; } // stub this call since it won't make it into the next release if (Common.isLoggedIn()) { return; } var pd = config.metadataMgr.getPrivateData(); var o = pd.origin; diff --git a/www/poll/inner.js b/www/poll/inner.js index 8f31116a1..94d732a7f 100644 --- a/www/poll/inner.js +++ b/www/poll/inner.js @@ -1274,16 +1274,9 @@ define([ }).nThen(function (waitFor) { common.getSframeChannel().onReady(waitFor()); }).nThen(function (waitFor) { - if (!AppConfig.displayCreationScreen) { return; } - var priv = common.getMetadataMgr().getPrivateData(); - if (priv.isNewFile) { - var c = (priv.settings.general && priv.settings.general.creation) || {}; - if (c.skip && !priv.forceCreationScreen) { - return void common.createPad(c, waitFor()); - } - common.getPadCreationScreen(c, waitFor()); - } + common.handleNewFile(waitFor); }).nThen(function (/* waitFor */) { + console.log('here'); Test.registerInner(common.getSframeChannel()); var metadataMgr = common.getMetadataMgr(); APP.locked = APP.readOnly = metadataMgr.getPrivateData().readOnly; diff --git a/www/whiteboard/inner.js b/www/whiteboard/inner.js index 8d2621aaf..3c540fe98 100644 --- a/www/whiteboard/inner.js +++ b/www/whiteboard/inner.js @@ -662,15 +662,7 @@ define([ }).nThen(function (waitFor) { common.getSframeChannel().onReady(waitFor()); }).nThen(function (waitFor) { - if (!AppConfig.displayCreationScreen) { return; } - var priv = common.getMetadataMgr().getPrivateData(); - if (priv.isNewFile) { - var c = (priv.settings.general && priv.settings.general.creation) || {}; - if (c.skip && !priv.forceCreationScreen) { - return void common.createPad(c, waitFor()); - } - common.getPadCreationScreen(c, waitFor()); - } + common.handleNewFile(waitFor); }).nThen(function (/*waitFor*/) { andThen(common); }); From 66d83dc045db43b7f29ad88c4c07cf138215441c Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 27 Feb 2018 15:13:39 +0100 Subject: [PATCH 08/21] update version --- customize.dist/pages.js | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/customize.dist/pages.js b/customize.dist/pages.js index 37bdc5b42..55beb2884 100644 --- a/customize.dist/pages.js +++ b/customize.dist/pages.js @@ -72,7 +72,7 @@ define([ ]) ]) ]), - h('div.cp-version-footer', "CryptPad v1.26.0 (undefined)") + h('div.cp-version-footer', "CryptPad v1.27.0 (null)") ]); }; diff --git a/package.json b/package.json index 16e4f69fb..01dd38ab1 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "cryptpad", "description": "realtime collaborative visual editor with zero knowlege server", - "version": "1.26.0", + "version": "1.27.0", "dependencies": { "chainpad-server": "^2.0.0", "express": "~4.10.1", From 60b2384885258f3413057d811343e89b49545d3e Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 27 Feb 2018 17:38:29 +0100 Subject: [PATCH 09/21] Move initial state into a help block --- customize.dist/pages.js | 6 -- .../src/less2/include/ckeditor-fix.less | 19 ------- customize.dist/src/less2/include/toolbar.less | 32 +++++++++++ customize.dist/translations/messages.el.js | 15 +---- customize.dist/translations/messages.es.js | 9 +-- customize.dist/translations/messages.fr.js | 15 +---- customize.dist/translations/messages.js | 15 +---- customize.dist/translations/messages.pt-br.js | 15 +---- customize.dist/translations/messages.ro.js | 14 +---- customize.dist/translations/messages.zh.js | 17 +----- www/code/app-code.less | 18 ++++++ www/code/inner.js | 47 ++++++++++++++-- www/common/common-ui-elements.js | 39 +++++++++++++ www/common/sframe-common-codemirror.js | 1 - www/common/sframe-common.js | 1 + www/common/toolbar3.js | 25 +-------- www/pad/app-pad.less | 38 ++++++++++--- www/pad/inner.js | 36 ++++++++---- www/poll/inner.js | 56 +++++-------------- www/slide/app-slide.less | 10 ++++ www/slide/inner.js | 15 ++++- www/slide/slide.js | 14 +++++ 22 files changed, 251 insertions(+), 206 deletions(-) diff --git a/customize.dist/pages.js b/customize.dist/pages.js index 37bdc5b42..32eab821d 100644 --- a/customize.dist/pages.js +++ b/customize.dist/pages.js @@ -819,12 +819,6 @@ define([ appToolbar(), h('div#cp-app-poll-content', [ h('div#cp-app-poll-form', [ - h('div#cp-app-poll-help', [ - h('h1', 'CryptPoll'), - setHTML(h('h2'), Msg.poll_subtitle), - h('p', Msg.poll_p_save), - h('p', Msg.poll_p_encryption) - ]), h('div.cp-app-poll-realtime', [ h('br'), h('div', [ diff --git a/customize.dist/src/less2/include/ckeditor-fix.less b/customize.dist/src/less2/include/ckeditor-fix.less index 96e6d893f..98672bd86 100644 --- a/customize.dist/src/less2/include/ckeditor-fix.less +++ b/customize.dist/src/less2/include/ckeditor-fix.less @@ -3,28 +3,9 @@ .cke_reset_all * { color: inherit; } - #cke_editor1 .cke_inner { - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - display: flex; - flex-flow: column; - } .cke_toolbox_main { display: inline-block; } - #cke_1_contents { - flex: 1; - margin-top: -1px; - display: flex; - overflow: visible; - iframe { - min-height: 100%; - width: 100%; - } - } .cke_toolbox .cp-toolbar-history { input.gotoInput { // TODO padding: 3px 3px; diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less index f8cd43fd0..a070c8af6 100644 --- a/customize.dist/src/less2/include/toolbar.less +++ b/customize.dist/src/less2/include/toolbar.less @@ -255,6 +255,38 @@ &.cp-markdown-help { float: right; } } } + + // TODO put in a different less file + .cp-help-container { + position: relative; + background-color: lighten(@bg-color, 15%); + &.cp-help-hidden { + display: none; + } + + .cp-help-close { + position: absolute; + top: 5px; + right: 5px; + } + .cp-help-text { + color: @color; + margin: 0; + padding: 15px; + h1 { + font-size: 20px; + } + h2 { + font-size: 18px; + } + h3 { + font-size: 16px; + } + ul, ol, p { margin: 0; } + } + } + + .cp-toolbar-userlist-drawer { background-color: @bg-color; color: @color; diff --git a/customize.dist/translations/messages.el.js b/customize.dist/translations/messages.el.js index 1e30248ec..36a19da87 100644 --- a/customize.dist/translations/messages.el.js +++ b/customize.dist/translations/messages.el.js @@ -714,13 +714,8 @@ define(function () { '

', 'Αυτό είναι CryptPad, ο συνεργατικός επεξεργαστής πραγματικού χρόνου Zero Knowledge. Τα πάντα αποθηκεύονται καθώς πληκτρολογείτε.', '
', - 'Μοιραστείτε τον σύνδεσμο σε αυτό το pad για να το επεξεργαστείτε με φίλους ή χρησιμοποιήστε το κουμπί  Share  για να μοιραστείτε ένα κείμενο με δικαιώματα read-only link το οποίο επιτρέπει να το αναγνώσει κάποιος αλλά όχι να το επεξεργαστεί.', + 'Μοιραστείτε τον σύνδεσμο σε αυτό το pad για να το επεξεργαστείτε με φίλους ή χρησιμοποιήστε το κουμπί για να μοιραστείτε ένα κείμενο με δικαιώματα read-only link το οποίο επιτρέπει να το αναγνώσει κάποιος αλλά όχι να το επεξεργαστεί.', '

', - - '

', - 'Εμπρός, απλά ξεκινήστε να πληκτρολογείτε...', - '

', - '

 

' ].join(''); out.codeInitialState = [ @@ -732,14 +727,6 @@ define(function () { out.slideInitialState = [ '# CryptSlide\n', - '* Αυτός είναι ένας συνεργατικός επεξεργαστής πραγματικού χρόνου με τεχνολογία zero knowledge.\n', - '* Ό,τι πληκτρολογείτε εδώ είναι κρυπτογραφημένο έτσι ώστε μόνο οι άνθρωποι που έχουν τον σύνδεσμο να μπορούν να έχουν πρόσβαση.\n', - '* Ακόμη κι ο διακομιστής δεν μπορεί να δει τι πληκτρολογείτε.\n', - '* Ό,τι δείτε εδώ, ό,τι ακούσετε εδώ, όταν φύγετε από εδώ, θα παραμείνει εδώ.\n', - '\n', - '---', - '\n', - '# Πως να το χρησιμοποιήσετε\n', '1. Γράψτε τα περιεχόμενα των slides σας χρησιμοποιώντας σύνταξη markdown\n', ' - Μάθετε περισσότερα για την σύνταξη markdown [εδώ](http://www.markdowntutorial.com/)\n', '2. Διαχωρίστε τα slides σας με ---\n', diff --git a/customize.dist/translations/messages.es.js b/customize.dist/translations/messages.es.js index 6df44d691..9e246294f 100644 --- a/customize.dist/translations/messages.es.js +++ b/customize.dist/translations/messages.es.js @@ -294,17 +294,12 @@ define(function () { '

', 'Esto es CryptPad, el editor colaborativo en tiempo real Zero Knowledge. Todo está guardado cuando escribes.', '
', - 'Comparte el enlace a este pad para editar con amigos o utiliza el botón  Compartir  para obtener un enlace sólo lectura que permite leer pero no escribir.', + 'Comparte el enlace a este pad para editar con amigos o utiliza el botón para obtener un enlace sólo lectura que permite leer pero no escribir.', '

', - - '

', - 'Vamos, empieza a escribir...', - '

', - '

 

' ].join(''); out.codeInitialState = "/*\n Esto es CryptPad, el editor colaborativo en tiempo real zero knowledge.\n Lo que escribes aquí está cifrado de manera que sólo las personas con el enlace pueden acceder a ello.\n Incluso el servidor no puede ver lo que escribes.\n Lo que ves aquí, lo que escuchas aquí, cuando sales, se queda aquí\n*/"; - out.slideInitialState = "# CryptSlide\n* Esto es CryptPad, el editor colaborativo en tiempo real zero knowledge.\n* Lo que escribes aquí está cifrado de manera que sólo las personas con el enlace pueden acceder a ello.\n* Incluso el servidor no puede ver lo que escribes.\n* Lo que ves aquí, lo que escuchas aquí, cuando sales, se queda aquí\n\n---\n# Cómo utilizarlo\n1. Escribe tu contenido en Markdown\n - Puedes aprender más sobre Markdown [aquí](http://www.markdowntutorial.com/)\n2. Separa tus diapositivas con ---\n3. Haz clic en \"Presentar\" para ver el resultado - Tus diapositivas se actualizan en tiempo real"; + out.slideInitialState = "# CryptSlide\n1. Escribe tu contenido en Markdown\n - Puedes aprender más sobre Markdown [aquí](http://www.markdowntutorial.com/)\n2. Separa tus diapositivas con ---\n3. Haz clic en \"Presentar\" para ver el resultado - Tus diapositivas se actualizan en tiempo real"; out.driveReadmeTitle = "¿Qué es CryptPad?"; out.readme_welcome = "¡Bienvenido a CryptPad!"; out.readme_p1 = "Bienvenido a CryptPad, aquí podrás anotar cosas solo o con otra gente."; diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 5e681e699..08b974821 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -780,13 +780,8 @@ define(function () { '

', 'Voici CryptPad, l\'éditeur collaboratif en temps-réel Zero Knowledge. Tout est sauvegardé dés que vous le tapez.', '
', - 'Partagez le lien vers ce pad avec des amis ou utilisez le bouton  Partager  pour obtenir le lien de lecture-seule, qui permet la lecture mais non la modification.', + 'Partagez le lien vers ce pad avec des amis ou utilisez le bouton pour obtenir le lien de lecture-seule, qui permet la lecture mais non la modification.', '

', - '

', - '', - 'Lancez-vous, commencez à taper...', - '

', - '

 

' ].join(''); out.codeInitialState = [ @@ -798,14 +793,6 @@ define(function () { out.slideInitialState = [ '# CryptSlide\n', - '* Voici CryptPad, l\'éditeur collaboratif en temps-réel Zero Knowledge.\n', - '* Ce que vous tapez ici est chiffré de manière que seules les personnes avec le lien peuvent y accéder.\n', - '* Même le serveur est incapable de voir ce que vous tapez.\n', - '* Ce que vous voyez ici, ce que vous entendez, quand vous partez, ça reste ici.\n', - '\n', - '---', - '\n', - '# Comment l\'utiliser\n', '1. Écrivez le contenu de votre présentation avec la syntaxe Markdown\n', ' - Apprenez à utiliser markdown en cliquant [ici](http://www.markdowntutorial.com/)\n', '2. Séparez vos slides avec ---\n', diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index c5f7bcd8c..1e15eac1c 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -816,13 +816,8 @@ define(function () { '

', 'This is CryptPad, the Zero Knowledge realtime collaborative editor. Everything is saved as you type.', '
', - 'Share the link to this pad to edit with friends or use the  Share  button to share a read-only link which allows viewing but not editing.', + 'Share the link to this pad to edit with friends or use the button to share a read-only link which allows viewing but not editing.', '

', - - '

', - 'Go ahead, just start typing...', - '

', - '

 

' ].join(''); out.codeInitialState = [ @@ -834,14 +829,6 @@ define(function () { out.slideInitialState = [ '# CryptSlide\n', - '* This is a zero knowledge realtime collaborative editor.\n', - '* What you type here is encrypted so only people who have the link can access it.\n', - '* Even the server cannot see what you type.\n', - '* What you see here, what you hear here, when you leave here, let it stay here.\n', - '\n', - '---', - '\n', - '# How to use\n', '1. Write your slides content using markdown syntax\n', ' - Learn more about markdown syntax [here](http://www.markdowntutorial.com/)\n', '2. Separate your slides with ---\n', diff --git a/customize.dist/translations/messages.pt-br.js b/customize.dist/translations/messages.pt-br.js index 79ba513c3..fbf63d067 100644 --- a/customize.dist/translations/messages.pt-br.js +++ b/customize.dist/translations/messages.pt-br.js @@ -486,13 +486,8 @@ define(function () { '

', 'This is CryptPad, the Zero Knowledge realtime collaborative editor. Everything is saved as you type.', '
', - 'Share the link to this pad to edit with friends or use the  Share  button to share a read-only link which allows viewing but not editing.', + 'Share the link to this pad to edit with friends or use the button to share a read-only link which allows viewing but not editing.', '

', - - '

', - 'Go ahead, just start typing...', - '

', - '

 

' ].join(''); out.codeInitialState = [ @@ -504,14 +499,6 @@ define(function () { out.slideInitialState = [ '# CryptSlide\n', - '* This is a zero knowledge realtime collaborative editor.\n', - '* What you type here is encrypted so only people who have the link can access it.\n', - '* Even the server cannot see what you type.\n', - '* What you see here, what you hear here, when you leave here, let it stay here.\n', - '\n', - '---', - '\n', - '# How to use\n', '1. Write your slides content using markdown syntax\n', ' - Learn more about markdown syntax [here](http://www.markdowntutorial.com/)\n', '2. Separate your slides with ---\n', diff --git a/customize.dist/translations/messages.ro.js b/customize.dist/translations/messages.ro.js index 14a55f8ab..56ec8b05d 100644 --- a/customize.dist/translations/messages.ro.js +++ b/customize.dist/translations/messages.ro.js @@ -4,16 +4,6 @@ define(function () { out.main_title = "CryptPad: Zero Knowledge, Colaborare în timp real"; out.main_slogan = "Puterea stă în cooperare - Colaborarea este cheia"; - out.type = {}; - out.pad = "Rich text"; - out.code = "Code"; - out.poll = "Poll"; - out.slide = "Presentation"; - out.drive = "Drive"; - out.whiteboard = "Whiteboard"; - out.file = "File"; - out.media = "Media"; - out.button_newpad = "Filă Text Nouă"; out.button_newcode = "Filă Cod Nouă"; out.button_newpoll = "Sondaj Nou"; @@ -330,9 +320,9 @@ define(function () { out.header_france = "With \"love\" from \"Franța\"/ by \"XWiki"; out.header_support = " \"OpenPaaS-ng\""; out.header_logoTitle = "Mergi la pagina principală"; - out.initialState = "

Acesta este CryptPad, editorul colaborativ bazat pe tehnologia Zero Knowledge în timp real. Totul este salvat pe măsură ce scrii.
Partajează link-ul către acest pad pentru a edita cu prieteni sau folosește  Share  butonul pentru a partaja read-only link permițând vizualizarea dar nu și editarea.

Îndrăznește, începe să scrii...

 

"; + out.initialState = "

Acesta este CryptPad, editorul colaborativ bazat pe tehnologia Zero Knowledge în timp real. Totul este salvat pe măsură ce scrii.
Partajează link-ul către acest pad pentru a edita cu prieteni sau folosește butonul pentru a partaja read-only link permițând vizualizarea dar nu și editarea.

"; out.codeInitialState = "/*\n Acesta este editorul colaborativ de cod bazat pe tehnologia Zero Knowledge CryptPad.\n Ce scrii aici este criptat, așa că doar oamenii care au link-ul pot să-l acceseze.\n Poți să alegi ce limbaj de programare pus n evidență și schema de culori UI n dreapta sus.\n*/"; - out.slideInitialState = "# CryptSlide\n* Acesta este un editor colaborativ bazat pe tehnologia Zero Knowledge.\n* Ce scrii aici este criptat, așa că doar oamenii care au link-ul pot să-l acceseze.\n* Nici măcar serverele nu au acces la ce scrii tu.\n* Ce vezi aici, ce auzi aici, atunci când pleci, lași aici.\n\n-\n# Cum se folosește\n1. Scrie-ți conținutul slide-urilor folosind sintaxa markdown\n - Află mai multe despre sintaxa markdown [aici](http://www.markdowntutorial.com/)\n2. Separă-ți slide-urile cu -\n3. Click pe butonul \"Play\" pentru a vedea rezultatele - Slide-urile tale sunt actualizate în timp real."; + out.slideInitialState = "# CryptSlide\n1. Scrie-ți conținutul slide-urilor folosind sintaxa markdown\n - Află mai multe despre sintaxa markdown [aici](http://www.markdowntutorial.com/)\n2. Separă-ți slide-urile cu ---\n3. Click pe butonul \"Play\" pentru a vedea rezultatele - Slide-urile tale sunt actualizate în timp real."; out.driveReadmeTitle = "Ce este CryptPad?"; out.readme_welcome = "Bine ai venit n CryptPad !"; out.readme_p1 = "Bine ai venit în CryptPad, acesta este locul unde îți poți lua notițe, singur sau cu prietenii."; diff --git a/customize.dist/translations/messages.zh.js b/customize.dist/translations/messages.zh.js index c7ac7915a..25b7fe8c8 100644 --- a/customize.dist/translations/messages.zh.js +++ b/customize.dist/translations/messages.zh.js @@ -469,13 +469,8 @@ define(function () { '

', '這是 CryptPad, 零知識即時協作編輯平台,當你輸入時一切已即存好。', '
', - '分享這個工作檔案的網址連結給友人或是使用、  分享  按鈕分享唯讀的連結 其只能看不能編寫。', - '

', - - '

', - '來吧, 開始打字輸入吧...', - '

', - '

 

' + '分享這個工作檔案的網址連結給友人或是使用、 按鈕分享唯讀的連結 其只能看不能編寫。', + '

' ].join(''); out.codeInitialState = [ @@ -487,14 +482,6 @@ define(function () { out.slideInitialState = [ '# CryptSlide\n', - '* 它是零知識即時協作編輯平台。\n', - '* 你所輸入的東西會予以加密,僅有知道此網頁連結者可以接取這份文件。\n', - '* 即便是本站伺服器也不知道你輸入了什麼內容。\n', - '* 你在這裏看到的、你在這裏聽到的、當你離開本站時,讓它就留在這裏吧。\n', - '\n', - '---', - '\n', - '# 如何使用\n', '1. 使用 markdown 語法來寫下你的投影片內容\n', ' - 進一步學習 markdown 語法 [here](http://www.markdowntutorial.com/)\n', '2. 利用 --- 來區隔不同的投影片\n', diff --git a/www/code/app-code.less b/www/code/app-code.less index 463bb07a3..f4153e95d 100644 --- a/www/code/app-code.less +++ b/www/code/app-code.less @@ -74,6 +74,24 @@ } } .markdown_main(); + .cp-app-code-preview-empty { + display: none; + } + &.cp-app-code-preview-isempty { + display: flex; + align-items: center; + justify-content: center; + #cp-app-code-preview-content { + display: none; + } + .cp-app-code-preview-empty { + //flex: 1 1 auto; + max-height: 100%; + max-width: 100%; + display: block; + opacity: 0.2; + } + } } #cp-app-code-preview-content { diff --git a/www/code/inner.js b/www/code/inner.js index e7f080c02..091baa0e8 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -63,6 +63,31 @@ define([ 'xml', ]); + var mkMarkdownTb = function (editor, framework) { + var $codeMirrorContainer = $('#cp-app-code-container'); + var markdownTb = framework._.sfCommon.createMarkdownToolbar(editor); + $codeMirrorContainer.prepend(markdownTb.toolbar); + + framework._.toolbar.$rightside.append(markdownTb.button); + + var modeChange = function (mode) { + if (['markdown', 'gfm'].indexOf(mode) !== -1) { return void markdownTb.setState(true); } + markdownTb.setState(false); + }; + + return { + modeChange: modeChange + }; + }; + var mkHelpMenu = function (framework) { + var $codeMirrorContainer = $('#cp-app-code-container'); + var helpMenu = framework._.sfCommon.createHelpMenu(); + $codeMirrorContainer.prepend(helpMenu.menu); + + $(helpMenu.text).html(DiffMd.render(Messages.codeInitialState)); + + framework._.toolbar.$rightside.append(helpMenu.button); + }; var mkPreviewPane = function (editor, CodeMirror, framework, isPresentMode) { var $previewContainer = $('#cp-app-code-preview'); var $preview = $('#cp-app-code-preview-content'); @@ -70,12 +95,20 @@ define([ var $codeMirrorContainer = $('#cp-app-code-container'); var $codeMirror = $('.CodeMirror'); - var markdownTb = framework._.sfCommon.createMarkdownToolbar(editor); - $codeMirrorContainer.prepend(markdownTb.toolbar); + $('', { + src: '/customize/main-favicon.png', + alt: '', + class: 'cp-app-code-preview-empty' + }).appendTo($previewContainer); var $previewButton = framework._.sfCommon.createButton(null, true); var forceDrawPreview = function () { try { + if (editor.getValue() === '') { + $previewContainer.addClass('cp-app-code-preview-isempty'); + return; + } + $previewContainer.removeClass('cp-app-code-preview-isempty'); DiffMd.apply(DiffMd.render(editor.getValue()), $preview); } catch (e) { console.error(e); } }; @@ -118,7 +151,7 @@ define([ } }); - framework._.toolbar.$rightside.append($previewButton).append(markdownTb.button); + framework._.toolbar.$rightside.append($previewButton); $preview.click(function (e) { if (!e.target) { return; } @@ -145,7 +178,6 @@ define([ } } }); - markdownTb.setState(true); return; } $editorContainer.removeClass('cp-app-code-present'); @@ -153,7 +185,6 @@ define([ $previewContainer.hide(); $previewButton.removeClass('active'); $codeMirrorContainer.addClass('cp-app-code-fullpage'); - markdownTb.setState(false); }; var isVisible = function () { @@ -252,8 +283,12 @@ define([ var common = framework._.sfCommon; var previewPane = mkPreviewPane(editor, CodeMirror, framework, isPresentMode); + var markdownTb = mkMarkdownTb(editor, framework); + mkHelpMenu(framework); + var evModeChange = Util.mkEvent(); evModeChange.reg(previewPane.modeChange); + evModeChange.reg(markdownTb.modeChange); mkIndentSettings(editor, framework._.cpNfInner.metadataMgr); CodeMirror.init(framework.localChange, framework._.title, framework._.toolbar); @@ -315,7 +350,7 @@ define([ }); framework.onDefaultContentNeeded(function () { - editor.setValue(Messages.codeInitialState); + editor.setValue(''); //Messages.codeInitialState); }); framework.setFileExporter(CodeMirror.getContentExtension, CodeMirror.fileExporter); diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 2a892cae6..502f18bea 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -855,6 +855,45 @@ define([ }; }; + UIElements.createHelpMenu = function (common) { + var type = common.getMetadataMgr().getMetadata().type || 'pad'; + + var text = h('p.cp-help-text'); + var closeButton = h('span.cp-help-close.fa.fa-window-close'); + var $toolbarButton = common.createButton('', true).addClass('cp-toolbar-button-active'); + var help = h('div.cp-help-container', [ + closeButton, + text + ]); + + var toggleHelp = function (forceClose) { + if ($(help).hasClass('cp-help-hidden')) { + if (forceClose) { return; } + common.setAttribute(['hideHelp', type], false); + $toolbarButton.addClass('cp-toolbar-button-active'); + return void $(help).removeClass('cp-help-hidden'); + } + $toolbarButton.removeClass('cp-toolbar-button-active'); + $(help).addClass('cp-help-hidden'); + common.setAttribute(['hideHelp', type], true); + }; + + $(closeButton).click(function () { toggleHelp(true); }); + $toolbarButton.click(function () { + toggleHelp(); + }); + + common.getAttribute(['hideHelp', type], function (err, val) { + if (val === true) { toggleHelp(true); } + }); + + return { + menu: help, + button: $toolbarButton, + text: text + }; + }; + // Avatars // Enable mediatags diff --git a/www/common/sframe-common-codemirror.js b/www/common/sframe-common-codemirror.js index cb507c2a8..4386e22f0 100644 --- a/www/common/sframe-common-codemirror.js +++ b/www/common/sframe-common-codemirror.js @@ -141,7 +141,6 @@ define([ mode: defaultMode || "javascript", readOnly: true }); - //editor.setValue(Messages.codeInitialState); editor.focus(); var setMode = exp.setMode = function (mode, cb) { diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index df6f77e87..d8804349b 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -90,6 +90,7 @@ define([ funcs.updateTags = callWithCommon(UIElements.updateTags); funcs.createLanguageSelector = callWithCommon(UIElements.createLanguageSelector); funcs.createMarkdownToolbar = callWithCommon(UIElements.createMarkdownToolbar); + funcs.createHelpMenu = callWithCommon(UIElements.createHelpMenu); funcs.getPadCreationScreen = callWithCommon(UIElements.getPadCreationScreen); funcs.createNewPadModal = callWithCommon(UIElements.createNewPadModal); funcs.onServerError = callWithCommon(UIElements.onServerError); diff --git a/www/common/toolbar3.js b/www/common/toolbar3.js index df97cf072..a09d13239 100644 --- a/www/common/toolbar3.js +++ b/www/common/toolbar3.js @@ -377,38 +377,15 @@ define([ config.$contentContainer.prepend($content); } - var $ck = config.$container.find('.cke_toolbox_main'); - var mobile = $('body').width() <= 600; var hide = function () { $content.hide(); $button.removeClass('cp-toolbar-button-active'); - $ck.css({ - 'padding-left': '', - }); }; var show = function () { if (Bar.isEmbed) { $content.hide(); return; } $content.show(); - if (mobile) { - $ck.hide(); - } $button.addClass('cp-toolbar-button-active'); - $ck.css({ - 'padding-left': '175px', - }); - var h = $ck.is(':visible') ? -$ck.height() : 0; - $content.css('margin-top', h+'px'); }; - $(window).on('cryptpad-ck-toolbar', function () { - if (mobile && $ck.is(':visible')) { return void hide(); } - if ($content.is(':visible')) { return void show(); } - hide(); - }); - $(window).on('resize', function () { - mobile = $('body').width() <= 600; - var h = $ck.is(':visible') ? -$ck.height() : 0; - $content.css('margin-top', h+'px'); - }); $closeIcon.click(function () { Common.setAttribute(['toolbar', 'userlist-drawer'], false); hide(); @@ -423,7 +400,7 @@ define([ }); show(); Common.getAttribute(['toolbar', 'userlist-drawer'], function (err, val) { - if (val === false || mobile) { return void hide(); } + if (val === false) { return void hide(); } show(); }); diff --git a/www/pad/app-pad.less b/www/pad/app-pad.less index 742163285..9e1b1da78 100644 --- a/www/pad/app-pad.less +++ b/www/pad/app-pad.less @@ -15,19 +15,41 @@ padding: 0px; display: flex; } - #cke_1_toolbox { - display: inline-flex; - width: 100%; - flex-flow: column; + .cke_toolbox_main { background-color: @colortheme_pad-toolbar-bg; - } - #cke_1_toolbox .cke_toolbar { - height: 28px; - padding: 2px 0; + .cke_toolbar { + height: 28px; + padding: 2px 0; + } } .cke_wysiwyg_frame { min-width: 60%; } + #cke_1_toolbox { + flex: 1; + } + #cke_editor1 { + display: flex; + flex-flow: column; + height: 100%; + border: 0; + > .cke_inner { + flex: 1; + position: unset; + display: flex; + margin-top: -1px; + #cke_1_contents { + flex: 1; + display: flex; + flex-flow: column; + height: auto !important; + iframe { + flex: 1; + } + } + } + } + } .cke_wysiwyg_frame { diff --git a/www/pad/inner.js b/www/pad/inner.js index 22ec21e40..c1a2adbf2 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -136,6 +136,16 @@ define([ check(); }; + var mkHelpMenu = function (framework) { + var $toolbarContainer = $('.cke_toolbox_main'); + var helpMenu = framework._.sfCommon.createHelpMenu(); + $toolbarContainer.before(helpMenu.menu); + + $(helpMenu.text).html(Messages.initialState); + + framework._.toolbar.$rightside.append(helpMenu.button); + }; + var mkDiffOptions = function (cursor, readOnly) { return { preDiffApply: function (info) { @@ -269,8 +279,6 @@ define([ element: $bar.find('.cke_toolbox_main') }; var onClick = function (visible) { - $(window).trigger('resize'); - $(window).trigger('cryptpad-ck-toolbar'); framework._.sfCommon.setAttribute(['pad', 'showToolbar'], visible); }; framework._.sfCommon.getAttribute(['pad', 'showToolbar'], function (err, data) { @@ -324,12 +332,12 @@ define([ var andThen2 = function (editor, Ckeditor, framework) { var mediaTagMap = {}; var $bar = $('#cke_1_toolbox'); + var $contentContainer = $('#cke_1_contents'); var $html = $bar.closest('html'); var $faLink = $html.find('head link[href*="/bower_components/components-font-awesome/css/font-awesome.min.css"]'); if ($faLink.length) { $html.find('iframe').contents().find('head').append($faLink.clone()); } - var ml = Ckeditor.instances.editor1.plugins.magicline.backdoor.that.line.$; [ml, ml.parentElement].forEach(function (el) { el.setAttribute('class', 'non-realtime'); @@ -352,6 +360,8 @@ define([ } }; + mkHelpMenu(framework); + framework.onEditableChange(function (unlocked) { if (!framework.isReadOnly()) { $(inner).attr('contenteditable', '' + Boolean(unlocked)); @@ -421,7 +431,7 @@ define([ $bar.find('#cke_1_toolbar_collapser').hide(); if (!framework.isReadOnly()) { - addToolbarHideBtn(framework, $bar); + addToolbarHideBtn(framework, $contentContainer); } else { $('.cke_toolbox_main').hide(); } @@ -466,9 +476,7 @@ define([ }); }); - framework.onDefaultContentNeeded(function () { - documentBody.innerHTML = Messages.initialState; - }); + framework.onDefaultContentNeeded(function () { }); var importMediaTags = function (dom, cb) { var $dom = $(dom); @@ -561,9 +569,9 @@ define([ nThen(function (waitFor) { Framework.create({ toolbarContainer: '#cke_1_toolbox', - contentContainer: '#cke_1_contents', + contentContainer: '#cke_editor1 > .cke_inner', patchTransformer: ChainPad.NaiveJSONTransformer, - thumbnail: { + /*thumbnail: { getContainer: function () { return $('iframe').contents().find('html')[0]; }, filter: function (el, before) { if (before) { @@ -584,7 +592,7 @@ define([ var range = module.cursor.makeRange(); module.cursor.fixSelection(sel, range); } - } + }*/ }, waitFor(function (fw) { window.APP.framework = framework = fw; })); nThen(function (waitFor) { @@ -624,6 +632,14 @@ define([ height: Messages.pad_mediatagHeight }; Links.addSupportForOpeningLinksInNewTab(Ckeditor)({editor: editor}); + }).nThen(function () { + // Move ckeditor parts to have a structure like the other apps + var $toolbarContainer = $('#cke_1_top'); + var $contentContainer = $('#cke_1_contents'); + var $mainContainer = $('#cke_editor1'); + $contentContainer.prepend($toolbarContainer.find('.cke_toolbox_main')); + $mainContainer.prepend($toolbarContainer); + $contentContainer.find('.cke_toolbox_main').addClass('cke_reset_all'); }).nThen(waitFor()); }).nThen(function (/*waitFor*/) { diff --git a/www/poll/inner.js b/www/poll/inner.js index 94d732a7f..2c7c4d7e0 100644 --- a/www/poll/inner.js +++ b/www/poll/inner.js @@ -14,6 +14,7 @@ define([ '/common/sframe-common-codemirror.js', '/common/common-thumbnail.js', '/common/common-interface.js', + '/common/hyperscript.js', '/customize/messages.js', 'cm/lib/codemirror', '/common/test.js', @@ -43,6 +44,7 @@ define([ SframeCM, Thumb, UI, + h, Messages, CMeditor, Test) @@ -61,8 +63,6 @@ define([ var debug = $.noop; //console.log; - var HIDE_INTRODUCTION_TEXT = "hide-text"; - var metadataMgr; var Title; var common; @@ -628,29 +628,6 @@ define([ APP.editor.refresh(); }; - var updateHelpButton = function () { - if (!APP.$helpButton) { return; } - var help = $('#cp-app-poll-help').is(':visible'); - var msg = (help ? Messages.poll_hide_help_button : Messages.poll_show_help_button); - APP.$helpButton.attr('title', msg); - if (help) { - APP.$helpButton.addClass('cp-toolbar-button-active'); - return; - } - APP.$helpButton.removeClass('cp-toolbar-button-active'); - }; - var showHelp = function(help) { - if (typeof help === 'undefined') { - help = !$('#cp-app-poll-help').is(':visible'); - } - - var msg = (help ? Messages.poll_hide_help_button : Messages.poll_show_help_button); - - $('#cp-app-poll-help').toggle(help); - $('#cp-app-poll-action-help').text(msg); - updateHelpButton(); - }; - var setEditable = function (editable) { APP.locked = APP.readOnly || !editable; @@ -1221,10 +1198,19 @@ define([ var $export = common.createButton('export', true, {}, exportFile); $drawer.append($export); - var $help = common.createButton('', true).click(function () { showHelp(); }) - .appendTo($rightside); - APP.$helpButton = $help; - updateHelpButton(); + var helpMenu = common.createHelpMenu(); + $('#cp-app-poll-form').prepend(helpMenu.menu); + $rightside.append(helpMenu.button); + var setHTML = function (e, html) { + e.innerHTML = html; + return e; + }; + var help = h('div', [ + setHTML(h('h1'), Messages.poll_subtitle), + h('p', Messages.poll_p_save), + h('p', Messages.poll_p_encryption) + ]); + $(helpMenu.text).html($(help).html()); if (APP.readOnly) { publish(true); return; } var $publish = common.createButton('', true) @@ -1344,18 +1330,6 @@ define([ }) .on('disconnect', onDisconnect) .on('reconnect', onReconnect); - - common.getAttribute(['poll', HIDE_INTRODUCTION_TEXT], function (e, value) { - if (e) { console.error(e); } - if (!value) { - common.setAttribute(['poll', HIDE_INTRODUCTION_TEXT], "1", function (e) { - if (e) { console.error(e); } - }); - showHelp(true); - } else { - showHelp(false); - } - }); }); }; main(); diff --git a/www/slide/app-slide.less b/www/slide/app-slide.less index 8926f52eb..14090e9bc 100644 --- a/www/slide/app-slide.less +++ b/www/slide/app-slide.less @@ -221,6 +221,16 @@ div#cp-app-slide-modal { background-color: black; color: white; + .cp-app-slide-isempty { + display: flex; + align-items: center; + justify-content: center; + img { + max-width: 100%; + max-height: 100%; + } + } + /* Navigation buttons */ .cp-app-slide-modal-button { position: absolute; diff --git a/www/slide/inner.js b/www/slide/inner.js index 173726d34..b41496024 100644 --- a/www/slide/inner.js +++ b/www/slide/inner.js @@ -9,6 +9,7 @@ define([ '/common/common-util.js', '/common/common-hash.js', '/common/common-interface.js', + '/common/diffMarked.js', '/customize/messages.js', 'cm/lib/codemirror', @@ -53,6 +54,7 @@ define([ Util, Hash, UI, + DiffMd, Messages, CMeditor) { @@ -426,6 +428,16 @@ define([ framework._.toolbar.$rightside.append(markdownTb.button); }; + var mkHelpMenu = function (framework) { + var $codeMirrorContainer = $('#cp-app-slide-editor-container'); + var helpMenu = framework._.sfCommon.createHelpMenu(); + $codeMirrorContainer.prepend(helpMenu.menu); + + $(helpMenu.text).html(DiffMd.render(Messages.slideInitialState)); + + framework._.toolbar.$rightside.append(helpMenu.button); + }; + var activateLinks = function ($content, framework) { $content.click(function (e) { if (!e.target) { return; } @@ -465,6 +477,7 @@ define([ mkFilePicker(framework, editor); mkSlidePreviewPane(framework, $contentContainer); mkMarkdownToolbar(framework, editor); + mkHelpMenu(framework); CodeMirror.configureTheme(common); @@ -519,7 +532,7 @@ define([ }); framework.onDefaultContentNeeded(function () { - CodeMirror.contentUpdate({ content: Messages.slideInitialState }); + CodeMirror.contentUpdate({ content: '' }); }); Slide.setTitle(framework._.title); diff --git a/www/slide/slide.js b/www/slide/slide.js index adc0a808b..ed63ac2e4 100644 --- a/www/slide/slide.js +++ b/www/slide/slide.js @@ -75,6 +75,20 @@ define([ if (typeof(Slide.content) !== 'string') { return; } var c = Slide.content; + + if (c === '') { + var $empty = $('', { + src: '/customize/main-favicon.png', + alt: '', + class: 'cp-app-code-preview-empty' + }); + $content.html('').append($empty); + $content.addClass('cp-app-slide-isempty'); + return; + //c = $('
').append($empty).html(); + } + $content.removeClass('cp-app-slide-isempty'); + var mediatagBg = ''; if (options.background && options.background.mt) { mediatagBg = options.background.mt; From d975bb9cc00543229515e58bfc87b9862775dc47 Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 28 Feb 2018 13:16:30 +0100 Subject: [PATCH 10/21] Fix focus after pad creation screen --- www/code/inner.js | 2 ++ www/pad/inner.js | 22 +++++++++++++++++----- www/slide/inner.js | 2 ++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/www/code/inner.js b/www/code/inner.js index 091baa0e8..d7a9b25e4 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -327,6 +327,8 @@ define([ framework.setTitleRecommender(CodeMirror.getHeadingText); framework.onReady(function (newPad) { + editor.focus(); + if (newPad && !CodeMirror.highlightMode) { CodeMirror.setMode('gfm', evModeChange.fire); //console.log("%s => %s", CodeMirror.highlightMode, CodeMirror.$language.val()); diff --git a/www/pad/inner.js b/www/pad/inner.js index c1a2adbf2..5ca7c24f6 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -437,6 +437,8 @@ define([ } framework.onReady(function (newPad) { + editor.focus(); + if (!module.isMaximized) { module.isMaximized = true; $('iframe.cke_wysiwyg_frame').css('width', ''); @@ -444,7 +446,6 @@ define([ } $('body').addClass('app-pad'); - editor.focus(); if (newPad) { cursor.setToEnd(); } else if (framework.isReadOnly()) { @@ -474,9 +475,18 @@ define([ $iframe.find('html').addClass('cke_body_width'); } }); + /*setTimeout(function () { + $('iframe.cke_wysiwyg_frame').focus(); + editor.focus(); + console.log(editor); + console.log(editor.focusManager); + $(window).trigger('resize'); + });*/ }); - framework.onDefaultContentNeeded(function () { }); + framework.onDefaultContentNeeded(function () { + inner.innerHTML = '

'; + }); var importMediaTags = function (dom, cb) { var $dom = $(dom); @@ -616,9 +626,11 @@ define([ var backColor = AppConfig.appBackgroundColor; var newCss = '.cke_body_width { background: '+ backColor +'; height: 100%; }' + '.cke_body_width body {' + - 'max-width: 50em; padding: 10px 30px; margin: 0 auto; min-height: 100%;'+ - 'box-sizing: border-box;'+ - '}'; + 'max-width: 50em; padding: 20px 30px; margin: 0 auto; min-height: 100%;'+ + 'box-sizing: border-box; overflow: auto;'+ + '}' + + 'html.cke_body_width { overflow: hidden; }' + + '.cke_body_width body > *:first-child { margin-top: 0; }'; Ckeditor.addCss(newCss); Ckeditor.plugins.addExternal('mediatag','/pad/', 'mediatag-plugin.js'); module.ckeditor = editor = Ckeditor.replace('editor1', { diff --git a/www/slide/inner.js b/www/slide/inner.js index b41496024..6ef545dff 100644 --- a/www/slide/inner.js +++ b/www/slide/inner.js @@ -502,6 +502,8 @@ define([ }); framework.onReady(function (/*newPad*/) { + editor.focus(); + CodeMirror.setMode('markdown', function () { }); Slide.onChange(function (o, n, l) { var slideNumber = ''; From dbe8ab014d7c7b6f9f48246f8fc2cde24cb0fe8e Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 28 Feb 2018 16:34:55 +0100 Subject: [PATCH 11/21] Select all in drive --- www/drive/inner.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/www/drive/inner.js b/www/drive/inner.js index cbeb0b08f..26f504797 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -548,6 +548,13 @@ define([ return; } + // Ctrl+A select all + if (e.which === 65 && e.ctrlKey) { + $content.find('.cp-app-drive-element:not(.cp-app-drive-element-selected)') + .addClass('cp-app-drive-element-selected'); + return; + } + // [Left, Up, Right, Down] if ([37, 38, 39, 40].indexOf(e.which) === -1) { return; } e.preventDefault(); @@ -2908,6 +2915,7 @@ define([ } // else move to trash moveElements(paths, [TRASH], false, refresh); + return; } }); var isCharacterKey = function (e) { From a4a6385e86e97ada55ffb7983c7eef419258ccbd Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 28 Feb 2018 16:38:28 +0100 Subject: [PATCH 12/21] Add keyboard shortcuts for the Ctrl+E or Cmd+E modal --- customize.dist/src/less2/include/icons.less | 4 ++ customize.dist/src/less2/include/toolbar.less | 1 + customize.dist/translations/messages.fr.js | 3 +- customize.dist/translations/messages.js | 3 +- www/common/common-ui-elements.js | 51 ++++++++++++++++--- www/common/toolbar3.js | 28 +++++----- 6 files changed, 66 insertions(+), 24 deletions(-) diff --git a/customize.dist/src/less2/include/icons.less b/customize.dist/src/less2/include/icons.less index a79bc25f5..03a6af5ab 100644 --- a/customize.dist/src/less2/include/icons.less +++ b/customize.dist/src/less2/include/icons.less @@ -25,6 +25,10 @@ text-overflow: ellipsis; word-wrap: break-word; } + &.cp-icons-element-selected { + background-color: white; + color: #666; + } .fa { display: block; font-size: 64px; diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less index a070c8af6..6f49250f4 100644 --- a/customize.dist/src/less2/include/toolbar.less +++ b/customize.dist/src/less2/include/toolbar.less @@ -208,6 +208,7 @@ width: auto; margin: 0; padding: 0; + outline: none; } label[for="cp-app-toolbar-creation-advanced"] { margin: 0; diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 08b974821..1a22c70ab 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -864,7 +864,8 @@ define(function () { out.creation_expiration = "Date d'expiration"; out.creation_propertiesTitle = "Disponibilité"; out.creation_appMenuName = "Mode avancé (Ctrl + E)"; - out.creation_newPadModalDescription = "Cliquez sur un type de pad pour le créer. Vous pouvez cocher la case pour afficher l'écran de création de pads"; + out.creation_newPadModalDescription = "Cliquez sur un type de pad pour le créer. Vous pouvez aussi appuyer sur Tab pour sélectionner un type et appuyer sur Entrée pour valider."; + out.creation_newPadModalDescriptionAdvanced = "Cochez la case si vous souhaitez voir l'écran de création de pads (pour les pads possédés ou à date d'expiration). Vous pouvez appuyer sur Espace pour changer sa valeur."; out.creation_newPadModalAdvanced = "Afficher l'écran de création de pads"; // New share modal diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 1e15eac1c..da9cad5e7 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -902,7 +902,8 @@ define(function () { out.creation_expiration = "Expiration time"; out.creation_propertiesTitle = "Availability"; out.creation_appMenuName = "Advanced mode (Ctrl + E)"; - out.creation_newPadModalDescription = "Click on a pad type to create it. You can check the box if you want to display the pad creation screen (for owned pads, expiring pads, etc.)."; + out.creation_newPadModalDescription = "Click on a pad type to create it. You can also press Tab to select the type and press Enter to confirm."; + out.creation_newPadModalDescriptionAdvanced = "You can check the box (or press Space to change its value) if you want to display the pad creation screen (for owned pads, expiring pads, etc.)."; out.creation_newPadModalAdvanced = "Display the pad creation screen"; // New share modal diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 502f18bea..5c0d3a2c0 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1528,6 +1528,7 @@ define([ if (!$blockContainer.length) { $blockContainer = $('
', { 'class': 'cp-modal-container', + tabindex: 1, 'id': cfg.id }); } @@ -1559,14 +1560,16 @@ define([ $body: $('body') }); var $title = $('

').text(Messages.fm_newFile); - var $description = $('

').text(Messages.creation_newPadModalDescription); + var $description = $('

').html(Messages.creation_newPadModalDescription); $modal.find('.cp-modal').append($title); $modal.find('.cp-modal').append($description); var $advanced; var $advancedContainer = $('

'); - if (common.isLoggedIn()) { + var priv = common.getMetadataMgr().getPrivateData(); + var c = (priv.settings.general && priv.settings.general.creation) || {}; + if (AppConfig.displayCreationScreen && common.isLoggedIn() && c.skip) { $advanced = $('', { type: 'checkbox', checked: 'checked', @@ -1575,9 +1578,12 @@ define([ $('