diff --git a/customize.dist/loading.js b/customize.dist/loading.js index 53e20b561..6dfe84b4d 100644 --- a/customize.dist/loading.js +++ b/customize.dist/loading.js @@ -151,6 +151,24 @@ define([], function () { max-width: 60%; display: inline-block; } +.cp-loading-progress { + width: 100%; + margin: 20px; +} +.cp-loading-progress p { + margin: 5px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.cp-loading-progress-bar { + height: 5px; + background: white; +} +.cp-loading-progress-bar-value { + height: 100%; + background: #00ff37; +} */}).toString().slice(14, -3); var urlArgs = window.location.href.replace(/^.*\?([^\?]*)$/, function (all, x) { return x; }); var elem = document.createElement('div'); diff --git a/customize.dist/src/less2/include/creation.less b/customize.dist/src/less2/include/creation.less index 8dd9469b1..57509455e 100644 --- a/customize.dist/src/less2/include/creation.less +++ b/customize.dist/src/less2/include/creation.less @@ -334,7 +334,7 @@ width: 95%; margin: 10px auto; } - .cp-creation-expire{ + .cp-creation-expire { &.active { label { flex: 1; diff --git a/customize.dist/translations/messages.fr.js b/customize.dist/translations/messages.fr.js index 4d40a2074..c2342b272 100644 --- a/customize.dist/translations/messages.fr.js +++ b/customize.dist/translations/messages.fr.js @@ -1120,5 +1120,12 @@ define(function () { out.share_embedCategory = "Intégration"; out.share_mediatagCopy = "Copier le mediatag"; + // Loading info + out.loading_pad_1 = "Initialisation du pad"; + out.loading_pad_2 = "Chargement du contenu du pad"; + out.loading_drive_1 = "Préparation des données de l'utilisateur"; + out.loading_drive_2 = "Mise à jour des données de l'utilisateur"; + out.loading_drive_3 = "Vérification des données de l'utilisateur"; + return out; }); diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index cd0e02477..15fb9a18b 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -1166,6 +1166,12 @@ define(function () { out.share_embedCategory = "Embed"; out.share_mediatagCopy = "Copy mediatag to clipboard"; + // Loading info + out.loading_pad_1 = "Initializing pad"; + out.loading_pad_2 = "Loading pad content"; + out.loading_drive_1 = "Preparing user data"; + out.loading_drive_2 = "Upgrading user data to the latest version"; + out.loading_drive_3 = "Checking user data integrity"; return out; }); diff --git a/www/common/common-interface.js b/www/common/common-interface.js index f38dadddd..9de70ef54 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -590,6 +590,11 @@ define([ var rdm = Math.floor(Math.random() * keys.length); return Messages.tips[keys[rdm]]; };*/ + var loading = { + error: false, + driveState: 0, + padState: 0 + }; UI.addLoadingScreen = function (config) { config = config || {}; var loadingText = config.loadingText; @@ -598,11 +603,21 @@ define([ $loading.css('display', ''); $loading.removeClass('cp-loading-hidden'); $('.cp-loading-spinner-container').show(); - if (loadingText) { - $('#' + LOADING).find('p').show().text(loadingText); - } else { - $('#' + LOADING).find('p').hide().text(''); + if (config.progress && !$loading.find('.cp-loading-progress').length) { + var progress = h('div.cp-loading-progress', [ + h('p.cp-loading-progress-drive'), + h('p.cp-loading-progress-pad') + ]); + $loading.find('.cp-loading-container').append(progress); + } else if (!config.progress) { + $loading.find('.cp-loading-progress').remove(); } + if (loadingText) { + $('#' + LOADING).find('#cp-loading-message').show().text(loadingText); + } else { + $('#' + LOADING).find('#cp-loading-message').hide().text(''); + } + loading.error = false; }; if ($('#' + LOADING).length) { todo(); @@ -611,6 +626,59 @@ define([ todo(); } }; + UI.updateLoadingProgress = function (data, isDrive) { + var $loading = $('#' + LOADING); + if (!$loading.length || loading.error) { return; } + var $progress; + if (isDrive) { + console.log(data); + // Drive state + if (loading.driveState === -1) { return; } // Already loaded + $progress = $loading.find('.cp-loading-progress-drive'); + if (!$progress.length) { return; } // Can't find the box to display data + + // If state is -1, remove the box, drive is loaded + if (data.state === -1) { + loading.driveState = -1; + $progress.remove(); + } else { + if (data.state < loading.driveState) { return; } // We should not display old data + // Update the current state + loading.driveState = data.state; + data.progress = data.progress || 100; + data.msg = Messages['loading_drive_'+data.state] || ''; + $progress.html(data.msg); + if (data.progress) { + $progress.append(h('div.cp-loading-progress-bar', [ + h('div.cp-loading-progress-bar-value', {style: 'width:'+data.progress+'%;'}) + ])); + } + } + } else { + // Pad state + if (loading.padState === -1) { return; } // Already loaded + $progress = $loading.find('.cp-loading-progress-pad'); + if (!$progress.length) { return; } // Can't find the box to display data + + // If state is -1, remove the box, pad is loaded + if (data.state === -1) { + loading.padState = -1; + $progress.remove(); + } else { + if (data.state < loading.padState) { return; } // We should not display old data + // Update the current state + loading.padState = data.state; + data.progress = data.progress || 100; + data.msg = Messages['loading_pad_'+data.state] || ''; + $progress.html(data.msg); + if (data.progress) { + $progress.append(h('div.cp-loading-progress-bar', [ + h('div.cp-loading-progress-bar-value', {style: 'width:'+data.progress+'%;'}) + ])); + } + } + } + }; UI.removeLoadingScreen = function (cb) { // Release the test blocker, hopefully every test has been registered. // This test is created in sframe-boot2.js @@ -619,6 +687,7 @@ define([ $('#' + LOADING).addClass("cp-loading-hidden"); setTimeout(cb, 750); + loading.error = false; var $tip = $('#cp-loading-tip').css('top', '') // loading.less sets transition-delay: $wait-time // and transition: opacity $fadeout-time @@ -632,13 +701,16 @@ define([ // jquery.fadeout can get stuck }; UI.errorLoadingScreen = function (error, transparent, exitable) { - if (!$('#' + LOADING).is(':visible') || $('#' + LOADING).hasClass('cp-loading-hidden')) { + var $loading = $('#' + LOADING); + if (!$loading.is(':visible') || $loading.hasClass('cp-loading-hidden')) { UI.addLoadingScreen({hideTips: true}); } + loading.error = true; + $loading.find('.cp-loading-progress').remove(); $('.cp-loading-spinner-container').hide(); $('#cp-loading-tip').remove(); - if (transparent) { $('#' + LOADING).css('opacity', 0.9); } - var $error = $('#' + LOADING).find('p').show(); + if (transparent) { $loading.css('opacity', 0.9); } + var $error = $loading.find('#cp-loading-message').show(); if (error instanceof Element) { $error.html('').append(error); } else { @@ -648,7 +720,8 @@ define([ $(window).focus(); $(window).keydown(function (e) { if (e.which === 27) { - $('#' + LOADING).hide(); + $loading.hide(); + loading.error = false; if (typeof(exitable) === "function") { exitable(); } } }); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index daf033274..be120b2a1 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -562,6 +562,10 @@ define([ pad.onDisconnectEvent = Util.mkEvent(); pad.onErrorEvent = Util.mkEvent(); + // Loading events + common.loading = {}; + common.loading.onDriveEvent = Util.mkEvent(); + common.getFullHistory = function (data, cb) { postMessage("GET_FULL_HISTORY", data, cb); }; @@ -726,6 +730,10 @@ define([ case 'DELETE_ACCOUNT': { common.startAccountDeletion(cb); break; } + // Loading + case 'LOADING_DRIVE': { + common.loading.onDriveEvent.fire(data); break; + } } }; diff --git a/www/common/migrate-user-object.js b/www/common/migrate-user-object.js index 6bacc65c1..1d6dd1210 100644 --- a/www/common/migrate-user-object.js +++ b/www/common/migrate-user-object.js @@ -9,7 +9,7 @@ define([ // 1: migrate pad attributes // 2: migrate indent settings (codemirror) - return function (userObject, cb) { + return function (userObject, cb, progress) { var version = userObject.version || 0; nThen(function () { @@ -107,7 +107,8 @@ define([ var data = userObject.drive.filesData; var el, parsed; var n = nThen(function () {}); - Object.keys(data).forEach(function (k) { + var padsLength = Object.keys(data).length; + Object.keys(data).forEach(function (k, i) { n = n.nThen(function (w) { setTimeout(w(function () { el = data[k]; @@ -121,6 +122,7 @@ define([ var secret = Hash.getSecrets(parsed.type, parsed.hash, el.password); el.channel = secret.channel; } + progress(6, Math.round(100*i/padsLength)); console.log('Adding missing channel in filesData ', el.channel); } })); @@ -133,6 +135,16 @@ define([ Feedback.send('Migrate-6', true); userObject.version = version = 6; } + /*}).nThen(function (waitFor) { + // Test progress bar in the loading screen + var i = 0; + var w = waitFor(); + var it = setInterval(function () { + i += 5; + if (i >= 100) { w(); clearInterval(it); i = 100;} + progress(0, i); + }, 500); + progress(0, 0);*/ }).nThen(function () { cb(); }); diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 17c4e1c56..d4c4b30f0 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -694,7 +694,6 @@ define([ expire = +Store.channel.data.expire || undefined; } - console.log(owners, expire); var allPads = Util.find(store.proxy, ['drive', 'filesData']) || {}; var isStronger; @@ -1053,10 +1052,21 @@ define([ } }); nThen(function (waitFor) { + postMessage('LOADING_DRIVE', { + state: 2 + }); userObject.migrate(waitFor()); }).nThen(function (waitFor) { - Migrate(proxy, waitFor()); + Migrate(proxy, waitFor(), function (version, progress) { + postMessage('LOADING_DRIVE', { + state: 2, + progress: progress + }); + }); }).nThen(function () { + postMessage('LOADING_DRIVE', { + state: 3 + }); userObject.fixFiles(); var requestLogin = function () { @@ -1164,6 +1174,7 @@ define([ && !drive['filesData']) { drive[Constants.oldStorageKey] = []; } + postMessage('LOADING_DRIVE', { state: 1 }); // Drive already exist: return the existing drive, don't load data from legacy store onReady(returned, cb); }) diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index 0777d2fb6..dc2313693 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -279,6 +279,8 @@ define([ var newContentStr = cpNfInner.chainpad.getUserDoc(); if (state === STATE.DELETED) { return; } + UI.updateLoadingProgress({ state: -1 }, false); + var newPad = false; if (newContentStr === '') { newPad = true; } @@ -429,8 +431,11 @@ define([ }; nThen(function (waitFor) { - UI.addLoadingScreen(); + UI.addLoadingScreen({progress: true}); SFCommon.create(waitFor(function (c) { common = c; })); + UI.updateLoadingProgress({ + state: 1 + }, false); }).nThen(function (waitFor) { common.getSframeChannel().onReady(waitFor()); }).nThen(function (waitFor) { @@ -442,7 +447,7 @@ define([ patchTransformer: options.patchTransformer || ChainPad.SmartJSONTransformer, // cryptpad debug logging (default is 1) - logLevel: 2, + logLevel: 1, validateContent: options.validateContent || function (content) { try { JSON.parse(content); @@ -456,7 +461,12 @@ define([ }, onRemote: onRemote, onLocal: onLocal, - onInit: function () { stateChange(STATE.INITIALIZING); }, + onInit: function () { + UI.updateLoadingProgress({ + state: 2 + }, false); + stateChange(STATE.INITIALIZING); + }, onReady: function () { evStart.reg(onReady); }, onConnectionChange: onConnectionChange, onError: onError diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index bc9d50d00..7c14a86a6 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -90,7 +90,16 @@ define([ SFrameChannel.create($('#sbox-iframe')[0].contentWindow, waitFor(function (sfc) { sframeChan = sfc; }), false, { cache: cache, localStore: localStore, language: Cryptpad.getLanguage() }); - Cryptpad.ready(waitFor(), { + Cryptpad.loading.onDriveEvent.reg(function (data) { + if (sframeChan) { sframeChan.event('EV_LOADING_INFO', data); } + }); + Cryptpad.ready(waitFor(function () { + if (sframeChan) { + sframeChan.event('EV_LOADING_INFO', { + state: -1 + }); + } + }), { messenger: cfg.messaging, driveEvents: cfg.driveEvents }); diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 2d6006187..dca14afb9 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -433,6 +433,10 @@ define([ UIElements.displayPasswordPrompt(funcs); }); + ctx.sframeChan.on('EV_LOADING_INFO', function (data) { + UI.updateLoadingProgress(data, true); + }); + ctx.metadataMgr.onReady(waitFor()); }).nThen(function () { try { diff --git a/www/common/sframe-protocol.js b/www/common/sframe-protocol.js index 970ec5524..a0e9b82c2 100644 --- a/www/common/sframe-protocol.js +++ b/www/common/sframe-protocol.js @@ -234,4 +234,7 @@ define({ // Ask for the pad password when a pad is protected 'EV_PAD_PASSWORD': true, 'Q_PAD_PASSWORD_VALUE': true, + + // Loading events to display in the loading screen + 'EV_LOADING_INFO': true, });