diff --git a/customize.dist/loading.js b/customize.dist/loading.js index 52a70b5c3..22dc69c31 100644 --- a/customize.dist/loading.js +++ b/customize.dist/loading.js @@ -279,7 +279,7 @@ button:not(.btn).primary:hover{ var built = false; var types = ['less', 'drive', 'migrate', 'sf', 'team', 'pad', 'end']; - var current; + var current, progress; var makeList = function (data) { var c = types.indexOf(data.type); current = c; @@ -295,7 +295,7 @@ button:not(.btn).primary:hover{ }; var list = ''; @@ -303,7 +303,7 @@ button:not(.btn).primary:hover{ }; var makeBar = function (data) { var c = types.indexOf(data.type); - var l = types.length; + var l = types.length - 1; // don't count "end" as a type var progress = Math.min(data.progress, 100); var p = (progress / l) + (100 * c / l); var bar = '
'+ @@ -315,8 +315,13 @@ button:not(.btn).primary:hover{ var hasErrored = false; var updateLoadingProgress = function (data) { if (!built || !data) { return; } + + // Make sure progress doesn't go backward var c = types.indexOf(data.type); if (c < current) { return console.error(data); } + if (c === current && progress > data.progress) { return console.error(data); } + progress = data.progress; + try { var el1 = document.querySelector('.cp-loading-spinner-container'); if (el1) { el1.style.display = 'none'; } diff --git a/customize.dist/src/less2/include/sidebar-layout.less b/customize.dist/src/less2/include/sidebar-layout.less index ace7350df..4273b0b9a 100644 --- a/customize.dist/src/less2/include/sidebar-layout.less +++ b/customize.dist/src/less2/include/sidebar-layout.less @@ -118,7 +118,7 @@ //border-radius: 0 0.25em 0.25em 0; //border: 1px solid #adadad; border-left: 0px; - height: @variables_input-height; + height: 40px; margin: 0 !important; } } diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 9fae121dc..3e9d848cd 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -65,12 +65,13 @@ define([ switch (e.which) { case 27: // cancel if (typeof(no) === 'function') { no(e); } + $(el || window).off('keydown', handler); break; case 13: // enter if (typeof(yes) === 'function') { yes(e); } + $(el || window).off('keydown', handler); break; } - $(el || window).off('keydown', handler); }; $(el || window).keydown(handler); diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 076fa52fe..5dd029def 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -701,7 +701,7 @@ define([ }); }; - common.useFile = function (Crypt, cb, optsPut) { + common.useFile = function (Crypt, cb, optsPut, onProgress) { var fileHost = Config.fileHost || window.location.origin; var data = common.fromFileData; var parsed = Hash.parsePadUrl(data.href); @@ -758,7 +758,9 @@ define([ return void cb(err); } u8 = _u8; - })); + }), function (progress) { + onProgress(progress * 50); + }); }).nThen(function (waitFor) { require(["/file/file-crypto.js"], waitFor(function (FileCrypto) { FileCrypto.decrypt(u8, key, waitFor(function (err, _res) { @@ -767,7 +769,9 @@ define([ return void cb(err); } res = _res; - })); + }), function (progress) { + onProgress(50 + progress * 50); + }); })); }).nThen(function (waitFor) { var ext = Util.parseFilename(data.title).ext; diff --git a/www/common/inner/common-mediatag.js b/www/common/inner/common-mediatag.js index 3d28d126a..86900f5bb 100644 --- a/www/common/inner/common-mediatag.js +++ b/www/common/inner/common-mediatag.js @@ -17,11 +17,18 @@ define([ var Nacl = window.nacl; // Configure MediaTags to use our local viewer + // This file is loaded by sframe-common so the following config is used in all the inner apps if (MediaTag) { MediaTag.setDefaultConfig('pdf', { viewer: '/common/pdfjs/web/viewer.html' }); + Messages.mediatag_saveButton = "Save"; // XXX + MediaTag.setDefaultConfig('download', { + text: Messages.download_mt_button, + textDl: Messages.mediatag_saveButton + }); } + MT.MediaTag = MediaTag; // Cache of the avatars outer html (including ) var avatars = {}; @@ -68,7 +75,7 @@ define([ childList: true, characterData: false }); - MediaTag($tag[0]).on('error', function (data) { + MediaTag($tag[0], {force: true}).on('error', function (data) { console.error(data); }); }; @@ -362,6 +369,10 @@ define([ }); }; + Messages.pad_mediatagShare = "Share file"; // XXX + Messages.pad_mediatagOpen = "Open file"; // XXX + Messages.mediatag_notReady = "Not ready"; // XXX + var mediatagContextMenu; MT.importMediaTagMenu = function (common) { if (mediatagContextMenu) { return mediatagContextMenu; } @@ -377,6 +388,14 @@ define([ 'tabindex': '-1', 'data-icon': "fa-eye", }, Messages.pad_mediatagPreview)), + h('li.cp-svg', h('a.cp-app-code-context-openin.dropdown-item', { + 'tabindex': '-1', + 'data-icon': "fa-external-link", + }, Messages.pad_mediatagOpen)), + h('li.cp-svg', h('a.cp-app-code-context-share.dropdown-item', { + 'tabindex': '-1', + 'data-icon': "fa-shhare-alt", + }, Messages.pad_mediatagShare)), h('li', h('a.cp-app-code-context-saveindrive.dropdown-item', { 'tabindex': '-1', 'data-icon': "fa-cloud-upload", @@ -413,12 +432,29 @@ define([ } else if ($this.hasClass("cp-app-code-context-download")) { var media = Util.find($mt, [0, '_mediaObject']); + if (!media) { return void console.error('no media'); } + if (!media.complete) { return void UI.warn(Messages.mediatag_notReady); } if (!(media && media._blob)) { return void console.error($mt); } window.saveAs(media._blob.content, media.name); } else if ($this.hasClass("cp-app-code-context-open")) { $mt.trigger('preview'); } + else if ($this.hasClass("cp-app-code-context-openin")) { + var hash = common.getHashFromMediaTag($mt); + common.openURL(Hash.hashToHref(hash, 'file')); + } + else if ($this.hasClass("cp-app-code-context-share")) { + var data = { + file: true, + pathname: '/file/', + hashes: { + fileHash: common.getHashFromMediaTag($mt) + }, + title: Util.find($mt[0], ['_mediaObject', 'name']) || '' + }; + common.getSframeChannel().event('EV_SHARE_OPEN', data); + } }); return m; diff --git a/www/common/media-tag.js b/www/common/media-tag.js index e86fd6071..e4ec9ce2a 100644 --- a/www/common/media-tag.js +++ b/www/common/media-tag.js @@ -603,7 +603,8 @@ var factory = function (Cache) { if (cfg.force) { dl(); return mediaObject; } - var maxSize = 5 * 1024 * 1024; + var maxSize = typeof(config.maxDownloadSize) === "number" ? config.maxDownloadSize + : (5 * 1024 * 1024); getFileSize(src, function (err, size) { if (err) { return void error(err); diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index ededee769..a46a94837 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -1808,7 +1808,12 @@ define([ } startRealtime(); cb(); - }, cryptputCfg); + }, cryptputCfg, function (progress) { + sframeChan.event('EV_LOADING_INFO', { + type: 'pad', + progress: progress + }); + }); return; } // Start realtime outside the iframe and callback diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 4198a649a..328bd70c8 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -142,7 +142,7 @@ define([ } return; }; - funcs.importMediaTag = function ($mt) { + var getMtData = function ($mt) { if (!$mt || !$mt.is('media-tag')) { return; } var chanStr = $mt.attr('src'); var keyStr = $mt.attr('data-crypto-key'); @@ -154,10 +154,27 @@ define([ var channel = src.replace(/\/blob\/[0-9a-f]{2}\//i, ''); // Get key var key = keyStr.replace(/cryptpad:/i, ''); + return { + channel: channel, + key: key + }; + }; + funcs.getHashFromMediaTag = function ($mt) { + var data = getMtData($mt); + if (!data) { return; } + return Hash.getFileHashFromKeys({ + version: 1, + channel: data.channel, + keys: { fileKeyStr: data.key } + }); + }; + funcs.importMediaTag = function ($mt) { + var data = getMtData($mt); + if (!data) { return; } var metadata = $mt[0]._mediaObject._blob.metadata; ctx.sframeChan.query('Q_IMPORT_MEDIATAG', { - channel: channel, - key: key, + channel: data.channel, + key: data.key, name: metadata.name, type: metadata.type, owners: metadata.owners @@ -792,6 +809,12 @@ define([ var privateData = ctx.metadataMgr.getPrivateData(); funcs.addShortcuts(window, Boolean(privateData.app)); + var mt = Util.find(privateData, ['settings', 'general', 'mediatag-size']); + if (MT.MediaTag && typeof(mt) === "number") { + var maxMtSize = mt === -1 ? Infinity : mt * 1024 * 1024; + MT.MediaTag.setDefaultConfig('maxDownloadSize', maxMtSize); + } + try { var feedback = privateData.feedbackAllowed; Feedback.init(feedback); diff --git a/www/file/inner.js b/www/file/inner.js index c29657672..6cc129de5 100644 --- a/www/file/inner.js +++ b/www/file/inner.js @@ -39,9 +39,6 @@ define([ var Nacl = window.nacl; var APP = window.APP = {}; - MediaTag.setDefaultConfig('download', { - text: Messages.download_mt_button - }); var andThen = function (common) { var $appContainer = $('#cp-app-file-content'); @@ -203,7 +200,6 @@ define([ cb(); } }).on('progress', function (data) { - if (data.progress > 75) { return; } var p = data.progress +'%'; $progress.width(p); $progressTxt.text(Math.floor(data.progress) + '%'); diff --git a/www/pad/inner.js b/www/pad/inner.js index 5139197e0..8a99b6101 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -46,6 +46,7 @@ define([ '/common/test.js', '/bower_components/diff-dom/diffDOM.js', + '/bower_components/file-saver/FileSaver.min.js', 'css!/customize/src/print.css', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', @@ -1085,6 +1086,9 @@ define([ border: Messages.pad_mediatagBorder, preview: Messages.pad_mediatagPreview, 'import': Messages.pad_mediatagImport, + download: Messages.download_mt_button, + share: Messages.pad_mediatagShare, + open: Messages.pad_mediatagOpen, options: Messages.pad_mediatagOptions }; Ckeditor._commentsTranslations = { @@ -1165,6 +1169,28 @@ define([ editor.plugins.mediatag.import = function($mt) { framework._.sfCommon.importMediaTag($mt); }; + editor.plugins.mediatag.download = function($mt) { + var media = Util.find($mt, [0, '_mediaObject']); + if (!media) { return void console.error('no media'); } + if (!media.complete) { return void UI.warn(Messages.mediatag_notReady); } + if (!(media && media._blob)) { return void console.error($mt); } + window.saveAs(media._blob.content, media.name); + }; + editor.plugins.mediatag.open = function($mt) { + var hash = framework._.sfCommon.getHashFromMediaTag($mt); + framework._.sfCommon.openURL(Hash.hashToHref(hash, 'file')); + }; + editor.plugins.mediatag.share = function($mt) { + var data = { + file: true, + pathname: '/file/', + hashes: { + fileHash: framework._.sfCommon.getHashFromMediaTag($mt) + }, + title: Util.find($mt[0], ['_mediaObject', 'name']) || '' + }; + framework._.sfCommon.getSframeChannel().event('EV_SHARE_OPEN', data); + }; Links.init(Ckeditor, editor); }).nThen(function() { // Move ckeditor parts to have a structure like the other apps diff --git a/www/pad/mediatag-plugin.js b/www/pad/mediatag-plugin.js index 46747b18a..22a732748 100644 --- a/www/pad/mediatag-plugin.js +++ b/www/pad/mediatag-plugin.js @@ -53,15 +53,57 @@ editor.plugins.mediatag.import($mt); } }); + editor.addCommand('downloadMT', { + exec: function (editor) { + var w = targetWidget; + targetWidget = undefined; + var $mt = $(w.$).find('media-tag'); + editor.plugins.mediatag.download($mt); + } + }); + editor.addCommand('openMT', { + exec: function (editor) { + var w = targetWidget; + targetWidget = undefined; + var $mt = $(w.$).find('media-tag'); + editor.plugins.mediatag.open($mt); + } + }); + editor.addCommand('shareMT', { + exec: function (editor) { + var w = targetWidget; + targetWidget = undefined; + var $mt = $(w.$).find('media-tag'); + editor.plugins.mediatag.share($mt); + } + }); if (editor.addMenuItems) { editor.addMenuGroup('mediatag'); + editor.addMenuItem('open', { + label: Messages.open, + icon: 'iframe', + command: 'openMT', + group: 'mediatag' + }); + editor.addMenuItem('share', { + label: Messages.share, + icon: 'link', + command: 'shareMT', + group: 'mediatag' + }); editor.addMenuItem('importMediatag', { label: Messages.import, icon: 'save', command: 'importMediatag', group: 'mediatag' }); + editor.addMenuItem('download', { + label: Messages.download, + icon: 'save', + command: 'downloadMT', + group: 'mediatag' + }); editor.addMenuItem('mediatag', { label: Messages.options, icon: 'image', @@ -76,6 +118,9 @@ targetWidget = element; return { mediatag: CKEDITOR.TRISTATE_OFF, + open: CKEDITOR.TRISTATE_OFF, + share: CKEDITOR.TRISTATE_OFF, + download: CKEDITOR.TRISTATE_OFF, importMediatag: CKEDITOR.TRISTATE_OFF, }; } diff --git a/www/secureiframe/inner.js b/www/secureiframe/inner.js index c20d53a80..4d5b8ee4f 100644 --- a/www/secureiframe/inner.js +++ b/www/secureiframe/inner.js @@ -52,10 +52,10 @@ define([ : Share.getShareModal; f(common, { origin: priv.origin, - pathname: priv.pathname, - password: priv.password, - isTemplate: priv.isTemplate, - hashes: priv.hashes, + pathname: data.pathname || priv.pathname, + password: data.hashes ? '' : priv.password, + isTemplate: data.hashes ? false : priv.isTemplate, + hashes: data.hashes || priv.hashes, common: common, title: data.title, versionHash: data.versionHash, @@ -64,8 +64,8 @@ define([ hideIframe(); }, fileData: { - hash: priv.hashes.fileHash, - password: priv.password + hash: (data.hashes && data.hashes.fileHash) || priv.hashes.fileHash, + password: data.hashes ? '' : priv.password } }, function (e, modal) { if (e) { console.error(e); } diff --git a/www/settings/app-settings.less b/www/settings/app-settings.less index 1f0da1263..0ac3d10f2 100644 --- a/www/settings/app-settings.less +++ b/www/settings/app-settings.less @@ -74,6 +74,10 @@ margin-right: 100%; } } + & > .fa { + align-self: center; + margin-right: -16px; + } } .cp-settings-info-block { [type="text"] { diff --git a/www/settings/inner.js b/www/settings/inner.js index 8882f5861..9ff57aae7 100644 --- a/www/settings/inner.js +++ b/www/settings/inner.js @@ -51,7 +51,7 @@ define([ 'cp-settings-info-block', 'cp-settings-displayname', 'cp-settings-language-selector', - 'cp-settings-resettips', + 'cp-settings-mediatag-size', 'cp-settings-change-password', 'cp-settings-delete' ], @@ -62,6 +62,7 @@ define([ 'cp-settings-userfeedback', ], 'drive': [ + 'cp-settings-resettips', 'cp-settings-drive-duplicate', 'cp-settings-thumbnails', 'cp-settings-drive-backup', @@ -576,6 +577,59 @@ define([ cb(form); }, true); + Messages.settings_mediatagSizeTitle = "Autodownload size in MegaBytes (MB)"; // XXX + Messages.settings_mediatagSizeHint = 'Maximum size for automatically loading media elements (images, videos, pdf) embedded into the pads. Elements bigger than the specified size can be loaded manually. Use "-1" to always load the media elements automatically.'; // XXX + makeBlock('mediatag-size', function(cb) { + var $inputBlock = $('
', { + 'class': 'cp-sidebarlayout-input-block', + }); + + var spinner; + var $input = $('', { + 'min': -1, + 'max': 1000, + type: 'number', + }).appendTo($inputBlock); + + var oldVal; + + var todo = function () { + var val = parseInt($input.val()); + if (val === oldVal) { return; } + if (typeof(val) !== 'number') { return UI.warn(Messages.error); } + spinner.spin(); + common.setAttribute(['general', 'mediatag-size'], val, function (err) { + if (err) { + spinner.hide(); + console.error(err); + return UI.warn(Messages.error); + } + spinner.done(); + UI.log(Messages.saved); + }); + }; + var $save = $(h('button.btn.btn-primary', Messages.settings_save)).appendTo($inputBlock); + spinner = UI.makeSpinner($inputBlock); + + $save.click(todo); + $input.on('keyup', function(e) { + if (e.which === 13) { todo(); } + }); + + common.getAttribute(['general', 'mediatag-size'], function(e, val) { + if (e) { return void console.error(e); } + if (typeof(val) !== 'number') { + oldVal = 5; + $input.val(5); + } else { + oldVal = val; + $input.val(val); + } + }); + + cb($inputBlock); + }, true); + // Security makeBlock('safe-links', function(cb) { diff --git a/www/support/ui.js b/www/support/ui.js index 9b86d6f20..a58fdf170 100644 --- a/www/support/ui.js +++ b/www/support/ui.js @@ -397,6 +397,7 @@ define([ var fmConfig = { body: $('body'), + noStore: true, // Don't store attachments into our drive onUploaded: function (ev, data) { if (ev.callback) { ev.callback(data); diff --git a/www/whiteboard/inner.js b/www/whiteboard/inner.js index 44efd1421..bab1603dc 100644 --- a/www/whiteboard/inner.js +++ b/www/whiteboard/inner.js @@ -331,10 +331,11 @@ define([ APP.FM.handleFile(blob); }); }; + var MAX_IMAGE_SIZE = 1 * 1024 * 1024; // 1 MB + var maxSizeStr = Messages._getKey('formattedMB', [Util.bytesToMegabytes(MAX_IMAGE_SIZE)]); var addImageToCanvas = function (img) { - // 1 MB maximum - if (img.src && img.src.length > 1 * 1024 * 1024) { - UI.warn(Messages.upload_tooLargeBrief); + if (img.src && img.src.length > MAX_IMAGE_SIZE) { + UI.warn(Messages._getKey('upload_tooLargeBrief', [maxSizeStr])); // XXX update key return; } var w = img.width; @@ -356,8 +357,8 @@ define([ var file = e.target.files[0]; var reader = new FileReader(); // 1 MB maximum - if (file.size > 1 * 1024 * 1024) { - UI.warn(Messages.upload_tooLargeBrief); + if (file.size > MAX_IMAGE_SIZE) { + UI.warn(Messages._getKey('upload_tooLargeBrief', [maxSizeStr])); return; } reader.onload = function () {