diff --git a/customize.dist/ckeditor-contents.css b/customize.dist/ckeditor-contents.css index a7939839d..663cd8cb9 100644 --- a/customize.dist/ckeditor-contents.css +++ b/customize.dist/ckeditor-contents.css @@ -232,14 +232,35 @@ media-tag button.btn { transition: none; color: #3F4141; border: 1px solid #3F4141; + max-width: 250px; } +media-tag button.mediatag-download-btn { + flex-flow: column; + min-height: 38px; + justify-content: center; +} +media-tag button.mediatag-download-btn > span { + display: flex; + line-height: 1.5; + align-items: center; + justify-content: center; +} +media-tag button.mediatag-download-btn * { + width: auto; +} +media-tag button.mediatag-download-btn > span.mediatag-download-name b { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + media-tag button.btn:hover, media-tag button.btn:active, media-tag button.btn:focus { background-color: #ccc; } -media-tag button b { +media-tag button.btn b { margin-left: 5px; } -media-tag button .fa { +media-tag button.btn .fa { display: inline; margin-right: 5px; } diff --git a/customize.dist/src/less2/include/markdown.less b/customize.dist/src/less2/include/markdown.less index d7fe13f43..af3ac74d8 100644 --- a/customize.dist/src/less2/include/markdown.less +++ b/customize.dist/src/less2/include/markdown.less @@ -94,8 +94,24 @@ height: 80vh; max-height: 90vh; } + button.mediatag-download-btn { + flex-flow: column; + & > span { + display: flex; + line-height: 1.5; + align-items: center; + &.mediatag-download-name b { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + } button.btn-default { display: inline-flex; + max-width: 250px; + min-height: 38px; + justify-content: center; .fa { margin-right: 5px; } diff --git a/www/common/inner/common-mediatag.js b/www/common/inner/common-mediatag.js index 72cb1e37b..eaf640b0d 100644 --- a/www/common/inner/common-mediatag.js +++ b/www/common/inner/common-mediatag.js @@ -23,9 +23,10 @@ define([ viewer: '/common/pdfjs/web/viewer.html' }); Messages.mediatag_saveButton = "Save"; // XXX + Messages.mediatag_loadButton = "Load attachment"; // XXX MediaTag.setDefaultConfig('download', { text: Messages.mediatag_saveButton, - textDl: Messages.download_mt_button, + textDl: Messages.mediatag_loadButton, }); } MT.MediaTag = MediaTag; diff --git a/www/common/media-tag.js b/www/common/media-tag.js index 8f7276446..446dfdf08 100644 --- a/www/common/media-tag.js +++ b/www/common/media-tag.js @@ -181,14 +181,17 @@ var factory = function () { mediaObject.tag.appendChild(text); }; var makeDownloadButton = function (cfg, mediaObject, size, cb) { + var metadata = cfg.metadata || {}; + var i = ''; + var name = metadata.name ? ''+ i +''+ + fixHTML(metadata.name)+'' : ''; var btn = document.createElement('button'); - btn.setAttribute('class', 'btn btn-default'); - btn.setAttribute('data-dl', '1'); - btn.innerHTML = '' + - cfg.download.textDl + ' (' + size + 'MB)'; + btn.setAttribute('class', 'btn btn-default mediatag-download-btn'); + btn.innerHTML = name + '' + (name ? '' : i) + + cfg.download.textDl + ' (' + size + 'MB)'; btn.addEventListener('click', function () { makeProgressBar(cfg, mediaObject); - var a = (cfg.body || document).querySelectorAll('media-tag[src="'+mediaObject.tag.getAttribute('src')+'"] button[data-dl]'); + var a = (cfg.body || document).querySelectorAll('media-tag[src="'+mediaObject.tag.getAttribute('src')+'"] button.mediatag-download-btn'); for(var i = 0; i < a.length; i++) { if (a[i] !== btn) { a[i].click(); } } @@ -346,6 +349,95 @@ var factory = function () { } }; + // The metadata size can go up to 65535 (16 bits - 2 bytes) + // The first 8 bits are stored in A[0] + // The last 8 bits are stored in A[0] + var uint8ArrayJoin = function (AA) { + var l = 0; + var i = 0; + for (; i < AA.length; i++) { l += AA[i].length; } + var C = new Uint8Array(l); + + i = 0; + for (var offset = 0; i < AA.length; i++) { + C.set(AA[i], offset); + offset += AA[i].length; + } + return C; + }; + var fetchMetadata = function (src, _cb) { + var cb = function (e, res) { + _cb(e, res); + cb = function () {}; + }; + + var cacheKey = getCacheKey(src); + + var fetch = function () { + var xhr = new XMLHttpRequest(); + xhr.open('GET', src, true); + xhr.setRequestHeader('Range', 'bytes=0-1'); + xhr.responseType = 'arraybuffer'; + + xhr.onerror = function () { return void cb("XHR_ERROR"); }; + xhr.onload = function () { + // Error? + if (/^4/.test('' + this.status)) { return void cb("XHR_ERROR " + this.status); } + var res = new Uint8Array(xhr.response); + var size = Decrypt.decodePrefix(res); + var xhr2 = new XMLHttpRequest(); + + xhr2.open("GET", src, true); + xhr2.setRequestHeader('Range', 'bytes=2-' + (size + 2)); + xhr2.responseType = 'arraybuffer'; + xhr2.onload = function () { + if (/^4/.test('' + this.status)) { return void cb("XHR_ERROR " + this.status); } + var res2 = new Uint8Array(xhr2.response); + var all = uint8ArrayJoin([res, res2]); + cb(void 0, all); + }; + xhr2.send(null); + }; + + xhr.send(null); + }; + + if (!cacheKey) { return void fetch(); } + + getBlobCache(cacheKey, function (err, u8) { + if (err || !u8) { return void fetch(); } + + var size = Decrypt.decodePrefix(u8.subarray(0,2)); + console.error(size); + + cb(null, u8.subarray(0, size+2)); + }); + }; + var decryptMetadata = function (u8, key) { + var prefix = u8.subarray(0, 2); + var metadataLength = Decrypt.decodePrefix(prefix); + + var metaBox = new Uint8Array(u8.subarray(2, 2 + metadataLength)); + var metaChunk = window.nacl.secretbox.open(metaBox, Decrypt.createNonce(), key); + + try { + return JSON.parse(window.nacl.util.encodeUTF8(metaChunk)); + } + catch (e) { return null; } + }; + var fetchDecryptedMetadata = function (src, strKey, cb) { + if (typeof(src) !== 'string') { + return window.setTimeout(function () { + cb('NO_SOURCE'); + }); + } + fetchMetadata(src, function (e, buffer) { + if (e) { return cb(e); } + var key = Decrypt.getKeyFromStr(strKey); + cb(void 0, decryptMetadata(buffer, key)); + }); + }; + // Decrypts a Uint8Array with the given key. var decrypt = function (u8, strKey, done, progressCb) { var Nacl = window.nacl; @@ -608,6 +700,7 @@ var factory = function () { if (errDecryption) { return void reject(errDecryption); } + // XXX emit 'metadata' u8Decrypted.metadata // Cache and display the decrypted blob resolve(u8Decrypted); }, function (progress) { @@ -654,7 +747,12 @@ var factory = function () { return void dl(); } var sizeMb = Math.round(10 * size / 1024 / 1024) / 10; - makeDownloadButton(cfg, mediaObject, sizeMb, dl); + fetchDecryptedMetadata(src, strKey, function (err, md) { + if (err) { return void error(err); } + cfg.metadata = md; + // XXX emit 'metadata' + makeDownloadButton(cfg, mediaObject, sizeMb, dl); + }); }); return mediaObject;