From 87abfff66bae684c1b5ff7de5b8d5f2933df998e Mon Sep 17 00:00:00 2001 From: yflory Date: Wed, 21 Dec 2016 18:33:21 +0100 Subject: [PATCH] Fix Flash Of Unstyled Content (fouc) --- customize.dist/DecorateToolbar.js | 3 +- customize.dist/fsStore.js | 7 +---- customize.dist/main.css | 31 +++++++++++++++++++ customize.dist/src/cryptpad.less | 30 +++++++++++++++++++ customize.dist/src/variables.less | 1 + customize.dist/translations/messages.fr.js | 5 ++++ customize.dist/translations/messages.js | 4 +++ www/code/main.js | 9 ++---- www/common/cryptpad-common.js | 35 +++++++++++++++++----- www/file/fileObject.js | 19 +++++++----- www/file/main.js | 22 ++++++++++---- www/pad/main.js | 9 ++---- www/poll/test/main.js | 17 +++++++---- www/slide/main.js | 8 ++--- 14 files changed, 149 insertions(+), 51 deletions(-) diff --git a/customize.dist/DecorateToolbar.js b/customize.dist/DecorateToolbar.js index 49a30c79f..023c929e1 100644 --- a/customize.dist/DecorateToolbar.js +++ b/customize.dist/DecorateToolbar.js @@ -10,8 +10,7 @@ define([ var main = function () { var url = window.location.pathname; var isHtml = /\.html/.test(url) || url === '/' || url === ''; - var isPoll = /\/poll\//.test(url); - if (!isHtml && !isPoll) { + if (!isHtml) { Messages._applyTranslation(); return; } diff --git a/customize.dist/fsStore.js b/customize.dist/fsStore.js index 7910a5cf3..f600819b1 100644 --- a/customize.dist/fsStore.js +++ b/customize.dist/fsStore.js @@ -146,11 +146,6 @@ define([ if (!Cryptpad.getUserHash()) { localStorage.FS_hash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys); } - window.patchText = TextPatcher.create({ - realtime: realtime, - logging: true, - }); - }).on('ready', function () { if (!rt.proxy[Cryptpad.storageKey] || !Cryptpad.isArray(rt.proxy[Cryptpad.storageKey])) { var oldStore = Cryptpad.getStore(true); @@ -171,7 +166,7 @@ define([ } return; } - Cryptpad.alert(Messages.common_connectionLost); + //Cryptpad.alert(Messages.common_connectionLost); }); }; diff --git a/customize.dist/main.css b/customize.dist/main.css index b9c517a63..14cf8bf32 100644 --- a/customize.dist/main.css +++ b/customize.dist/main.css @@ -315,6 +315,37 @@ tr { font-family: lato, Helvetica, sans-serif; font-size: 1.02em; } +#loading { + position: fixed; + z-index: 9999; + top: 0px; + bottom: 0px; + left: 0px; + right: 0px; + background: #302B28; + text-align: center; + font-size: 1.5em; +} +#loading .loadingContainer { + margin-top: 50vh; + transform: translateY(-50%); +} +#loading .cryptofist { + margin-left: auto; + margin-right: auto; +} +@media screen and (max-height: 450px) { + #loading .cryptofist { + display: none; + } +} +#loading .spinnerContainer { + position: relative; + height: 100px; +} +#loading .spinnerContainer > div { + height: 100px; +} #main { width: 70vw; margin: auto; diff --git a/customize.dist/src/cryptpad.less b/customize.dist/src/cryptpad.less index 07fc138aa..2e1b44467 100644 --- a/customize.dist/src/cryptpad.less +++ b/customize.dist/src/cryptpad.less @@ -142,6 +142,36 @@ p, pre, td, a, table, tr { .lato; } +#loading { + position: fixed; + z-index: 9999; + top: 0px; + bottom: 0px; + left: 0px; + right: 0px; + background: @bg-loading; + text-align: center; + font-size: 1.5em; + .loadingContainer { + margin-top: 50vh; + transform: translateY(-50%); + } + .cryptofist { + margin-left: auto; + margin-right: auto; + @media screen and (max-height: 450px) { + display: none; + } + } + .spinnerContainer { + position: relative; + height: 100px; + > div { + height: 100px; + } + } +} + #main { width: 70vw; margin: auto; diff --git a/customize.dist/src/variables.less b/customize.dist/src/variables.less index c6d555219..f3db72022 100644 --- a/customize.dist/src/variables.less +++ b/customize.dist/src/variables.less @@ -32,3 +32,4 @@ @alertify-input-bg: @base; @alertify-input-fg: @fore; +@bg-loading: @base; diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 3fa0bd5a1..ac72aefc6 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -19,6 +19,10 @@ define(function () { ].join(''); out.common_connectionLost = 'Connexion au serveur perdue'; + out.websocketError = 'Impossible de se connecter au serveur WebSocket...'; + + out.loading = "Chargement..."; + out.error = "Erreur"; out.disconnected = 'Déconnecté'; out.synchronizing = 'Synchronisation'; @@ -212,6 +216,7 @@ define(function () { out.fo_existingNameError = "Ce nom est déjà utilisé dans ce répertoire. Veuillez en choisir un autre."; out.fo_moveFolderToChildError = "Vous ne pouvez pas déplacer un dossier dans un de ses descendants"; out.fo_unableToRestore = "Impossible de restaurer ce fichier à son emplacement d'origine. Vous pouvez essayer de le déplacer à un nouvel emplacement."; + out.fo_unavailableName = "Un fichier ou dossier avec le même nom existe déjà au nouvel emplacement. Renommez cet élément avant d'essayer à nouveau."; // index.html diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 3bb537252..359985acd 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -23,6 +23,9 @@ define(function () { out.common_connectionLost = 'Server Connection Lost'; out.websocketError = 'Unable to connect to the websocket server...'; + out.loading = "Loading..."; + out.error = "Error"; + out.disconnected = 'Disconnected'; out.synchronizing = 'Synchronizing'; out.reconnecting = 'Reconnecting...'; @@ -211,6 +214,7 @@ define(function () { out.fo_existingNameError = "Name already used in that directory. Please choose another one."; out.fo_moveFolderToChildError = "You can't move a folder into one of its descendants"; out.fo_unableToRestore = "Unable to restore that file to its original location. You can try to move it to a new location."; + out.fo_unavailableName = "A file or a folder with the same name already exist at the new location. Rename the element and try again."; // login out.login_login = "log in"; diff --git a/www/code/main.js b/www/code/main.js index 54e166fed..1f22b4e92 100644 --- a/www/code/main.js +++ b/www/code/main.js @@ -21,12 +21,10 @@ define([ var module = window.APP = { Cryptpad: Cryptpad, - spinner: Cryptpad.spinner(document.body), }; Cryptpad.styleAlerts(); - - module.spinner.show(); + Cryptpad.addLoadingScreen(); var ifrw = module.ifrw = $('#pad-iframe')[0].contentWindow; var stringify = function (obj) { @@ -43,8 +41,7 @@ define([ } var onConnectError = function (info) { - module.spinner.hide(); - Cryptpad.alert(Messages.websocketError); + Cryptpad.errorLoadingScreen(Messages.websocketError); }; var andThen = function (CMeditor) { @@ -565,7 +562,7 @@ define([ }); } - $(module.spinner.get().el).fadeOut(750); + Cryptpad.removeLoadingScreen(); setEditable(true); initializing = false; //Cryptpad.log("Your document is ready"); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 09f44d3d9..545f9b519 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -735,6 +735,26 @@ define([ }); }; + var LOADING = 'loading'; + common.addLoadingScreen = function () { + var $loading = $('
', {id: LOADING}); + var $container = $('
', {'class': 'loadingContainer'}); + $container.append(''); + var $spinner = $('
', {'class': 'spinnerContainer'}); + loadingSpinner = common.spinner($spinner).show(); + var $text = $('

').text(Messages.loading); + $container.append($spinner).append($text); + $loading.append($container); + $('body').append($loading); + }; + common.removeLoadingScreen = function () { + $('#' + LOADING).fadeOut(750); + }; + common.errorLoadingScreen = function (error) { + $('.spinnerContainer').hide(); + $('#' + LOADING).find('p').text(error || Messages.error); + }; + /* * Saving files */ @@ -1066,17 +1086,17 @@ define([ $(parent).append($target); var opts = { - lines: 9, // The number of lines to draw - length: 12, // The length of each line - width: 11, // The line thickness - radius: 20, // The radius of the inner circle + lines: 20, // The number of lines to draw + length: 5, // The length of each line + width: 2, // The line thickness + radius: 15, // The radius of the inner circle scale: 2, // Scales overall size of the spinner corners: 1, // Corner roundness (0..1) - color: '#777', // #rgb or #rrggbb or array of colors + color: '#ddd', // #rgb or #rrggbb or array of colors opacity: 0.3, // Opacity of the lines rotate: 31, // The rotation offset direction: 1, // 1: clockwise, -1: counterclockwise - speed: 0.9, // Rounds per second + speed: 1, // Rounds per second trail: 49, // Afterglow percentage fps: 20, // Frames per second when using setTimeout() as a fallback for CSS zIndex: 2e9, // The z-index (defaults to 2000000000) @@ -1085,7 +1105,8 @@ define([ left: '50%', // Left position relative to parent shadow: false, // Whether to render a shadow hwaccel: false, // Whether to use hardware acceleration - position: 'absolute', // Element positioning + position: 'relative', // Element positioning + height: '100px' }; var spinner = new Spinner(opts).spin($target[0]); diff --git a/www/file/fileObject.js b/www/file/fileObject.js index 2a339b9cc..d7d7f0a4a 100644 --- a/www/file/fileObject.js +++ b/www/file/fileObject.js @@ -254,7 +254,7 @@ define([ var parentEl = exp.findElement(files, parentPath); if (path.length === 4 && path[0] === TRASH) { files[TRASH][path[1]].splice(path[2], 1); - } else if (path[0] === UNSORTED) { + } else if (path[0] === UNSORTED) { //TODO || === TEMPLATE parentEl.splice(key, 1); } else { parentEl[key] = undefined; @@ -264,6 +264,7 @@ define([ }; // Find an element in a object following a path, resursively + // NOTE: it is always used with an absolute path and root === files in our code var findElement = exp.findElement = function (root, pathInput) { if (!pathInput) { error("Invalid path:\n", pathInput, "\nin root\n", root); @@ -279,6 +280,7 @@ define([ return findElement(root[key], path); }; + // Get the object {element: element, path: [path]} from a trash root path var getTrashElementData = exp.getTrashElementData = function (trashPath) { if (!isInTrashRoot) { debug("Called getTrashElementData on a element not in trash root: ", trashPath); @@ -289,6 +291,7 @@ define([ return findElement(files, parentPath); }; + // Get data from AllFiles (Cryptpad_RECENTPADS) var getFileData = exp.getFileData = function (file) { if (!file) { return; } var res; @@ -328,6 +331,7 @@ define([ }; // Move to trash + // TODO: rename the function var removeElement = exp.removeElement = function (path, cb, keepOld) { if (!path || path.length < 2 || path[0] === TRASH) { debug("Calling removeElement from a wrong path: ", path); @@ -343,6 +347,7 @@ define([ if (cb) { cb(); } }; + //TODO add suport for TEMPLATE here var moveElement = exp.moveElement = function (elementPath, newParentPath, cb, keepOld) { if (comparePath(elementPath, newParentPath)) { return; } // Nothing to do... if (isPathInTrash(newParentPath)) { @@ -353,12 +358,13 @@ define([ var newParent = findElement(files, newParentPath); + // Never move a folder in one of its children if (isFolder(element) && isSubpath(newParentPath, elementPath)) { log(Messages.fo_moveFolderToChildError); return; } - if (isPathInUnsorted(newParentPath)) { + if (isPathInUnsorted(newParentPath)) { //TODO || TEMPLATE if (isFolder(element)) { log(Messages.fo_moveUnsortedError); return; @@ -386,7 +392,7 @@ define([ var newName = !isPathInRoot(elementPath) ? getAvailableName(newParent, name) : name; if (typeof(newParent[newName]) !== "undefined") { - log("A file with the same name already exist at the new location. Rename the file and try again."); + log(Messages.fo_unavailableName); return; } newParent[newName] = element; @@ -523,6 +529,7 @@ define([ var emptyTrash = exp.emptyTrash = function (cb) { files[TRASH] = {}; + checkDeletedFiles(); if(cb) { cb(); } }; @@ -592,7 +599,7 @@ define([ var fixFiles = exp.fixFiles = function () { // Explore the tree and check that everything is correct: - // * 'root', 'trash' and 'filesData' exist and are objects + // * 'root', 'trash', 'unsorted' and 'filesData' exist and are objects // * ROOT: Folders are objects, files are href // * TRASH: Trash root contains only arrays, each element of the array is an object {element:.., path:..} // * FILES_DATA: - Data (title, cdate, adte) are stored in filesData. filesData contains only href keys linking to object with title, cdate, adate. @@ -601,10 +608,6 @@ define([ // * UNSORTED: Contains only files (href), and does not contains files that are in ROOT debug("Cleaning file system..."); - // Create a backup - if (typeof(localStorage.oldFileSystem) === "undefined") { - localStorage.oldFileSystem = '[]'; - } var before = JSON.stringify(files); if (typeof(files[ROOT]) !== "object") { debug("ROOT was not an object"); files[ROOT] = {}; } diff --git a/www/file/main.js b/www/file/main.js index 1f7c40772..f62b2cd39 100644 --- a/www/file/main.js +++ b/www/file/main.js @@ -18,6 +18,11 @@ define([ var $iframe = $('#pad-iframe').contents(); var ifrw = $('#pad-iframe')[0].contentWindow; + Cryptpad.addLoadingScreen(); + var onConnectError = function (info) { + Cryptpad.errorLoadingScreen(Messages.websocketError); + }; + var APP = window.APP = { $bar: $iframe.find('#toolbar'), editable: false @@ -48,12 +53,6 @@ define([ console.error.apply(console, arguments); }; var log = config.log = Cryptpad.log; - var DEBUG_LS = APP.DEBUG_LS = { - resetLocalStorage : function () { - delete localStorage[LOCALSTORAGE_OPENED]; - delete localStorage[LOCALSTORAGE_LAST]; - } - }; var getLastOpenedFolder = function () { var path; @@ -459,6 +458,7 @@ define([ var andThen = function () { filesOp.moveElements(paths, newPath, cb); }; + // "force" is currently unused but may be configurable by user if (newPath[0] !== TRASH || force) { andThen(); return; @@ -1405,6 +1405,7 @@ define([ pressKey(e.which, false); }); $(ifrw).on('keydown', function (e) { + // "Del" if (e.which === 46) { var $selected = $iframe.find('.selected'); if (!$selected.length) { return; } @@ -1552,6 +1553,7 @@ define([ var $backupButton = Cryptpad.createButton('', true); $backupButton.on('click', function() { var url = window.location.origin + window.location.pathname + '#' + editHash; + //TODO change text & transalte Cryptpad.alert("Backup URL for this pad. It is highly recommended that you do not share it with other people.
Anybody with that URL can remove all the files in your file manager.
" + url); }); $userBlock.append($backupButton); @@ -1566,12 +1568,15 @@ define([ proxy[FILES_DATA] = s; initLocalStorage(); init(proxy); + APP.userList.onChange(); + Cryptpad.removeLoadingScreen(); }); return; } initLocalStorage(); init(proxy); APP.userList.onChange(); + Cryptpad.removeLoadingScreen(); }; var onDisconnect = function (info) { setEditable(false); @@ -1593,6 +1598,11 @@ define([ onDisconnect(); }); }); + Cryptpad.onError(function (info) { + if (info) { + onConnectError(); + } + }); }); diff --git a/www/pad/main.js b/www/pad/main.js index 1b929b09f..8f59a898c 100644 --- a/www/pad/main.js +++ b/www/pad/main.js @@ -27,6 +27,7 @@ define([ var DiffDom = window.diffDOM; Cryptpad.styleAlerts(); + Cryptpad.addLoadingScreen(); var stringify = function (obj) { return JSONSortify(obj); @@ -60,7 +61,6 @@ define([ logFights: true, fights: [], Cryptpad: Cryptpad, - spinner: Cryptpad.spinner(document.body), }; var toolbar; @@ -78,8 +78,7 @@ define([ }; var onConnectError = function (info) { - module.spinner.hide(); - Cryptpad.alert(Messages.websocketError); + Cryptpad.errorLoadingScreen(Messages.websocketError); }; var andThen = function (Ckeditor) { @@ -140,9 +139,6 @@ define([ $(inner).css({ color: '#333', }); - $(module.spinner.get().el).fadeOut(750); - } else { - module.spinner.show(); } if (!readOnly || !bool) { inner.setAttribute('contenteditable', bool); @@ -657,6 +653,7 @@ define([ console.log("Unlocking editor"); setEditable(true); initializing = false; + Cryptpad.removeLoadingScreen(); // Update the toolbar list: // Add the current user in the metadata if he has edit rights if (readOnly) { return; } diff --git a/www/poll/test/main.js b/www/poll/test/main.js index 3f72e47ac..4642f40cf 100644 --- a/www/poll/test/main.js +++ b/www/poll/test/main.js @@ -22,6 +22,11 @@ define([ var secret = Cryptpad.getSecrets(); var readOnly = secret.keys && !secret.keys.editKeyStr; + Cryptpad.addLoadingScreen(); + var onConnectError = function (info) { + Cryptpad.errorLoadingScreen(Messages.websocketError); + }; + var APP = window.APP = { Toolbar: Toolbar, Hyperjson: Hyperjson, @@ -566,6 +571,7 @@ define([ } else { publish(true); } + Cryptpad.removeLoadingScreen(); // Update the toolbar list: // Add the current user in the metadata if he has edit rights @@ -662,11 +668,7 @@ define([ var disconnect = function (info) { //setEditable(false); // TODO - if (info.error) { - Cryptpad.alert(Messages.websocketError); - return; - } - //Cryptpad.alert(Messages.common_connectionLost); // TODO + Cryptpad.alert(Messages.common_connectionLost); }; var config = { @@ -715,5 +717,10 @@ define([ } }); }); + Cryptpad.onError(function (info) { + if (info) { + onConnectError(); + } + }); }); diff --git a/www/slide/main.js b/www/slide/main.js index d1dfe212e..2dc6bc913 100644 --- a/www/slide/main.js +++ b/www/slide/main.js @@ -22,7 +22,6 @@ define([ var module = window.APP = { Cryptpad: Cryptpad, - spinner: Cryptpad.spinner(document.body), TextPatcher: TextPatcher, Slide: Slide, }; @@ -32,7 +31,7 @@ define([ var SLIDE_COLOR_ID = "cryptpad-color"; Cryptpad.styleAlerts(); - module.spinner.show(); + Cryptpad.addLoadingScreen(); var stringify = function (obj) { return JSONSortify(obj); @@ -60,8 +59,7 @@ define([ var presentMode = Slide.isPresentURL(); var onConnectError = function (info) { - module.spinner.hide(); - Cryptpad.alert(Messages.websocketError); + Cryptpad.errorLoadingScreen(Messages.websocketError); }; var andThen = function (CMeditor) { @@ -663,7 +661,7 @@ define([ document.title = APP.title; }); - $(module.spinner.get().el).fadeOut(750); + Cryptpad.removeLoadingScreen(); setEditable(true); initializing = false; //Cryptpad.log("Your document is ready");