From 299a2f4c080810faf0f6101deca5543e6c8f20a0 Mon Sep 17 00:00:00 2001 From: yflory <yann.flory@xwiki.com> 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<br>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 <yann.flory@xwiki.com> 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 @@ +<!DOCTYPE html> +<html class="cp"> +<!-- If this file is not called customize.dist/src/template.html, it is generated --> +<head> + <title data-localization="main_title">CryptPad: Zero Knowledge, Collaborative Real Time Editing</title> + <meta content="text/html; charset=utf-8" http-equiv="content-type"/> + <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> + <link rel="icon" type="image/png" href="/customize/main-favicon.png" id="favicon"/> + <script async data-bootload="/customize/template.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script> +</head> +<body class="html"> + <noscript> + <p><strong>OOPS</strong> In order to do encryption in your browser, Javascript is really <strong>really</strong> required.</p> + <p><strong>OUPS</strong> Afin de pouvoir réaliser le chiffrement dans votre navigateur, Javascript est <strong>vraiment</strong> nécessaire.</p> + </noscript> +</html> + 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 <yann.flory@xwiki.com> 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 <yann.flory@xwiki.com> 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 <yann.flory@xwiki.com> 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 <yann.flory@xwiki.com> 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 <yann.flory@xwiki.com> 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, <a href="/" target="_blank">cliquez ici</a> pour vous authentifier<br>ou appuyez sur <em>Échap</em> 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 <em>Échap</em>.<br> 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, <a href="/" target="_blank">click here</a> to log in<br>or press <em>Escape</em> 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 <em>Esc</em>.<br>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 <ansuz@transitiontech.ca> 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 <yann.flory@xwiki.com> 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 () { '<p>', 'Αυτό είναι <strong>CryptPad</strong>, ο συνεργατικός επεξεργαστής πραγματικού χρόνου Zero Knowledge. Τα πάντα αποθηκεύονται καθώς πληκτρολογείτε.', '<br>', - 'Μοιραστείτε τον σύνδεσμο σε αυτό το pad για να το επεξεργαστείτε με φίλους ή χρησιμοποιήστε το κουμπί <span class="fa fa-share-alt" style="border: 1px solid black;color:#000;"> Share </span> για να μοιραστείτε ένα κείμενο με δικαιώματα <em>read-only link</em> το οποίο επιτρέπει να το αναγνώσει κάποιος αλλά όχι να το επεξεργαστεί.', + 'Μοιραστείτε τον σύνδεσμο σε αυτό το pad για να το επεξεργαστείτε με φίλους ή χρησιμοποιήστε το κουμπί <span class="fa fa-share-alt"></span> για να μοιραστείτε ένα κείμενο με δικαιώματα <em>read-only link</em> το οποίο επιτρέπει να το αναγνώσει κάποιος αλλά όχι να το επεξεργαστεί.', '</p>', - - '<p><em>', - 'Εμπρός, απλά ξεκινήστε να πληκτρολογείτε...', - '</em></p>', - '<p> <br></p>' ].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 () { '<p>', 'Esto es <strong>CryptPad</strong>, el editor colaborativo en tiempo real Zero Knowledge. Todo está guardado cuando escribes.', '<br>', - 'Comparte el enlace a este pad para editar con amigos o utiliza el botón <span class="fa fa-share-alt" style="border: 1px solid black;color:#000;"> Compartir </span> para obtener un <em>enlace sólo lectura</em> que permite leer pero no escribir.', + 'Comparte el enlace a este pad para editar con amigos o utiliza el botón <span class="fa fa-share-alt"></span> para obtener un <em>enlace sólo lectura</em> que permite leer pero no escribir.', '</p>', - - '<p><em>', - 'Vamos, empieza a escribir...', - '</em></p>', - '<p> <br></p>' ].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 () { '<p>', 'Voici <strong>CryptPad</strong>, l\'éditeur collaboratif en temps-réel Zero Knowledge. Tout est sauvegardé dés que vous le tapez.', '<br>', - 'Partagez le lien vers ce pad avec des amis ou utilisez le bouton <span class="fa fa-share-alt" style="border: 1px solid black;color:#000;"> Partager </span> pour obtenir le <em>lien de lecture-seule</em>, qui permet la lecture mais non la modification.', + 'Partagez le lien vers ce pad avec des amis ou utilisez le bouton <span class="fa fa-share-alt"></span> pour obtenir le <em>lien de lecture-seule</em>, qui permet la lecture mais non la modification.', '</p>', - '<p>', - '<em>', - 'Lancez-vous, commencez à taper...', - '</em></p>', - '<p> <br></p>' ].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 () { '<p>', 'This is <strong>CryptPad</strong>, the Zero Knowledge realtime collaborative editor. Everything is saved as you type.', '<br>', - 'Share the link to this pad to edit with friends or use the <span class="fa fa-share-alt" style="border: 1px solid black;color:#000;"> Share </span> button to share a <em>read-only link</em> which allows viewing but not editing.', + 'Share the link to this pad to edit with friends or use the <span class="fa fa-share-alt"></span> button to share a <em>read-only link</em> which allows viewing but not editing.', '</p>', - - '<p><em>', - 'Go ahead, just start typing...', - '</em></p>', - '<p> <br></p>' ].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 () { '<p>', 'This is <strong>CryptPad</strong>, the Zero Knowledge realtime collaborative editor. Everything is saved as you type.', '<br>', - 'Share the link to this pad to edit with friends or use the <span style="background-color:#5cb85c;color:#ffffff;"> Share </span> button to share a <em>read-only link</em> which allows viewing but not editing.', + 'Share the link to this pad to edit with friends or use the <span class="fa fa-share-alt"></span> button to share a <em>read-only link</em> which allows viewing but not editing.', '</p>', - - '<p><span style="color:#808080;"><em>', - 'Go ahead, just start typing...', - '</em></span></p>', - '<p> <br></p>' ].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 = "<a href=\"http://www.xwiki.com/\" target=\"_blank\" rel=\"noopener noreferrer\">With <img class=\"bottom-bar-heart\" src=\"/customize/heart.png\" alt=\"love\" /> from <img class=\"bottom-bar-fr\" src=\"/customize/fr.png\" title=\"Franța\" alt=\"Franța\"/> by <img src=\"/customize/logo-xwiki.png\" alt=\"XWiki SAS\" class=\"bottom-bar-xwiki\"/></a>"; out.header_support = "<a href=\"http://ng.open-paas.org/\" title=\"OpenPaaS::ng\" target=\"_blank\" rel=\"noopener noreferrer\"> <img src=\"/customize/openpaasng.png\" alt=\"OpenPaaS-ng\" class=\"bottom-bar-openpaas\" /></a>"; out.header_logoTitle = "Mergi la pagina principală"; - out.initialState = "<p>Acesta este <strong>CryptPad</strong>, editorul colaborativ bazat pe tehnologia Zero Knowledge în timp real. Totul este salvat pe măsură ce scrii.<br>Partajează link-ul către acest pad pentru a edita cu prieteni sau folosește <span class=\"fa fa-share-alt\" style=\"border:1px solid black;color:#000;\"> Share </span> butonul pentru a partaja <em>read-only link</em> permițând vizualizarea dar nu și editarea.</p><p><em>Îndrăznește, începe să scrii...</em></p><p> <br></p>"; + out.initialState = "<p>Acesta este <strong>CryptPad</strong>, editorul colaborativ bazat pe tehnologia Zero Knowledge în timp real. Totul este salvat pe măsură ce scrii.<br>Partajează link-ul către acest pad pentru a edita cu prieteni sau folosește <span class=\"fa fa-share-alt\"></span> butonul pentru a partaja <em>read-only link</em> permițând vizualizarea dar nu și editarea.</p>"; 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 () { '<p>', '這是 <strong>CryptPad</strong>, 零知識即時協作編輯平台,當你輸入時一切已即存好。', '<br>', - '分享這個工作檔案的網址連結給友人或是使用、 <span class="fa fa-share-alt" style="border: 1px solid black;color:#000;"> 分享 </span> 按鈕分享<em>唯讀的連結</em> 其只能看不能編寫。', - '</p>', - - '<p><em>', - '來吧, 開始打字輸入吧...', - '</em></p>', - '<p> <br></p>' + '分享這個工作檔案的網址連結給友人或是使用、 <span class="fa fa-share-alt"></span> 按鈕分享<em>唯讀的連結</em> 其只能看不能編寫。', + '</p>' ].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); + $('<img>', { + 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 = $('<img>', { + src: '/customize/main-favicon.png', + alt: '', + class: 'cp-app-code-preview-empty' + }); + $content.html('').append($empty); + $content.addClass('cp-app-slide-isempty'); + return; + //c = $('<div>').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 <yann.flory@xwiki.com> 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 = '<p></p>'; + }); 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 <yann.flory@xwiki.com> 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 <yann.flory@xwiki.com> 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 <b>Tab</b> pour sélectionner un type et appuyer sur <b>Entrée</b> 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 <b>Espace</b> 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 <b>Tab</b> to select the type and press <b>Enter</b> to confirm."; + out.creation_newPadModalDescriptionAdvanced = "You can check the box (or press <b>Space</b> 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 = $('<div>', { 'class': 'cp-modal-container', + tabindex: 1, 'id': cfg.id }); } @@ -1559,14 +1560,16 @@ define([ $body: $('body') }); var $title = $('<h3>').text(Messages.fm_newFile); - var $description = $('<p>').text(Messages.creation_newPadModalDescription); + var $description = $('<p>').html(Messages.creation_newPadModalDescription); $modal.find('.cp-modal').append($title); $modal.find('.cp-modal').append($description); var $advanced; var $advancedContainer = $('<div>'); - 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 = $('<input>', { type: 'checkbox', checked: 'checked', @@ -1575,9 +1578,12 @@ define([ $('<label>', { for: 'cp-app-toolbar-creation-advanced' }).text(Messages.creation_newPadModalAdvanced).appendTo($advancedContainer); + $description.append('<br>'); + $description.append(Messages.creation_newPadModalDescriptionAdvanced); } var $container = $('<div>'); + var i = 0; AppConfig.availablePadTypes.forEach(function (p) { if (p === 'drive') { return; } if (p === 'contacts') { return; } @@ -1586,7 +1592,8 @@ define([ if (!common.isLoggedIn() && AppConfig.registeredOnlyTypes && AppConfig.registeredOnlyTypes.indexOf(p) !== -1) { return; } var $element = $('<li>', { - 'class': 'cp-icons-element' + 'class': 'cp-icons-element', + 'id': 'cp-newpad-icons-'+ (i++) }).prepend(UI.getIcon(p)).appendTo($container); $element.append($('<span>', {'class': 'cp-icons-name'}) .text(Messages.type[p])); @@ -1594,7 +1601,7 @@ define([ $element.click(function () { $modal.hide(); if ($advanced && $advanced.is(':checked')) { - common.sessionStorage.put(Constants.displayPadCreationScreen, true, function () { + common.sessionStorage.put(Constants.displayPadCreationScreen, true, function (){ common.openURL('/' + p + '/'); }); return; @@ -1605,11 +1612,41 @@ define([ }); }); + var selected = -1; + var next = function () { + selected = ++selected % 5; + $container.find('.cp-icons-element-selected').removeClass('cp-icons-element-selected'); + $container.find('#cp-newpad-icons-'+selected).addClass('cp-icons-element-selected'); + }; + + $modal.off('keydown'); + $modal.keydown(function (e) { + if (e.which === 9) { + e.preventDefault(); + e.stopPropagation(); + next(); + return; + } + if (e.which === 13) { + if ($container.find('.cp-icons-element-selected').length === 1) { + $container.find('.cp-icons-element-selected').click(); + } + return; + } + if (e.which === 32 && $advanced) { + $advanced.prop('checked', !$advanced.prop('checked')); + $modal.focus(); + e.stopPropagation(); + e.preventDefault(); + } + }); + - /*var $content = createNewPadIcons($modal, isInRoot);*/ $modal.find('.cp-modal').append($container).append($advancedContainer); - window.setTimeout(function () { $modal.show(); }); - //addNewPadHandlers($modal, isInRoot); + window.setTimeout(function () { + $modal.show(); + $modal.focus(); + }); }; UIElements.initFilePicker = function (common, cfg) { diff --git a/www/common/toolbar3.js b/www/common/toolbar3.js index a09d13239..a9554f634 100644 --- a/www/common/toolbar3.js +++ b/www/common/toolbar3.js @@ -768,21 +768,19 @@ define([ content: $('<div>').append(UI.getIcon(p)).html() + Messages.type[p] }); }); - if (Config.displayCreationScreen) { - pads_options.push({ - tag: 'a', - attributes: { - id: 'cp-app-toolbar-creation-advanced', - href: origin - }, - content: '<span class="fa fa-plus-circle"></span> ' + Messages.creation_appMenuName - }); - $(window).keydown(function (e) { - if (e.which === 69 && e.ctrlKey) { - Common.createNewPadModal(); - } - }); - } + pads_options.push({ + tag: 'a', + attributes: { + id: 'cp-app-toolbar-creation-advanced', + href: origin + }, + content: '<span class="fa fa-plus-circle"></span> ' + Messages.creation_appMenuName + }); + $(window).keydown(function (e) { + if (e.which === 69 && (e.ctrlKey || e.metaKey)) { + Common.createNewPadModal(); + } + }); var dropdownConfig = { text: '', // Button initial text options: pads_options, // Entries displayed in the menu From 753b7550ca208261d7e489c9af98a0a235790c15 Mon Sep 17 00:00:00 2001 From: yflory <yann.flory@xwiki.com> Date: Wed, 28 Feb 2018 17:02:35 +0100 Subject: [PATCH 13/21] Save button in the pad creation screen --- .../src/less2/include/creation.less | 6 ++- customize.dist/translations/messages.fr.js | 1 + customize.dist/translations/messages.js | 1 + www/common/common-ui-elements.js | 49 ++++++++++++++++--- 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/customize.dist/src/less2/include/creation.less b/customize.dist/src/less2/include/creation.less index 58d5a53ba..2ca8cc402 100644 --- a/customize.dist/src/less2/include/creation.less +++ b/customize.dist/src/less2/include/creation.less @@ -75,7 +75,7 @@ } } - .cp-creation-create { + .cp-creation-create, .cp-creation-settings { button { .tools_unselectable(); padding: 15px; @@ -84,6 +84,7 @@ margin: 3px 10px; border: none; cursor: pointer; + outline: none; &:hover { background: darken(@colortheme_loading-bg, 5%); } @@ -159,6 +160,9 @@ color: lighten(#0275d8, 10%); } } + &> span.fa { + margin-left: 15px; + } } .cp-creation-deleted { background: #111; diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 1a22c70ab..edf3362d4 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -857,6 +857,7 @@ define(function () { out.creation_createFromTemplate = "Depuis un modèle"; out.creation_createFromScratch = "Nouveau pad vide"; out.creation_settings = "Préférences des nouveaux pads"; + out.creation_saveSettings = "Sauver les préférences"; // Properties about creation data out.creation_owners = "Propriétaires"; out.creation_ownedByOther = "Possédé par un autre utilisateur"; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index da9cad5e7..0dabbefe7 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -895,6 +895,7 @@ define(function () { out.creation_createFromTemplate = "From template"; out.creation_createFromScratch = "From scratch"; out.creation_settings = "New Pad settings"; + out.creation_saveSettings = "Save settings"; // Properties about creation data out.creation_owners = "Owners"; out.creation_ownedByOther = "Owned by another user"; diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 5c0d3a2c0..9a5a1bc42 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1839,8 +1839,7 @@ define([ UIElements.setExpirationValue(cfg.expire, $creation); // Create the pad - var create = function (template) { - $creationContainer.remove(); + var getFormValues = function (template) { // Type of pad var ownedVal = parseInt($('input[name="cp-creation-owned"]:checked').val()); // Life time @@ -1856,11 +1855,16 @@ define([ expireVal = ($('#cp-creation-expire-val').val() || 0) * unit; } - common.createPad({ + return { owned: ownedVal, expire: expireVal, template: template - }, function () { + }; + }; + var create = function (template) { + $creationContainer.remove(); + + common.createPad(getFormValues(template), function () { cb(); }); }; @@ -1905,10 +1909,39 @@ define([ // Settings button var origin = common.getMetadataMgr().getPrivateData().origin; - $(h('div.cp-creation-settings', h('a', { - href: origin + '/settings/#creation', - target: '_blank' - }, Messages.creation_settings))).appendTo($creation); + var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved}).hide(); + var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}).hide(); + var okTo; + var $saveButton = $('<button>').text(Messages.creation_saveSettings).click(function () { + if (okTo) { clearTimeout(okTo); } + $ok.hide(); + $spinner.show(); + var val = getFormValues(); + NThen(function (waitFor) { + common.setAttribute(['general', 'creation', 'owned'], val.owned, waitFor(function (e) { + if (e) { return void console.error(e); } + })); + common.setAttribute(['general', 'creation', 'expire'], val.expire, waitFor(function (e) { + if (e) { return void console.error(e); } + })); + }).nThen(function () { + $spinner.hide(); + $ok.show(); + okTo = setTimeout(function () { + $ok.hide(); + }, 5000); + }); + }); + $(h('div.cp-creation-settings', [ + $saveButton[0], + h('br'), + h('a', { + href: origin + '/settings/#creation', + target: '_blank' + }, Messages.creation_settings), + $ok[0], + $spinner[0] + ])).appendTo($creation); }; UIElements.onServerError = function (common, err, toolbar, cb) { From 2c90cb5907131336f2541ad89106541560260d68 Mon Sep 17 00:00:00 2001 From: yflory <yann.flory@xwiki.com> Date: Wed, 28 Feb 2018 17:59:27 +0100 Subject: [PATCH 14/21] Move help button in drawer and fix drawer style --- customize.dist/src/less2/include/toolbar.less | 24 ++++++++++++++++++- customize.dist/translations/messages.fr.js | 7 +++--- customize.dist/translations/messages.js | 7 +++--- www/code/inner.js | 2 +- www/common/common-ui-elements.js | 11 ++++++++- www/pad/inner.js | 2 +- www/poll/inner.js | 2 +- www/slide/inner.js | 2 +- 8 files changed, 45 insertions(+), 12 deletions(-) diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less index 6f49250f4..07e5eff61 100644 --- a/customize.dist/src/less2/include/toolbar.less +++ b/customize.dist/src/less2/include/toolbar.less @@ -855,6 +855,7 @@ font-size: 17px; } &> span { + order: 8; box-sizing: border-box; min-width: 150px; height: @toolbar_line-height; @@ -869,15 +870,36 @@ border: 0; width: 100%; line-height: 1em; + &.cp-toolbar-button-active { + background-color: inherit; + } .cp-toolbar-drawer-element { margin-left: 10px; display: inline; - vertical-align: top; + vertical-align: baseline; + } + &.fa-info-circle, &.fa-history, &.fa-cog { + .cp-toolbar-drawer-element { + margin-left: 11px; + } + } + &.fa-question { + .cp-toolbar-drawer-element { + margin-left: 16px; + } } &:hover { background-color: @colortheme_dropdown-bg-hover !important; color: @colortheme_dropdown-color; } + order: 8; + &.fa-history { order: 1; } + &.fa-download { order: 2; } + &.fa-upload { order: 3; } + &.fa-print { order: 4; } + &.fa-cog { order: 5; } + &.fa-info-circle { order: 6; } + &.fa-help { order: 7; } } } } diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index edf3362d4..145d50720 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -218,6 +218,10 @@ define(function () { out.cancelButton = 'Annuler (Échap)'; out.doNotAskAgain = "Ne plus demander (Échap)"; + out.show_help_button = "Afficher l'aide"; + out.hide_help_button = "Cacher l'aide"; + out.help_button = "Aide"; + out.historyText = "Historique"; out.historyButton = "Afficher l'historique du document"; out.history_next = "Voir la version suivante"; @@ -278,9 +282,6 @@ define(function () { out.poll_locked = "Verrouillé"; out.poll_unlocked = "Déverrouillé"; - out.poll_show_help_button = "Afficher l'aide"; - out.poll_hide_help_button = "Cacher l'aide"; - out.poll_bookmark_col = "Marquer cette colonne comme favorite pour qu'elle soit toujours déverouillée et affichée en première position."; out.poll_bookmarked_col = "Voici votre colonne favorite; elle sera toujours dévérouillée et affichée en première position."; out.poll_total = 'TOTAL'; diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 0dabbefe7..92702a339 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -220,6 +220,10 @@ define(function () { out.cancelButton = 'Cancel (esc)'; out.doNotAskAgain = "Don't ask me again (Esc)"; + out.show_help_button = "Show help"; + out.hide_help_button = "Hide help"; + out.help_button = "Help"; + out.historyText = "History"; out.historyButton = "Display the document history"; out.history_next = "Go to the next version"; @@ -280,9 +284,6 @@ define(function () { out.poll_locked = "Locked"; out.poll_unlocked = "Unlocked"; - out.poll_show_help_button = "Show help"; - out.poll_hide_help_button = "Hide help"; - out.poll_bookmark_col = 'Bookmark this column so that it is always unlocked and displayed at the beginning for you'; out.poll_bookmarked_col = 'This is your bookmarked column. It will always be unlocked and displayed at the beginning for you.'; out.poll_total = 'TOTAL'; diff --git a/www/code/inner.js b/www/code/inner.js index d7a9b25e4..c782c3f08 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -86,7 +86,7 @@ define([ $(helpMenu.text).html(DiffMd.render(Messages.codeInitialState)); - framework._.toolbar.$rightside.append(helpMenu.button); + framework._.toolbar.$drawer.append(helpMenu.button); }; var mkPreviewPane = function (editor, CodeMirror, framework, isPresentMode) { var $previewContainer = $('#cp-app-code-preview'); diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 9a5a1bc42..c72ea7b07 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -657,6 +657,11 @@ define([ data.element.toggle(); var isVisible = data.element.is(':visible'); if (callback) { callback(isVisible); } + if (isVisible) { + button.addClass('cp-toolbar-button-active'); + } else { + button.removeClass('cp-toolbar-button-active'); + } updateIcon(isVisible); }); updateIcon(data.element.is(':visible')); @@ -681,7 +686,6 @@ define([ default: button = $('<button>', { 'class': "fa fa-question", - style: 'font:'+size+' FontAwesome' }) .click(common.prepareFeedback(type)); } @@ -861,6 +865,9 @@ define([ 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'); + $toolbarButton.attr('title', Messages.hide_help_button); + $toolbarButton + .append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.help_button)); var help = h('div.cp-help-container', [ closeButton, text @@ -871,9 +878,11 @@ define([ if (forceClose) { return; } common.setAttribute(['hideHelp', type], false); $toolbarButton.addClass('cp-toolbar-button-active'); + $toolbarButton.attr('title', Messages.hide_help_button); return void $(help).removeClass('cp-help-hidden'); } $toolbarButton.removeClass('cp-toolbar-button-active'); + $toolbarButton.attr('title', Messages.show_help_button); $(help).addClass('cp-help-hidden'); common.setAttribute(['hideHelp', type], true); }; diff --git a/www/pad/inner.js b/www/pad/inner.js index 5ca7c24f6..8e11b2285 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -143,7 +143,7 @@ define([ $(helpMenu.text).html(Messages.initialState); - framework._.toolbar.$rightside.append(helpMenu.button); + framework._.toolbar.$drawer.append(helpMenu.button); }; var mkDiffOptions = function (cursor, readOnly) { diff --git a/www/poll/inner.js b/www/poll/inner.js index 2c7c4d7e0..c88cf7cbe 100644 --- a/www/poll/inner.js +++ b/www/poll/inner.js @@ -1200,7 +1200,7 @@ define([ var helpMenu = common.createHelpMenu(); $('#cp-app-poll-form').prepend(helpMenu.menu); - $rightside.append(helpMenu.button); + $drawer.append(helpMenu.button); var setHTML = function (e, html) { e.innerHTML = html; return e; diff --git a/www/slide/inner.js b/www/slide/inner.js index 6ef545dff..663814af2 100644 --- a/www/slide/inner.js +++ b/www/slide/inner.js @@ -435,7 +435,7 @@ define([ $(helpMenu.text).html(DiffMd.render(Messages.slideInitialState)); - framework._.toolbar.$rightside.append(helpMenu.button); + framework._.toolbar.$drawer.append(helpMenu.button); }; var activateLinks = function ($content, framework) { From ee3b926e848bc5d172250948d3a8982fda7c52c8 Mon Sep 17 00:00:00 2001 From: yflory <yann.flory@xwiki.com> Date: Thu, 1 Mar 2018 10:33:28 +0100 Subject: [PATCH 15/21] Get rid of ckeditor's reset_all class... --- www/pad/inner.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/pad/inner.js b/www/pad/inner.js index 8e11b2285..4aff47102 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -652,6 +652,7 @@ define([ $contentContainer.prepend($toolbarContainer.find('.cke_toolbox_main')); $mainContainer.prepend($toolbarContainer); $contentContainer.find('.cke_toolbox_main').addClass('cke_reset_all'); + $toolbarContainer.removeClass('cke_reset_all'); }).nThen(waitFor()); }).nThen(function (/*waitFor*/) { From 95bbc3d130b05aebf5f86797cf14c1a478f982a1 Mon Sep 17 00:00:00 2001 From: yflory <yann.flory@xwiki.com> Date: Thu, 1 Mar 2018 11:23:16 +0100 Subject: [PATCH 16/21] Add the mediatag button back in the code app --- www/code/inner.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/code/inner.js b/www/code/inner.js index c782c3f08..d10496993 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -54,6 +54,7 @@ define([ var MEDIA_TAG_MODES = Object.freeze([ 'markdown', + 'gfm', 'html', 'htmlembedded', 'htmlmixed', From 12bfcbe70124ed3b5a8067f2b641898dde676ce7 Mon Sep 17 00:00:00 2001 From: yflory <yann.flory@xwiki.com> Date: Thu, 1 Mar 2018 14:32:14 +0100 Subject: [PATCH 17/21] Add fixed order for rightside icons in the toolbar --- customize.dist/src/less2/include/toolbar.less | 38 ++++--- www/code/inner.js | 11 +- www/common/common-thumbnail.js | 3 +- www/common/common-ui-elements.js | 100 ++++++++++++------ www/common/sframe-app-framework.js | 6 +- www/drive/app-drive.less | 2 +- www/file/app-file.less | 24 +++++ www/file/inner.js | 12 +-- www/poll/inner.js | 16 ++- www/slide/inner.js | 63 ++++++----- www/slide/slide.js | 3 - www/whiteboard/app-whiteboard.less | 7 ++ www/whiteboard/inner.js | 30 +++--- 13 files changed, 183 insertions(+), 132 deletions(-) diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less index 07e5eff61..b6258c4fe 100644 --- a/customize.dist/src/less2/include/toolbar.less +++ b/customize.dist/src/less2/include/toolbar.less @@ -389,11 +389,6 @@ margin: 0; }*/ - .cp-toolbar-rightside-button { - float: right; - cursor: pointer; - } - select { margin-left: 5px; margin-right: 5px; @@ -475,13 +470,6 @@ background-color: @bg-color; } } - .cp-toolbar-rightside { - @media screen and (max-width: @barWidth) { // 450px - flex-wrap: wrap; - height: auto; - width: 100%; - } - } .cp-toolbar-title-hoverable:hover { .cp-toolbar-title-editable, .cp-toolbar-title-edit { cursor: text; @@ -830,13 +818,37 @@ } } .cp-toolbar-rightside { + display: flex; min-height: @toolbar_line-height; overflow: hidden; + @media screen and (max-width: @barWidth) { // 450px + flex-wrap: wrap; + height: auto; + width: 100%; + } &:empty { min-height: 0; height: 0; } - text-align: right; + + .cp-toolbar-rightside-button { + cursor: pointer; + // UI actions + &.cp-toolbar-icon-toggle { order: 1; } + &.cp-toolbar-icon-preview { order: 2; } + &.cp-toolbar-icon-present { order: 3; } + // Content actions + &.cp-toolbar-icon-mediatag { order: 10; } + order: 11; + // Storage actions + &.cp-toolbar-icon-hashtag { order: 20; } + &.cp-toolbar-icon-template { order: 21; } + &.cp-toolbar-icon-forget { order: 22; } + // Drawer + &.cp-toolbar-drawer-button { order: 30; } + + } + .cp-toolbar-drawer-content:empty ~ .cp-toolbar-drawer-button { display: none; } diff --git a/www/code/inner.js b/www/code/inner.js index d10496993..1799819dd 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -102,7 +102,7 @@ define([ class: 'cp-app-code-preview-empty' }).appendTo($previewContainer); - var $previewButton = framework._.sfCommon.createButton(null, true); + var $previewButton = framework._.sfCommon.createButton('preview', true); var forceDrawPreview = function () { try { if (editor.getValue() === '') { @@ -119,12 +119,6 @@ define([ forceDrawPreview(); }, 150); - $previewButton.removeClass('fa-question').addClass('fa-eye'); - window.setTimeout(function () { - // setTimeout needed for tippy (tooltip), otherwise we have the browser's default - // tooltips - $previewButton.attr('title', Messages.previewButtonTitle); - }); var previewTo; $previewButton.click(function () { clearTimeout(previewTo); @@ -377,9 +371,6 @@ define([ if ($preview.length && $preview.is(':visible')) { return $preview[0]; } - if ($codeMirror.length) { - return $codeMirror[0]; - } }; var main = function () { diff --git a/www/common/common-thumbnail.js b/www/common/common-thumbnail.js index f0ba27194..f3864e6a3 100644 --- a/www/common/common-thumbnail.js +++ b/www/common/common-thumbnail.js @@ -177,6 +177,7 @@ define([ window.html2canvas = undefined; Thumb.fromDOM = function (opts, cb) { var element = opts.getContainer(); + if (!element) { return; } var todo = function () { if (opts.filter) { opts.filter(element, true); } window.html2canvas(element, { @@ -202,8 +203,8 @@ define([ var mkThumbnail = function () { var content = opts.getContent(); if (content === oldThumbnailState) { return; } + oldThumbnailState = content; Thumb.fromDOM(opts, function (err, b64) { - oldThumbnailState = content; Thumb.setPadThumbnail(common, opts.href, b64); }); }; diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index c72ea7b07..8bf3474c1 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -468,7 +468,7 @@ define([ switch (type) { case 'export': button = $('<button>', { - 'class': 'fa fa-download', + 'class': 'fa fa-download cp-toolbar-icon-export', title: Messages.exportButtonTitle, }).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.exportButton)); @@ -479,7 +479,7 @@ define([ break; case 'import': button = $('<button>', { - 'class': 'fa fa-upload', + 'class': 'fa fa-upload cp-toolbar-icon-import', title: Messages.importButtonTitle, }).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.importButton)); if (callback) { @@ -525,7 +525,8 @@ define([ if (!common.isLoggedIn()) { return; } button = $('<button>', { title: Messages.saveTemplateButton, - }).append($('<span>', {'class':'fa fa-bookmark', style: 'font:'+size+' FontAwesome'})); + class: 'fa fa-bookmark cp-toolbar-icon-template' + }); if (data.rt) { button .click(function () { @@ -570,37 +571,45 @@ define([ break; case 'forget': button = $('<button>', { - id: 'cryptpad-forget', title: Messages.forgetButtonTitle, - 'class': "fa fa-trash cryptpad-forget", - style: 'font:'+size+' FontAwesome' + 'class': "fa fa-trash cp-toolbar-icon-forget" }); - if (callback) { - button - .click(common.prepareFeedback(type)) - .click(function() { - var msg = common.isLoggedIn() ? Messages.forgetPrompt : Messages.fm_removePermanentlyDialog; - UI.confirm(msg, function (yes) { - if (!yes) { return; } - sframeChan.query('Q_MOVE_TO_TRASH', null, function (err) { - if (err) { return void callback(err); } - var cMsg = common.isLoggedIn() ? Messages.movedToTrash : Messages.deleted; - UI.alert(cMsg, undefined, true); - callback(); - return; - }); + callback = typeof callback === "function" ? callback : function () {}; + button + .click(common.prepareFeedback(type)) + .click(function() { + var msg = common.isLoggedIn() ? Messages.forgetPrompt : Messages.fm_removePermanentlyDialog; + UI.confirm(msg, function (yes) { + if (!yes) { return; } + sframeChan.query('Q_MOVE_TO_TRASH', null, function (err) { + if (err) { return void callback(err); } + var cMsg = common.isLoggedIn() ? Messages.movedToTrash : Messages.deleted; + UI.alert(cMsg, undefined, true); + callback(); + return; }); - }); - } + + }); break; case 'present': button = $('<button>', { title: Messages.presentButtonTitle, - 'class': "fa fa-play-circle cp-app-slide-present-button", // used in slide.js - style: 'font:'+size+' FontAwesome' + 'class': "fa fa-play-circle cp-toolbar-icon-present", // used in slide.js }); break; + case 'preview': + button = $('<button>', { + title: Messages.previewButtonTitle, + 'class': "fa fa-eye cp-toolbar-icon-preview", + }); + break; + case 'print': + button = $('<button>', { + title: Messages.printButtonTitle, + 'class': "fa fa-print cp-toolbar-icon-print", + }).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.printText)); + break; case 'history': if (!AppConfig.enableHistory) { button = $('<span>'); @@ -608,7 +617,7 @@ define([ } button = $('<button>', { title: Messages.historyButton, - 'class': "fa fa-history history", + 'class': "fa fa-history cp-toolbar-icon-history", }).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.historyText)); if (data.histConfig) { button @@ -622,19 +631,25 @@ define([ button = $('<button>', { title: Messages.moreActions, 'class': "cp-toolbar-drawer-button fa fa-ellipsis-h", - style: 'font:'+size+' FontAwesome' }); break; + case 'mediatag': + button = $('<button>', { + 'class': 'fa fa-picture-o cp-toolbar-icon-mediatag', + title: Messages.filePickerButton, + }) + .click(common.prepareFeedback(type)); + break; case 'savetodrive': button = $('<button>', { - 'class': 'fa fa-cloud-upload', + 'class': 'fa fa-cloud-upload cp-toolbar-icon-savetodrive', title: Messages.canvas_saveToDrive, }) .click(common.prepareFeedback(type)); break; case 'hashtag': button = $('<button>', { - 'class': 'fa fa-hashtag', + 'class': 'fa fa-hashtag cp-toolbar-icon-hashtag', title: Messages.tags_title, }) .click(common.prepareFeedback(type)) @@ -642,7 +657,7 @@ define([ break; case 'toggle': button = $('<button>', { - 'class': 'fa fa-caret-down', + 'class': 'fa fa-caret-down cp-toolbar-icon-toggle', }) .click(common.prepareFeedback(type)); window.setTimeout(function () { @@ -668,7 +683,7 @@ define([ break; case 'properties': button = $('<button>', { - 'class': 'fa fa-info-circle', + 'class': 'fa fa-info-circle cp-toolbar-icon-properties', title: Messages.propertiesButtonTitle, }).append($('<span>', {'class': 'cp-toolbar-drawer-element'}) .text(Messages.propertiesButton)) @@ -684,10 +699,24 @@ define([ }); break; default: + data = data || {}; + var icon = data.icon || "fa-question"; button = $('<button>', { - 'class': "fa fa-question", + 'class': "fa " + icon, }) .click(common.prepareFeedback(type)); + if (data.title) { button.attr('title', data.title); } + if (data.style) { button.attr('style', data.style); } + if (data.id) { button.attr('id', data.id); } + if (data.hiddenReadOnly) { button.addClass('cp-hidden-if-readonly'); } + if (data.name) { + button.addClass('cp-toolbar-icon-'+data.name); + button.click(common.prepareFeedback(data.name)); + } + if (data.text) { + $('<span>', {'class': 'cp-toolbar-drawer-element'}).text(data.text) + .appendTo(button); + } } if (rightside) { button.addClass('cp-toolbar-rightside-button'); @@ -864,10 +893,11 @@ define([ 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'); - $toolbarButton.attr('title', Messages.hide_help_button); - $toolbarButton - .append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.help_button)); + var $toolbarButton = common.createButton('', true, { + title: Messages.hide_help_button, + text: Messages.help_button, + name: 'help' + }).addClass('cp-toolbar-button-active'); var help = h('div.cp-help-container', [ closeButton, text diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index d612387fa..d5a4e7896 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -398,11 +398,7 @@ define([ '" data-crypto-key="cryptpad:' + data.key + '"></media-tag>'), data); } }); - $embedButton = $('<button>', { - title: Messages.filePickerButton, - 'class': 'cp-toolbar-rightside-button fa fa-picture-o', - style: 'font-size: 17px' - }).click(function () { + $embedButton = common.createButton('mediatag', true).click(function () { common.openFilePicker({ types: ['file'], where: ['root'] diff --git a/www/drive/app-drive.less b/www/drive/app-drive.less index 083eeebe4..188fcf0bf 100644 --- a/www/drive/app-drive.less +++ b/www/drive/app-drive.less @@ -724,7 +724,7 @@ span { } } - .history { + .cp-toolbar-icon-history { float: right; .cp-toolbar-drawer-element { display: none; diff --git a/www/file/app-file.less b/www/file/app-file.less index a777b6014..ec22a2e0c 100644 --- a/www/file/app-file.less +++ b/www/file/app-file.less @@ -30,6 +30,8 @@ flex-flow: column; display: flex; justify-content: center; align-items: center; + flex-flow: column; + min-height: 0; } #cp-app-file-content.ready { @@ -134,3 +136,25 @@ media-tag { z-index: 10000; display: block; } + +#cp-app-file-download-view { + flex: 1; + display: flex; + min-height: 0; + align-items: center; + justify-content: center; + flex-flow: column; + media-tag { + flex: 1; + min-height: 0; + max-width: 100vw; + display: flex; + align-items: center; + justify-content: center; + &> * { + max-height: 100%; + max-width: 100%; + } + } + +} diff --git a/www/file/inner.js b/www/file/inner.js index b4b327998..b90f392a1 100644 --- a/www/file/inner.js +++ b/www/file/inner.js @@ -100,6 +100,11 @@ define([ var title = document.title = metadata.name; Title.updateTitle(title || Title.defaultTitle); toolbar.addElement(['pageTitle'], {pageTitle: title}); + toolbar.$rightside.append(common.createButton('forget', true)); + if (common.isLoggedIn()) { + toolbar.$rightside.append(common.createButton('hashtag', true)); + } + common.setPadAttribute('fileType', metadata.type); @@ -118,7 +123,6 @@ define([ $mt.attr('data-crypto-key', 'cryptpad:'+cryptKey); var rightsideDisplayed = false; - $(window.document).on('decryption', function (e) { var decrypted = e.originalEvent; if (decrypted.callback) { @@ -142,13 +146,7 @@ define([ toolbar.$rightside .append(common.createButton('export', true, {}, function () { saveAs(decrypted.blob, decrypted.metadata.name); - })) - .append(common.createButton('forget', true, {}, function () { - // not sure what to do here })); - if (common.isLoggedIn()) { - toolbar.$rightside.append(common.createButton('hashtag', true)); - } rightsideDisplayed = true; } diff --git a/www/poll/inner.js b/www/poll/inner.js index c88cf7cbe..6a77db8a9 100644 --- a/www/poll/inner.js +++ b/www/poll/inner.js @@ -1064,7 +1064,7 @@ define([ setTimeout(waitFor()); }).nThen(function (waitFor) { // Switch to non-admin mode - $('.cp-toolbar-rightside-button.fa-check').click(); + $('.cp-toolbar-icon-publish').click(); setTimeout(waitFor()); }).nThen(function (waitFor) { $('.cp-app-poll-comments-add-name').val("Mr.Me").keyup(); @@ -1213,9 +1213,11 @@ define([ $(helpMenu.text).html($(help).html()); if (APP.readOnly) { publish(true); return; } - var $publish = common.createButton('', true) - .removeClass('fa-question').addClass('fa-check') - .click(function () { publish(!APP.proxy.published); }).appendTo($rightside); + var $publish = common.createButton('', true, { + name: 'publish', + icon: 'fa-check', + hiddenReadOnly: true + }).click(function () { publish(!APP.proxy.published); }).appendTo($rightside); APP.$publishButton = $publish; updatePublishButton(); @@ -1230,11 +1232,7 @@ define([ } }; common.initFilePicker(fileDialogCfg); - APP.$mediaTagButton = $('<button>', { - title: Messages.filePickerButton, - 'class': 'cp-toolbar-rightside-button fa fa-picture-o', - style: 'font-size: 17px' - }).click(function () { + APP.$mediaTagButton = common.createButton('mediatag', true).click(function () { var pickerCfg = { types: ['file'], where: ['root'] diff --git a/www/slide/inner.js b/www/slide/inner.js index 663814af2..abbf3828f 100644 --- a/www/slide/inner.js +++ b/www/slide/inner.js @@ -73,9 +73,7 @@ define([ }; var mkSlidePreviewPane = function (framework, $contentContainer) { - var $previewButton = framework._.sfCommon.createButton(null, true); - $previewButton.removeClass('fa-question').addClass('fa-eye'); - $previewButton.attr('title', Messages.previewButtonTitle); + var $previewButton = framework._.sfCommon.createButton('preview', true); $previewButton.click(function () { var $c = $contentContainer; if ($c.hasClass('cp-app-slide-preview')) { @@ -102,19 +100,16 @@ define([ }); }; - var mkPrintButton = function (framework, editor, $content, $print, $toolbarDrawer) { - var $printButton = $('<button>', { - title: Messages.printButtonTitle, - 'class': 'cp-toolbar-rightside-button fa fa-print', - style: 'font-size: 17px' - }).click(function () { + var mkPrintButton = function (framework, editor, $content, $print) { + var $printButton = framework._.sfCommon.createButton('print', true); + $printButton.click(function () { Slide.update(editor.getValue(), true); $print.html($content.html()); window.focus(); window.print(); framework.feedback('PRINT_SLIDES'); - }).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.printText)); - $toolbarDrawer.append($printButton); + }); + framework._.toolbar.$drawer.append($printButton); }; // Flag to check if a file from the filepicker is a mediatag for the slides or a background image @@ -122,7 +117,7 @@ define([ isBackground: false }; - var mkSlideOptionsButton = function (framework, slideOptions, $toolbarDrawer) { + var mkSlideOptionsButton = function (framework, slideOptions) { var metadataMgr = framework._.cpNfInner.metadataMgr; var updateSlideOptions = function (newOpt) { if (JSONSortify(newOpt) !== JSONSortify(slideOptions)) { @@ -319,14 +314,17 @@ define([ return $container; }; - var $slideOptions = $('<button>', { + var $optionsButton = framework._.sfCommon.createButton(null, true, { + icon: 'fa-cog', title: Messages.slideOptionsTitle, - 'class': 'cp-toolbar-rightside-button fa fa-cog cp-hidden-if-readonly', - style: 'font-size: 17px' - }).click(function () { + hiddenReadOnly: true, + text: Messages.slideOptionsText, + name: 'options' + }); + $optionsButton.click(function () { $('body').append(createPrintDialog()); - }).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.slideOptionsText)); - $toolbarDrawer.append($slideOptions); + }); + framework._.toolbar.$drawer.append($optionsButton); metadataMgr.onChange(function () { var md = metadataMgr.getMetadata(); @@ -363,17 +361,21 @@ define([ framework.localChange(); }; - var $back = $('<button>', { - id: SLIDE_BACKCOLOR_ID, - 'class': 'fa fa-square cp-toolbar-rightside-button cp-hidden-if-readonly', - 'style': 'font-family: FontAwesome; color: #000;', - title: Messages.backgroundButtonTitle + var $back = framework._.sfCommon.createButton(null, true, { + icon: 'fa-square', + title: Messages.backgroundButtonTitle, + hiddenReadOnly: true, + name: 'background', + style: 'color: #000;', + id: SLIDE_BACKCOLOR_ID }); - var $text = $('<button>', { - id: SLIDE_COLOR_ID, - 'class': 'fa fa-i-cursor cp-toolbar-rightside-button cp-hidden-if-readonly', - 'style': 'font-family: FontAwesome; font-weight: bold; color: #fff;', - title: Messages.colorButtonTitle + var $text = framework._.sfCommon.createButton(null, true, { + icon: 'fa-i-cursor', + title: Messages.colorButtonTitle, + hiddenReadOnly: true, + name: 'color', + style: 'font-weight: bold; color: #FFF;', + id: SLIDE_COLOR_ID }); var $testColor = $('<input>', { type: 'color', value: '!' }); var $check = $("#cp-app-slide-colorpicker"); @@ -471,7 +473,7 @@ define([ activateLinks($content, framework); Slide.setModal(framework._.sfCommon, $modal, $content, slideOptions, Messages.slideInitialState); - mkPrintButton(framework, editor, $content, $print, $toolbarDrawer); + mkPrintButton(framework, editor, $content, $print); mkSlideOptionsButton(framework, slideOptions, $toolbarDrawer); mkColorConfiguration(framework, $modal); mkFilePicker(framework, editor); @@ -559,9 +561,6 @@ define([ if ($c.hasClass('cp-app-slide-preview')) { return $('.cp-app-slide-frame').first()[0]; } - if ($codeMirror.length) { - return $codeMirror[0]; - } }; var main = function () { diff --git a/www/slide/slide.js b/www/slide/slide.js index ed63ac2e4..17ad19c0c 100644 --- a/www/slide/slide.js +++ b/www/slide/slide.js @@ -139,7 +139,6 @@ define([ change(null, Slide.index); Common.setPresentUrl(true); - $('.cp-app-slide-present-button').hide(); updateFontSize(); return; } @@ -147,8 +146,6 @@ define([ Common.setTabTitle(); // Remove the slide number from the title Common.setPresentUrl(false); change(Slide.index, null); - $('.cp-app-slide-present-button').show(); - $('.cp-app-slide-source-button').hide(); $modal.removeClass('cp-app-slide-shown'); updateFontSize(); }; diff --git a/www/whiteboard/app-whiteboard.less b/www/whiteboard/app-whiteboard.less index 29c739b6e..7bbb7fbaf 100644 --- a/www/whiteboard/app-whiteboard.less +++ b/www/whiteboard/app-whiteboard.less @@ -31,6 +31,13 @@ display: none; } + .cp-toolbar-rightside { + .cp-toolbar-icon-savetodrive { order: 13; } + .cp-toolbar-icon-embedImage { order: 12; } + .cp-toolbar-icon-mediatag { order: 11; } + .cp-toolbar-icon-color { order: 10; } + } + #cp-app-whiteboard-media-hidden { display: none; } diff --git a/www/whiteboard/inner.js b/www/whiteboard/inner.js index 3c540fe98..7228f50c4 100644 --- a/www/whiteboard/inner.js +++ b/www/whiteboard/inner.js @@ -312,12 +312,13 @@ define([ return; } - var $color = APP.$color = $('<button>', { - id: "cp-app-whiteboard-color-picker", + var $color = APP.$color = common.createButton(null, true, { + icon: 'fa-square', title: Messages.canvas_chooseColor, - 'class': "fa fa-square cp-toolbar-rightside-button", - }) - .on('click', function () { + name: 'color', + id: 'cp-app-whiteboard-color-picker' + }); + $color.on('click', function () { pickColor($color.css('background-color'), function (color) { setColor(color); }); @@ -469,12 +470,13 @@ define([ }; reader.readAsDataURL(file); }; - common.createButton('', true) - .attr('title', Messages.canvas_imageEmbed) - .removeClass('fa-question').addClass('fa-file-image-o') - .click(function () { - $('<input>', {type:'file'}).on('change', onUpload).click(); - }).appendTo($rightside); + common.createButton('', true, { + title: Messages.canvas_imageEmbed, + icon: 'fa-file-image-o', + name: 'embedImage' + }).click(function () { + $('<input>', {type:'file'}).on('change', onUpload).click(); + }).appendTo($rightside); if (common.isLoggedIn()) { var fileDialogCfg = { @@ -493,11 +495,7 @@ define([ } }; common.initFilePicker(fileDialogCfg); - APP.$mediaTagButton = $('<button>', { - title: Messages.filePickerButton, - 'class': 'cp-toolbar-rightside-button fa fa-picture-o', - style: 'font-size: 17px' - }).click(function () { + APP.$mediaTagButton = common.createButton('mediatag', true).click(function () { var pickerCfg = { types: ['file'], where: ['root'], From b7b560fcb8152aa27b81e4994b8b4b756333ec02 Mon Sep 17 00:00:00 2001 From: yflory <yann.flory@xwiki.com> Date: Thu, 1 Mar 2018 14:48:36 +0100 Subject: [PATCH 18/21] Enable Cmd key support in shortcuts --- www/code/inner.js | 1 - www/common/common-ui-elements.js | 1 - www/common/toolbar3.js | 2 +- www/drive/inner.js | 5 +++-- www/slide/inner.js | 1 - 5 files changed, 4 insertions(+), 6 deletions(-) diff --git a/www/code/inner.js b/www/code/inner.js index 1799819dd..66010a485 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -367,7 +367,6 @@ define([ var getThumbnailContainer = function () { var $preview = $('#cp-app-code-preview-content'); - var $codeMirror = $('.CodeMirror'); if ($preview.length && $preview.is(':visible')) { return $preview[0]; } diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 8bf3474c1..35a5d38ec 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -463,7 +463,6 @@ define([ UIElements.createButton = function (common, type, rightside, data, callback) { var AppConfig = common.getAppConfig(); var button; - var size = "17px"; var sframeChan = common.getSframeChannel(); switch (type) { case 'export': diff --git a/www/common/toolbar3.js b/www/common/toolbar3.js index a9554f634..a000025d1 100644 --- a/www/common/toolbar3.js +++ b/www/common/toolbar3.js @@ -777,7 +777,7 @@ define([ content: '<span class="fa fa-plus-circle"></span> ' + Messages.creation_appMenuName }); $(window).keydown(function (e) { - if (e.which === 69 && (e.ctrlKey || e.metaKey)) { + if (e.which === 69 && (e.ctrlKey || (navigator.platform === "MacIntel" && e.metaKey))) { Common.createNewPadModal(); } }); diff --git a/www/drive/inner.js b/www/drive/inner.js index 26f504797..58d547b0e 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -41,7 +41,8 @@ define([ { var APP = window.APP = { editable: false, - mobile: function () { return $('body').width() <= 600; } // Menu and content area are not inline-block anymore for mobiles + mobile: function () { return $('body').width() <= 600; }, // Menu and content area are not inline-block anymore for mobiles + isMac: navigator.platform === "MacIntel" }; var stringify = function (obj) { @@ -549,7 +550,7 @@ define([ } // Ctrl+A select all - if (e.which === 65 && e.ctrlKey) { + if (e.which === 65 && (e.ctrlKey || (e.metaKey && APP.isMac))) { $content.find('.cp-app-drive-element:not(.cp-app-drive-element-selected)') .addClass('cp-app-drive-element-selected'); return; diff --git a/www/slide/inner.js b/www/slide/inner.js index abbf3828f..44073bb46 100644 --- a/www/slide/inner.js +++ b/www/slide/inner.js @@ -556,7 +556,6 @@ define([ }; var getThumbnailContainer = function () { - var $codeMirror = $('.CodeMirror'); var $c = $('#cp-app-slide-editor'); if ($c.hasClass('cp-app-slide-preview')) { return $('.cp-app-slide-frame').first()[0]; From b0dba481d834d77bcf36b1ef0a488ce8f4fc3eb2 Mon Sep 17 00:00:00 2001 From: yflory <yann.flory@xwiki.com> Date: Fri, 2 Mar 2018 18:33:43 +0100 Subject: [PATCH 19/21] Fix small UI issues and IE issues --- customize.dist/pages.js | 12 ++-- .../src/less2/include/creation.less | 5 ++ customize.dist/src/less2/include/help.less | 32 +++++++++++ .../src/less2/include/markdown-toolbar.less | 20 +++++++ customize.dist/src/less2/include/toolbar.less | 57 +++---------------- www/common/common-interface.js | 4 +- www/common/common-ui-elements.js | 26 ++++++++- www/common/diffMarked.js | 5 +- www/common/toolbar3.js | 4 +- www/pad/app-pad.less | 6 +- www/pad/inner.js | 1 - www/poll/inner.js | 1 + www/whiteboard/app-whiteboard.less | 13 ++++- www/whiteboard/inner.js | 8 +++ 14 files changed, 126 insertions(+), 68 deletions(-) create mode 100644 customize.dist/src/less2/include/help.less create mode 100644 customize.dist/src/less2/include/markdown-toolbar.less diff --git a/customize.dist/pages.js b/customize.dist/pages.js index 811714531..9dd366da2 100644 --- a/customize.dist/pages.js +++ b/customize.dist/pages.js @@ -756,10 +756,14 @@ define([ Pages['/whiteboard/'] = Pages['/whiteboard/index.html'] = function () { return [ appToolbar(), - h('div#cp-app-whiteboard-canvas-area', h('canvas#cp-app-whiteboard-canvas', { - width: 600, - height: 600 - })), + h('div#cp-app-whiteboard-canvas-area', + h('div#cp-app-whiteboard-container', + h('canvas#cp-app-whiteboard-canvas', { + width: 600, + height: 600 + }) + ) + ), h('div#cp-app-whiteboard-controls', { style: { display: 'block', diff --git a/customize.dist/src/less2/include/creation.less b/customize.dist/src/less2/include/creation.less index 2ca8cc402..16bce0637 100644 --- a/customize.dist/src/less2/include/creation.less +++ b/customize.dist/src/less2/include/creation.less @@ -25,6 +25,7 @@ text-align: center; font: @colortheme_app-font; width: 100%; + outline: none; & > div { width: 60vw; max-width: 100%; @@ -88,6 +89,10 @@ &:hover { background: darken(@colortheme_loading-bg, 5%); } + &.cp-creation-button-selected { + color: darken(@colortheme_loading-bg, 10%); + background: @colortheme_loading-color; + } } } diff --git a/customize.dist/src/less2/include/help.less b/customize.dist/src/less2/include/help.less new file mode 100644 index 000000000..905c453fb --- /dev/null +++ b/customize.dist/src/less2/include/help.less @@ -0,0 +1,32 @@ +@import (once) "./colortheme-all.less"; + +.help_main (@color, @bg-color) { + .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; } + } + } +} diff --git a/customize.dist/src/less2/include/markdown-toolbar.less b/customize.dist/src/less2/include/markdown-toolbar.less new file mode 100644 index 000000000..4fb466525 --- /dev/null +++ b/customize.dist/src/less2/include/markdown-toolbar.less @@ -0,0 +1,20 @@ +@import (once) "./colortheme-all.less"; + +.markdownToolbar_main (@color, @bg-color) { + .cp-markdown-toolbar { + height: @toolbar_line-height; + background-color: lighten(@bg-color, 20%); + display: none; + button { + height: @toolbar_line-height !important; + outline: 0; + color: @color; + .toolbar_button; + font: normal normal normal 14px/1 FontAwesome; + &:hover { + background-color: lighten(@bg-color, 8%); + } + &.cp-markdown-help { float: right; } + } + } +} diff --git a/customize.dist/src/less2/include/toolbar.less b/customize.dist/src/less2/include/toolbar.less index b6258c4fe..a0c01e377 100644 --- a/customize.dist/src/less2/include/toolbar.less +++ b/customize.dist/src/less2/include/toolbar.less @@ -8,6 +8,8 @@ @import (once) "./tools.less"; @import (once) "./icons.less"; @import (once) "./modal.less"; +@import (once) "./markdown-toolbar.less"; +@import (once) "./help.less"; .toolbar_main ( @color: @colortheme_default-color, // Color of the text for the toolbar @@ -24,6 +26,8 @@ .ckeditor_fix(); .history_main(); .iconColors_main(); + .markdownToolbar_main(@color, @bg-color); + .help_main(@color, @bg-color); .cp-toolbar-container { display: flex; @@ -239,55 +243,6 @@ } } - // TODO(cjd) This ought to be in a less file for markdown-based editors - .cp-markdown-toolbar { - height: @toolbar_line-height; - background-color: lighten(@bg-color, 20%); - display: none; - button { - height: @toolbar_line-height !important; - outline: 0; - color: @color; - .toolbar_button; - font: normal normal normal 14px/1 FontAwesome; - &:hover { - background-color: lighten(@bg-color, 8%); - } - &.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; @@ -450,6 +405,7 @@ font-size: @colortheme_app-font-size; flex: 1; max-width: none; + line-height: calc(@toolbar_line-height - 12px); // padding + border } } } @@ -615,7 +571,7 @@ } input { max-width: ~"calc(100% - 40px)"; - flex: 1; + //flex: 1; vertical-align: middle; box-sizing: border-box; cursor: auto; @@ -623,6 +579,7 @@ font-size: 20px; padding: 5px 5px; height: 40px; + line-height: 28px; // padding + border } } .cp-toolbar-link, .cp-toolbar-new { diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 4822e357b..5286a9ac6 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -668,7 +668,6 @@ define([ position: 'bottom', distance: 0, performance: true, - dynamicTitle: true, delay: [delay, 0], sticky: true }); @@ -691,6 +690,9 @@ define([ mutations.forEach(function(mutation) { if (mutation.type === "childList") { for (var i = 0; i < mutation.addedNodes.length; i++) { + if ($(mutation.addedNodes[i]).attr('title')) { + addTippy(0, mutation.addedNodes[i]); + } $(mutation.addedNodes[i]).find('[title]').each(addTippy); } for (var j = 0; j < mutation.removedNodes.length; j++) { diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 35a5d38ec..de550dc0c 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -588,7 +588,6 @@ define([ return; }); }); - }); break; case 'present': @@ -1777,7 +1776,7 @@ define([ var $body = $('body'); var $creationContainer = $('<div>', { id: 'cp-creation-container' }).appendTo($body); - var $creation = $('<div>', { id: 'cp-creation' }).appendTo($creationContainer); + var $creation = $('<div>', { id: 'cp-creation', tabindex: 1 }).appendTo($creationContainer); var setHTML = function (e, html) { e.innerHTML = html; @@ -1980,6 +1979,29 @@ define([ $ok[0], $spinner[0] ])).appendTo($creation); + + var selected = -1; + var next = function () { + selected = ++selected % $creation.find('button').length; + $creation.find('button').removeClass('cp-creation-button-selected'); + $($creation.find('button').get(selected)).addClass('cp-creation-button-selected'); + }; + + $creation.keydown(function (e) { + if (e.which === 9) { + e.preventDefault(); + e.stopPropagation(); + next(); + return; + } + if (e.which === 13) { + if ($creation.find('.cp-creation-button-selected').length === 1) { + $creation.find('.cp-creation-button-selected').click(); + } + return; + } + }); + $creation.focus(); }; UIElements.onServerError = function (common, err, toolbar, cb) { diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index f79d8cbdc..47e869fc9 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -116,6 +116,7 @@ define([ /* remove listeners from the DOM */ var removeListeners = function (root) { + if (!root) { return; } slice(root.attributes).map(function (attr) { if (/^on/i.test(attr.name)) { console.log('removing attribute', attr.name, root.attributes[attr.name]); @@ -171,7 +172,9 @@ define([ return mt + '</media-tag>'; }); - var safe_newHtmlFixed = domFromHTML(unsafe_newHtmlFixed).body.outerHTML; + var newDomFixed = domFromHTML(unsafe_newHtmlFixed); + if (!newDomFixed || !newDomFixed.body) { return; } + var safe_newHtmlFixed = newDomFixed.body.outerHTML; var $div = $('<div>', {id: id}).append(safe_newHtmlFixed); var Dom = domFromHTML($('<div>').append($div).html()); diff --git a/www/common/toolbar3.js b/www/common/toolbar3.js index a000025d1..38cb2d759 100644 --- a/www/common/toolbar3.js +++ b/www/common/toolbar3.js @@ -318,7 +318,7 @@ define([ $span.append($rightCol); } else { Common.displayAvatar($span, data.avatar, name, function ($img) { - if (data.avatar && $img.length) { + if (data.avatar && $img && $img.length) { avatars[data.avatar] = $img[0].outerHTML; } $span.append($rightCol); @@ -610,7 +610,7 @@ define([ }); }); $('.cp-toolbar-top').append($msg); - UI.addTooltips(); + //UI.addTooltips(); }); }; diff --git a/www/pad/app-pad.less b/www/pad/app-pad.less index 9e1b1da78..fa7d1142a 100644 --- a/www/pad/app-pad.less +++ b/www/pad/app-pad.less @@ -13,7 +13,6 @@ #cke_1_top { overflow: visible; padding: 0px; - display: flex; } .cke_toolbox_main { background-color: @colortheme_pad-toolbar-bg; @@ -23,10 +22,7 @@ } } .cke_wysiwyg_frame { - min-width: 60%; - } - #cke_1_toolbox { - flex: 1; + width: 100%; } #cke_editor1 { display: flex; diff --git a/www/pad/inner.js b/www/pad/inner.js index 4aff47102..5d161142b 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -629,7 +629,6 @@ define([ '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'); diff --git a/www/poll/inner.js b/www/poll/inner.js index 6a77db8a9..a8deebbfe 100644 --- a/www/poll/inner.js +++ b/www/poll/inner.js @@ -820,6 +820,7 @@ define([ var checkDeletedCells = function () { // faster than forEach? var c; + if (!APP.proxy || !APP.proxy.content) { return; } for (var k in APP.proxy.content.cells) { c = Render.getCoordinates(k); if (APP.proxy.content.colsOrder.indexOf(c[0]) === -1 || diff --git a/www/whiteboard/app-whiteboard.less b/www/whiteboard/app-whiteboard.less index 7bbb7fbaf..1aba715a9 100644 --- a/www/whiteboard/app-whiteboard.less +++ b/www/whiteboard/app-whiteboard.less @@ -42,6 +42,13 @@ display: none; } + #cp-app-whiteboard-container { + flex: 1; + display: flex; + flex-flow: column; + overflow: auto; + } + // created in the html #cp-app-whiteboard-canvas-area { flex: 1; @@ -51,6 +58,8 @@ .cp-app-whiteboard-canvas-container { margin: auto; background: white; + flex: 1; + min-height: 0; & > canvas { border: 1px solid black; } @@ -71,7 +80,7 @@ border-top: 1px solid black; background: white; - padding: 1em; + padding: 10px; & > * + * { margin: 0; @@ -127,7 +136,7 @@ display: flex; justify-content: space-between; - padding: 1em; + padding: 10px; span.cp-app-whiteboard-palette-color { height: 4vw; diff --git a/www/whiteboard/inner.js b/www/whiteboard/inner.js index 7228f50c4..efa8edd87 100644 --- a/www/whiteboard/inner.js +++ b/www/whiteboard/inner.js @@ -454,6 +454,14 @@ define([ var $properties = common.createButton('properties', true); toolbar.$drawer.append($properties); + if (Messages.whiteboardHelp) { + var $appContainer = $('#cp-app-whiteboard-container'); + var helpMenu = common.createHelpMenu(); + $appContainer.prepend(helpMenu.menu); + $(helpMenu.text).html(Messages.whiteboardHelp); + toolbar.$drawer.append(helpMenu.button); + } + if (!readOnly) { makeColorButton($rightside); From 62186bd4bd25a96220d79664bd2f3f2ba3cf2e9d Mon Sep 17 00:00:00 2001 From: yflory <yann.flory@xwiki.com> Date: Mon, 5 Mar 2018 11:19:01 +0100 Subject: [PATCH 20/21] Remove tooltip when the element is removed from DOM --- www/common/common-interface.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 5286a9ac6..d10b289cd 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -677,6 +677,12 @@ define([ setInterval(UI.clearTooltips, delay); var checkRemoved = function (x) { var out = false; + var xId = $(x).attr('aria-describedby'); + if (xId) { + if (xId.indexOf('tippy-tooltip-') === 0) { + return true; + } + } $(x).find('[aria-describedby]').each(function (i, el) { var id = el.getAttribute('aria-describedby'); if (id.indexOf('tippy-tooltip-') !== 0) { return; } From fdf2899e8819274f34605179cc4ad0520d8ebfb7 Mon Sep 17 00:00:00 2001 From: ansuz <ansuz@transitiontech.ca> Date: Mon, 5 Mar 2018 14:51:22 +0100 Subject: [PATCH 21/21] @kpcyrd said I should update this --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 01dd38ab1..d91081835 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "version": "1.27.0", "dependencies": { "chainpad-server": "^2.0.0", - "express": "~4.10.1", + "express": "~4.16.0", "nthen": "~0.1.0", "pull-stream": "^3.6.1", "replify": "^1.2.0",