diff --git a/customize.dist/src/less2/include/contextmenu.less b/customize.dist/src/less2/include/contextmenu.less new file mode 100644 index 000000000..1a9049b54 --- /dev/null +++ b/customize.dist/src/less2/include/contextmenu.less @@ -0,0 +1,19 @@ +@import (reference) "./colortheme-all.less"; + +.contextmenu_main() { + --LessLoader_require: LessLoader_currentFile(); +}; +& { + .cp-contextmenu { + display: none; + position: absolute; + z-index: 50000; + li { + padding: 0; + font-size: @colortheme_app-font-size; + a { + cursor: pointer; + } + } + } +} diff --git a/customize.dist/src/less2/include/framework.less b/customize.dist/src/less2/include/framework.less index f46018b8c..4853f663b 100644 --- a/customize.dist/src/less2/include/framework.less +++ b/customize.dist/src/less2/include/framework.less @@ -3,6 +3,7 @@ @import (reference) './fileupload.less'; @import (reference) './alertify.less'; @import (reference) './corner.less'; +@import (reference) './contextmenu.less'; @import (reference) './tokenfield.less'; @import (reference) './creation.less'; @import (reference) './tippy.less'; @@ -29,6 +30,7 @@ ); .alertify_main(); .corner_main(); + .contextmenu_main(); .fileupload_main(); .tokenfield_main(); .tippy_main(); @@ -63,6 +65,7 @@ .fileupload_main(); .alertify_main(); .corner_main(); + .contextmenu_main(); .tippy_main(); .checkmark_main(20px); .password_main(); diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js index 367411e27..8510c06f3 100644 --- a/customize.dist/translations/messages.js +++ b/customize.dist/translations/messages.js @@ -252,6 +252,8 @@ define(function () { out.pad_mediatagRatio = "Keep ratio"; out.pad_mediatagBorder = "Border width (px)"; out.pad_mediatagPreview = "Preview"; + out.pad_mediatagImport = 'Save in CryptDrive'; + out.pad_mediatagOptions = 'Image properties'; // Kanban out.kanban_newBoard = "New board"; diff --git a/www/code/inner.js b/www/code/inner.js index 9b52f9806..3d6b16d37 100644 --- a/www/code/inner.js +++ b/www/code/inner.js @@ -110,7 +110,7 @@ define([ return; } $previewContainer.removeClass('cp-app-code-preview-isempty'); - DiffMd.apply(DiffMd.render(editor.getValue()), $preview); + DiffMd.apply(DiffMd.render(editor.getValue()), $preview, framework._.sfCommon); } catch (e) { console.error(e); } }; var drawPreview = Util.throttle(function () { diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index a47167e99..2d2d641cd 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2361,5 +2361,96 @@ define([ }; + var createContextMenu = function (menu) { + var $menu = $(menu).appendTo($('body')); + + var display = function (e) { + $menu.css({ display: "block" }); + var h = $menu.outerHeight(); + var w = $menu.outerWidth(); + var wH = window.innerHeight; + var wW = window.innerWidth; + if (h > wH) { + $menu.css({ + top: '0px', + bottom: '' + }); + } else if (e.pageY + h <= wH) { + $menu.css({ + top: e.pageY+'px', + bottom: '' + }); + } else { + $menu.css({ + bottom: '0px', + top: '' + }); + } + if(w > wW) { + $menu.css({ + left: '0px', + right: '' + }); + } else if (e.pageX + w <= wW) { + $menu.css({ + left: e.pageX+'px', + right: '' + }); + } else { + $menu.css({ + left: '', + right: '0px', + }); + } + }; + + var hide = function () { + $menu.hide(); + }; + var remove = function () { + $menu.remove(); + }; + + $('body').click(hide); + + return { + menu: menu, + show: display, + hide: hide, + remove: remove + }; + }; + + var mediatagContextMenu; + UIElements.importMediaTagMenu = function (common) { + if (mediatagContextMenu) { return mediatagContextMenu; } + + // Create context menu + var menu = h('div.cp-contextmenu.dropdown.cp-unselectable', [ + h('ul.dropdown-menu', { + 'role': 'menu', + 'aria-labelledBy': 'dropdownMenu', + 'style': 'display:block;position:static;margin-bottom:5px;' + }, [ + h('li', h('a.dropdown-item', { + 'tabindex': '-1', + }, Messages.pad_mediatagImport)) + ]) + ]); + var m = createContextMenu(menu); + + mediatagContextMenu = m; + + var $menu = $(m.menu); + $menu.on('click', 'a', function (e) { + e.stopPropagation(); + m.hide(); + var $mt = $menu.data('mediatag'); + common.importMediaTag($mt); + }); + + return m; + }; + return UIElements; }); diff --git a/www/common/diffMarked.js b/www/common/diffMarked.js index fca3023b4..c224b4072 100644 --- a/www/common/diffMarked.js +++ b/www/common/diffMarked.js @@ -166,7 +166,8 @@ define([ return patch; }; - DiffMd.apply = function (newHtml, $content) { + DiffMd.apply = function (newHtml, $content, common) { + var contextMenu = common.importMediaTagMenu(); var id = $content.attr('id'); if (!id) { throw new Error("The element must have a valid id"); } var pattern = /()<\/media-tag>/g; @@ -192,6 +193,11 @@ define([ DD.apply($content[0], patch); var $mts = $content.find('media-tag:not(:has(*))'); $mts.each(function (i, el) { + $(el).contextmenu(function (e) { + e.preventDefault(); + $(contextMenu.menu).data('mediatag', $(el)); + contextMenu.show(e); + }); MediaTag(el); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { diff --git a/www/common/media-tag.js b/www/common/media-tag.js index 5b911f2b8..c820d9201 100644 --- a/www/common/media-tag.js +++ b/www/common/media-tag.js @@ -390,6 +390,7 @@ var end = function (decrypted) { process(mediaObject, decrypted, cfg, function (err) { if (err) { return void emit('error', err); } + mediaObject._blob = decrypted; emit('complete', decrypted); }); }; diff --git a/www/common/outer/sharedworker.js b/www/common/outer/sharedworker.js index 3d946070d..8f59e603e 100644 --- a/www/common/outer/sharedworker.js +++ b/www/common/outer/sharedworker.js @@ -18,6 +18,9 @@ var debug = function (msg) { console.log(msg); }; var init = function (client, cb) { debug('SharedW INIT'); + require.config({ + waitSeconds: 600 + }); require(['/api/config?cb=' + (+new Date()).toString(16)], function (ApiConfig) { if (ApiConfig.requireConf) { require.config(ApiConfig.requireConf); } diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index 290e00482..43728c55c 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -379,6 +379,29 @@ define([ }); }); + sframeChan.on('Q_IMPORT_MEDIATAG', function (obj, cb) { + var key = obj.key; + var channel = obj.channel; + var hash = Utils.Hash.getFileHashFromKeys({ + version: 1, + channel: channel, + keys: { + fileKeyStr: key + } + }); + var href = '/file/#' + hash; + var data = { + title: obj.name, + href: href, + channel: channel, + owners: obj.owners, + forceSave: true, + }; + Cryptpad.setPadTitle(data, function (err) { + Cryptpad.setPadAttribute('fileType', obj.type, null, href); + cb(err); + }); + }); sframeChan.on('Q_SETTINGS_SET_DISPLAY_NAME', function (newName, cb) { Cryptpad.setDisplayName(newName, function (err) { diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index e3cce0f28..a68a011fb 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -94,6 +94,7 @@ define([ funcs.getPadCreationScreen = callWithCommon(UIElements.getPadCreationScreen); funcs.createNewPadModal = callWithCommon(UIElements.createNewPadModal); funcs.onServerError = callWithCommon(UIElements.onServerError); + funcs.importMediaTagMenu = callWithCommon(UIElements.importMediaTagMenu); // Thumb funcs.displayThumbnail = callWithCommon(Thumb.displayThumbnail); @@ -130,6 +131,24 @@ define([ } return; }; + funcs.importMediaTag = function ($mt) { + if (!$mt || !$mt.is('media-tag')) { return; } + var chanStr = $mt.attr('src'); + var keyStr = $mt.attr('data-crypto-key'); + var channel = chanStr.replace(/\/blob\/[0-9a-f]{2}\//i, ''); + var key = keyStr.replace(/cryptpad:/i, ''); + var metadata = $mt[0]._mediaObject._blob.metadata; + ctx.sframeChan.query('Q_IMPORT_MEDIATAG', { + channel: channel, + key: key, + name: metadata.name, + type: metadata.type, + owners: metadata.owners + }, function () { + UI.log(Messages.saved); + }); + }; + funcs.getFileSize = function (channelId, cb) { funcs.sendAnonRpcMsg("GET_FILE_SIZE", channelId, function (data) { if (!data) { return void cb("No response"); } diff --git a/www/common/sframe-protocol.js b/www/common/sframe-protocol.js index 6ceb5aeb2..02390b290 100644 --- a/www/common/sframe-protocol.js +++ b/www/common/sframe-protocol.js @@ -261,4 +261,7 @@ define({ 'EV_AUTOSTORE_DISPLAY_POPUP': true, 'Q_AUTOSTORE_STORE': true, 'Q_IS_PAD_STORED': true, + + // Import mediatag from a pad + 'Q_IMPORT_MEDIATAG': true }); diff --git a/www/drive/app-drive.less b/www/drive/app-drive.less index 009704758..37f79f193 100644 --- a/www/drive/app-drive.less +++ b/www/drive/app-drive.less @@ -148,19 +148,6 @@ user-select: none; } - .cp-app-drive-context { - display: none; - position: absolute; - z-index: 500; - li { - padding: 0; - font-size: @colortheme_app-font-size; - a { - cursor: pointer; - } - } - } - .cp-app-drive-element-droppable { background-color: #FE9A2E; color: #222; diff --git a/www/drive/inner.html b/www/drive/inner.html index 463619753..8328ef14b 100644 --- a/www/drive/inner.html +++ b/www/drive/inner.html @@ -6,7 +6,7 @@ diff --git a/www/drive/inner.js b/www/drive/inner.js index 1a603cd53..9fd9f82e6 100644 --- a/www/drive/inner.js +++ b/www/drive/inner.js @@ -244,7 +244,7 @@ define([ }; var createContextMenu = function () { - var menu = h('div.cp-app-drive-context.dropdown.cp-unselectable', [ + var menu = h('div.cp-contextmenu.dropdown.cp-unselectable', [ h('ul.dropdown-menu', { 'role': 'menu', 'aria-labelledby': 'dropdownMenu', @@ -2594,12 +2594,12 @@ define([ $li = findDataHolder($tree.find('.cp-app-drive-element-active')); } // Close if already opened - if ($('.cp-app-drive-context:visible').length) { + if ($('.cp-contextmenu:visible').length) { APP.hideMenu(); return; } // Open the menu - $('.cp-app-drive-context').css({ + $('.cp-contextmenu').css({ top: ($context.offset().top + 32) + 'px', right: '0px', left: '' diff --git a/www/pad/app-pad.less b/www/pad/app-pad.less index 1bc4db423..43109f3d3 100644 --- a/www/pad/app-pad.less +++ b/www/pad/app-pad.less @@ -43,6 +43,12 @@ body.cp-app-pad { } } + .cke_dialog { + display: block; + overflow-x: auto; + max-height: 100vh; + } + .cke_wysiwyg_frame { min-width: 60%; } @@ -55,4 +61,4 @@ body.cp-app-pad { display:none; } } -} \ No newline at end of file +} diff --git a/www/pad/inner.js b/www/pad/inner.js index 2356475d6..a97406d70 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -777,8 +777,18 @@ define([ 'max-width: 50em; padding: 20px 30px; margin: 0 auto; min-height: 100%;'+ 'box-sizing: border-box; overflow: auto;'+ '}' + - '.cke_body_width body > *:first-child { margin-top: 0; }'; + '.cke_body_width body > *:first-child { margin-top: 0; }' + Ckeditor.addCss(newCss); + Ckeditor._mediatagTranslations = { + title: Messages.pad_mediatagTitle, + width: Messages.pad_mediatagWidth, + height: Messages.pad_mediatagHeight, + ratio: Messages.pad_mediatagRatio, + border: Messages.pad_mediatagBorder, + preview: Messages.pad_mediatagPreview, + 'import': Messages.pad_mediatagImport, + options: Messages.pad_mediatagOptions + }; Ckeditor.plugins.addExternal('mediatag','/pad/', 'mediatag-plugin.js'); Ckeditor.plugins.addExternal('blockbase64','/pad/', 'disable-base64.js'); module.ckeditor = editor = Ckeditor.replace('editor1', { @@ -786,13 +796,8 @@ define([ }); editor.on('instanceReady', waitFor()); }).nThen(function () { - editor.plugins.mediatag.translations = { - title: Messages.pad_mediatagTitle, - width: Messages.pad_mediatagWidth, - height: Messages.pad_mediatagHeight, - ratio: Messages.pad_mediatagRatio, - border: Messages.pad_mediatagBorder, - preview: Messages.pad_mediatagPreview, + editor.plugins.mediatag.import = function ($mt) { + framework._.sfCommon.importMediaTag($mt); }; Links.addSupportForOpeningLinksInNewTab(Ckeditor)({editor: editor}); }).nThen(function () { diff --git a/www/pad/mediatag-plugin-dialog.js b/www/pad/mediatag-plugin-dialog.js index 03dca1229..11ee8daff 100644 --- a/www/pad/mediatag-plugin-dialog.js +++ b/www/pad/mediatag-plugin-dialog.js @@ -1,5 +1,5 @@ CKEDITOR.dialog.add('mediatag', function (editor) { - var Messages = editor.plugins.mediatag.translations; + var Messages = CKEDITOR._mediatagTranslations; return { title: Messages.title, minWidth: 400, @@ -51,6 +51,8 @@ CKEDITOR.dialog.add('mediatag', function (editor) { }, ], onShow: function () { + + var thiss = this; var sel = editor.getSelection(); element = sel.getSelectedElement(); if (!element) { return; } @@ -82,6 +84,11 @@ CKEDITOR.dialog.add('mediatag', function (editor) { }); $preview.html('').append($clone); + var center = function () { + var top = Math.max(($(document).height()/2) - (thiss.getSize().height/2), 0); + thiss.move(thiss.getPosition().x, top); + }; + var update = function () { var w = $(wInput).val() || Math.round(rect.width); var h = $(hInput).val() || Math.round(rect.height); @@ -91,6 +98,7 @@ CKEDITOR.dialog.add('mediatag', function (editor) { height: h+'px', 'border-width': b+'px' }); + center(); }; $(wInput).on('keyup', function () { @@ -116,6 +124,8 @@ CKEDITOR.dialog.add('mediatag', function (editor) { $(borderInput).on('keyup', function () { update(); }); + + setTimeout(center); }, onOk: function() { var dialog = this; diff --git a/www/pad/mediatag-plugin.js b/www/pad/mediatag-plugin.js index c989ee725..46747b18a 100644 --- a/www/pad/mediatag-plugin.js +++ b/www/pad/mediatag-plugin.js @@ -28,6 +28,8 @@ }, init: function( editor ) { var pluginName = 'mediatag'; + var Messages = CKEDITOR._mediatagTranslations; + var targetWidget; // Register the dialog. CKEDITOR.dialog.add( pluginName, this.path + 'mediatag-plugin-dialog.js' ); @@ -42,6 +44,44 @@ } }); + + editor.addCommand('importMediatag', { + exec: function (editor) { + var w = targetWidget; + targetWidget = undefined; + var $mt = $(w.$).find('media-tag'); + editor.plugins.mediatag.import($mt); + } + }); + + if (editor.addMenuItems) { + editor.addMenuGroup('mediatag'); + editor.addMenuItem('importMediatag', { + label: Messages.import, + icon: 'save', + command: 'importMediatag', + group: 'mediatag' + }); + editor.addMenuItem('mediatag', { + label: Messages.options, + icon: 'image', + command: 'mediatag', + group: 'mediatag' + }); + } + if (editor.contextMenu) { + editor.contextMenu.addListener(function (element) { + if (element.is('.cke_widget_mediatag') + || element.getAttribute('data-cke-display-name') === 'media-tag') { + targetWidget = element; + return { + mediatag: CKEDITOR.TRISTATE_OFF, + importMediatag: CKEDITOR.TRISTATE_OFF, + }; + } + }); + } + }, } ); diff --git a/www/poll/inner.js b/www/poll/inner.js index 7a287b7db..08793c63c 100644 --- a/www/poll/inner.js +++ b/www/poll/inner.js @@ -645,7 +645,7 @@ define([ var updatePublishedDescription = function () { var v = APP.editor.getValue(); - DiffMd.apply(DiffMd.render(v || ''), APP.$descriptionPublished); + DiffMd.apply(DiffMd.render(v || ''), APP.$descriptionPublished, common); }; var updateDescription = function (old, n) { var o = APP.editor.getValue(); diff --git a/www/slide/inner.js b/www/slide/inner.js index 89ec0dafa..c06010b6e 100644 --- a/www/slide/inner.js +++ b/www/slide/inner.js @@ -9,7 +9,6 @@ define([ '/common/common-util.js', '/common/common-hash.js', '/common/common-interface.js', - '/common/diffMarked.js', '/customize/messages.js', 'cm/lib/codemirror', @@ -54,7 +53,6 @@ define([ Util, Hash, UI, - DiffMd, Messages, CMeditor) { diff --git a/www/slide/slide.js b/www/slide/slide.js index 17ad19c0c..88ef757ac 100644 --- a/www/slide/slide.js +++ b/www/slide/slide.js @@ -95,7 +95,7 @@ define([ } var m = '' + mediatagBg + ''+DiffMd.render(c).replace(separatorReg, '' + mediatagBg + '')+''; - try { DiffMd.apply(m, $content); } catch (e) { return console.error(e); } + try { DiffMd.apply(m, $content, Common); } catch (e) { return console.error(e); } var length = getNumberOfSlides(); $modal.find('style.cp-app-slide-style').remove();