diff --git a/addons/web_editor/i18n/web_editor.pot b/addons/web_editor/i18n/web_editor.pot index 5ba6e567caa..180e57d6ddf 100644 --- a/addons/web_editor/i18n/web_editor.pot +++ b/addons/web_editor/i18n/web_editor.pot @@ -1034,14 +1034,6 @@ msgid "" "prevent it from being updated during future App upgrades." msgstr "" -#. module: web_editor -#. odoo-javascript -#: code:addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js:0 -#: code:addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js:0 -#, python-format -msgid "Embed" -msgstr "" - #. module: web_editor #. odoo-javascript #: code:addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js:0 @@ -2036,14 +2028,6 @@ msgstr "" msgid "Paragraph block" msgstr "" -#. module: web_editor -#. odoo-javascript -#: code:addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js:0 -#: code:addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js:0 -#, python-format -msgid "Paste" -msgstr "" - #. module: web_editor #. odoo-javascript #: code:addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js:0 @@ -2051,13 +2035,6 @@ msgstr "" msgid "Paste as URL" msgstr "" -#. module: web_editor -#. odoo-javascript -#: code:addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js:0 -#, python-format -msgid "Paste as text" -msgstr "" - #. module: web_editor #: model_terms:ir.ui.view,arch_db:web_editor.snippet_options msgid "Patterns" @@ -2593,13 +2570,6 @@ msgstr "" msgid "Signature" msgstr "" -#. module: web_editor -#. odoo-javascript -#: code:addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js:0 -#, python-format -msgid "Simple text paste" -msgstr "" - #. module: web_editor #. odoo-javascript #: code:addons/web_editor/static/src/js/editor/snippets.options.js:0 diff --git a/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js b/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js index 2abf87ef69c..aa4505abe43 100644 --- a/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js +++ b/addons/web_editor/static/src/js/editor/odoo-editor/src/OdooEditor.js @@ -4308,135 +4308,116 @@ export class OdooEditor extends EventTarget { if(!text.match(/\${.*}/gi)) { splitAroundUrl = text.split(URL_REGEX); } - this.historyPauseSteps("_onPaste"); - for (let i = 0; i < splitAroundUrl.length; i++) { - const url = /^https?:\/\//gi.test(splitAroundUrl[i]) - ? splitAroundUrl[i] - : 'https://' + splitAroundUrl[i]; - const youtubeUrl = YOUTUBE_URL_GET_VIDEO_ID.exec(url); + if (splitAroundUrl.length === 3 && !splitAroundUrl[0] && !splitAroundUrl[2]) { + // Pasted content is a single URL. + const url = /^https?:\/\//i.test(text) ? text : 'https://' + text; + const youtubeUrl = this.options.allowCommandVideo &&YOUTUBE_URL_GET_VIDEO_ID.exec(url); const urlFileExtention = url.split('.').pop(); - const isImageUrl = ['jpg', 'jpeg', 'png', 'gif'].includes(urlFileExtention.toLowerCase()); - // Even indexes will always be plain text, and odd indexes will always be URL. - // only allow images emebed inside an existing link. No other url or video embed. - if (i % 2 && (isImageUrl || !selectionIsInsideALink)) { - const baseEmbedCommand = [ - { - category: this.options._t('Paste'), - name: this.options._t('Paste as URL'), - description: this.options._t('Create an URL'), - fontawesome: 'fa-link', - callback: () => { - this.historyUndo(); - this._applyRawCommand('insert', this._createLink(splitAroundUrl[i], url)); - }, - }, - { - category: this.options._t('Paste'), - name: this.options._t('Paste as text'), - description: this.options._t('Simple text paste'), - fontawesome: 'fa-font', - callback: () => {}, - }, - ]; - - const execCommandAtStepIndex = (index, callback) => { - this.historyRevertUntil(index); + const isImageUrl = ['jpg', 'jpeg', 'png', 'gif', 'svg'].includes(urlFileExtention.toLowerCase()); + // A url cannot be transformed inside an existing link. + // An image can be embedded inside an existing link, a video cannot. + if (selectionIsInsideALink) { + if (isImageUrl) { + const img = document.createElement('IMG'); + img.setAttribute('src', url); + this._applyCommand('insert', img); + } else { + this._applyCommand('insert', text); + } + } else if (isImageUrl || youtubeUrl) { + // Open powerbox with commands to embed media or paste as link. + // Insert URL as text, store history step index to revert it later. + const stepIndexBeforeInsert = this._historySteps.length - 1; + this._applyCommand('insert', text); + const revertTextInsertion = () => { + this.historyRevertUntil(stepIndexBeforeInsert); this.historyStep(true); this._historyStepsStates.set(peek(this._historySteps).id, 'consumed'); - - callback(); - - this.historyStep(true); }; - + let commands; + const pasteAsURLCommand = { + name: this.options._t('Paste as URL'), + description: this.options._t('Create an URL.'), + fontawesome: 'fa-link', + callback: () => { + revertTextInsertion(); + this._applyRawCommand('insert', this._createLink(text, url)) + }, + }; if (isImageUrl) { - const stepIndexBeforeInsert = this._historySteps.length - 1; - this.execCommand('insert', splitAroundUrl[i]); - this.powerbox.open([ - { - category: this.options._t('Embed'), - name: this.options._t('Embed Image'), - description: this.options._t('Embed the image in the document'), - fontawesome: 'fa-image', - callback: () => { - execCommandAtStepIndex(stepIndexBeforeInsert, () => { - const img = document.createElement('IMG'); - img.setAttribute('src', url); - const sel = this.document.getSelection(); - if (!sel.isCollapsed) { - this.deleteRange(sel); - } - if (sel.rangeCount) { - sel.getRangeAt(0).insertNode(img); - sel.collapseToEnd(); - } - }); - }, + const embedImageCommand = { + name: this.options._t('Embed Image'), + description: this.options._t('Embed the image in the document.'), + fontawesome: 'fa-image', + callback: () => { + revertTextInsertion(); + const img = document.createElement('IMG'); + img.setAttribute('src', url); + this._applyRawCommand('insert', img); }, - ...baseEmbedCommand, - ]); - } else if (this.options.allowCommandVideo && youtubeUrl) { - const stepIndexBeforeInsert = this._historySteps.length - 1; - this.execCommand('insert', splitAroundUrl[i]); - this.powerbox.open([ - { - category: this.options._t('Embed'), - name: this.options._t('Embed Youtube Video'), - description: this.options._t('Embed the youtube video in the document'), - fontawesome: 'fa-youtube-play', - callback: async () => { - let videoElement; - if (this.options.getYoutubeVideoElement) { - videoElement = await this.options.getYoutubeVideoElement(youtubeUrl[0]); - } else { - videoElement = document.createElement('iframe'); - videoElement.setAttribute('width', '560'); - videoElement.setAttribute('height', '315'); - videoElement.setAttribute( - 'src', - `https://www.youtube.com/embed/${youtubeUrl[1]}`, - ); - videoElement.setAttribute('title', 'YouTube video player'); - videoElement.setAttribute('frameborder', '0'); - videoElement.setAttribute( - 'allow', - 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture', - ); - videoElement.setAttribute('allowfullscreen', '1'); - } - - execCommandAtStepIndex(stepIndexBeforeInsert, () => { - - const sel = this.document.getSelection(); - if (!sel.isCollapsed) { - this.deleteRange(sel); - } - if (sel.rangeCount) { - sel.getRangeAt(0).insertNode(videoElement); - sel.collapseToEnd(); - } - }); - }, - }, - ...baseEmbedCommand, - ]); + }; + commands = [embedImageCommand, pasteAsURLCommand]; } else { - this._applyCommand('insert', this._createLink(splitAroundUrl[i], url)); + // URL is a YouTube video. + const embedVideoCommand = { + name: this.options._t('Embed Youtube Video'), + description: this.options._t('Embed the youtube video in the document.'), + fontawesome: 'fa-youtube-play', + callback: () => { + revertTextInsertion(); + let videoElement; + if (this.options.getYoutubeVideoElement) { + videoElement = this.options.getYoutubeVideoElement(youtubeUrl[0]); + } else { + videoElement = document.createElement('iframe'); + videoElement.setAttribute('width', '560'); + videoElement.setAttribute('height', '315'); + videoElement.setAttribute( + 'src', + `https://www.youtube.com/embed/${youtubeUrl[1]}`, + ); + videoElement.setAttribute('title', 'YouTube video player'); + videoElement.setAttribute('frameborder', '0'); + videoElement.setAttribute( + 'allow', + 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture', + ); + videoElement.setAttribute('allowfullscreen', '1'); + } + this._applyRawCommand('insert', videoElement); + }, + }; + commands = [embedVideoCommand, pasteAsURLCommand]; } - } else if (splitAroundUrl[i] !== '') { - const textFragments = splitAroundUrl[i].split(/\r?\n/); - let textIndex = 1; - for (const textFragment of textFragments) { - this._applyCommand('insert', textFragment); - if (textIndex < textFragments.length) { - this._applyCommand('oShiftEnter'); + this.powerbox.open(commands); + } else { + this._applyCommand('insert', this._createLink(text, url)); + } + } else { + this.historyPauseSteps(); + for (let i = 0; i < splitAroundUrl.length; i++) { + const url = /^https?:\/\//gi.test(splitAroundUrl[i]) + ? splitAroundUrl[i] + : 'https://' + splitAroundUrl[i]; + // Even indexes will always be plain text, and odd indexes will always be URL. + // only allow images emebed inside an existing link. No other url or video embed. + if (i % 2 && !selectionIsInsideALink) { + this._applyCommand('insert', this._createLink(splitAroundUrl[i], url)); + } else if (splitAroundUrl[i] !== '') { + const textFragments = splitAroundUrl[i].split(/\r?\n/); + let textIndex = 1; + for (const textFragment of textFragments) { + this._applyCommand('insert', textFragment); + if (textIndex < textFragments.length) { + this._applyCommand('oShiftEnter'); + } + textIndex++; } - textIndex++; } } + this.historyUnpauseSteps(); + this.historyStep(); } - this.historyUnpauseSteps("_onPaste"); - this.historyStep(); } } _onDragStart(ev) {