diff options
| author | Christophe Matthieu <chm@odoo.com> | 2019-01-28 09:39:56 +0000 |
|---|---|---|
| committer | Christophe Matthieu <chm@odoo.com> | 2019-02-14 15:11:19 +0000 |
| commit | b49745e52d7a7bc27afd416206dcd5fa242aa07a (patch) | |
| tree | ae6a047da7e77b951db241e1342278ce543972e2 | |
| parent | 7daa85dd12ff522be510bc2f8db1d968cae7d891 (diff) | |
[IMP] web_editor: lazy load the wysiwyg
Issue: wysiwyg asset slow down the loading of the website, error
inadvertently introduced: https://github.com/odoo/odoo/pull/29775
The assets are now loaded assynchroneously, when the editor is needed,
its assets will be loaded.
closes odoo/odoo#30700
32 files changed, 960 insertions, 807 deletions
diff --git a/addons/mass_mailing/static/src/js/mass_mailing_widget.js b/addons/mass_mailing/static/src/js/mass_mailing_widget.js index 12eec137545..cf97d3fd9a0 100644 --- a/addons/mass_mailing/static/src/js/mass_mailing_widget.js +++ b/addons/mass_mailing/static/src/js/mass_mailing_widget.js @@ -12,6 +12,9 @@ var _t = core._t; var MassMailingFieldHtml = FieldHtml.extend({ xmlDependencies: (FieldHtml.prototype.xmlDependencies || []).concat(["/mass_mailing/static/src/xml/mass_mailing.xml"]), + jsLibs: [ + '/mass_mailing/static/src/js/mass_mailing_snippets.js', + ], custom_events: _.extend({}, FieldHtml.prototype.custom_events, { snippets_loaded: '_onSnippetsLoaded', @@ -305,7 +308,7 @@ var MassMailingFieldHtml = FieldHtml.extend({ this.$content.focusIn(); } } - this.wysiwyg.snippets.trigger('reload_snippet_dropzones'); + this.wysiwyg.trigger('reload_snippet_dropzones'); }, //-------------------------------------------------------------------------- @@ -442,7 +445,7 @@ var MassMailingFieldHtml = FieldHtml.extend({ selectedTheme = themeParams; // Notify form view - self.wysiwyg._onChange(); + self.wysiwyg.getEditable().trigger('change'); $dropdown.find('.dropdown-menu').removeClass('show'); $dropdown.find('.dropdown-item.selected').removeClass('selected'); $dropdown.find('.dropdown-item:eq(' + themesParams.indexOf(selectedTheme) + ')').addClass('selected'); diff --git a/addons/mass_mailing/static/tests/mass_mailing_html_tests.js b/addons/mass_mailing/static/tests/mass_mailing_html_tests.js index 36bea2db624..0657278ec16 100644 --- a/addons/mass_mailing/static/tests/mass_mailing_html_tests.js +++ b/addons/mass_mailing/static/tests/mass_mailing_html_tests.js @@ -46,7 +46,7 @@ QUnit.module('field html', { } if (xmlId === 'template.assets_all_style') { return $.when({ - cssLibs: $('head link[href]:not([type="image/x-icon"])').map(function () { + cssLibs: $('link[href]:not([type="image/x-icon"])').map(function () { return $(this).attr('href'); }).get(), cssContents: ['.field_body {background-color: red;}'] diff --git a/addons/mass_mailing/views/editor_field_html.xml b/addons/mass_mailing/views/editor_field_html.xml index 25f2be6fe23..620ccc78c44 100644 --- a/addons/mass_mailing/views/editor_field_html.xml +++ b/addons/mass_mailing/views/editor_field_html.xml @@ -7,15 +7,17 @@ </template> <template id="assets_mail_themes_edition"> <!-- maybe to remove and convert into a field dumy with attr invisible if the template is not selected --> - <t t-call="web._assets_helpers"/> - <link rel="stylesheet" type="text/scss" href="/web/static/src/scss/webclient.scss"/> - <link rel="stylesheet" type="text/scss" href="/web_editor/static/src/scss/wysiwyg_variables.scss"/> + <t t-call="web._assets_helpers"> + <link rel="stylesheet" type="text/scss" href="/web_editor/static/src/scss/wysiwyg_variables.scss"/> + </t> <link rel="stylesheet" type="text/scss" href="/mass_mailing/static/src/scss/mass_mailing.ui.scss"/> + <link rel="stylesheet" type="text/scss" href="/web/static/src/scss/webclient.scss"/> </template> <template id="iframe_css_assets_edit"> <t t-call-assets="web.assets_common" t-js="false"/> <t t-call-assets="web.assets_frontend" t-js="false"/> + <t t-call-assets="web_editor.assets_wysiwyg" t-js="false"/> <t t-call-assets="mass_mailing.assets_mail_themes" t-js="false"/> <t t-call-assets="mass_mailing.assets_mail_themes_edition" t-js="false"/> </template> @@ -26,6 +28,14 @@ <template id="qunit_suite" inherit_id="web.qunit_suite"> <xpath expr="." position="inside"> + <script type="text/javascript"> + odoo.define('mass_mailing.FieldHtml.test', function (require) { + 'use strict'; + var MassMailingFieldHtml = require('mass_mailing.FieldHtml'); + MassMailingFieldHtml.include({jsLibs: []}); + }); + </script> + <script type="text/javascript" src="/mass_mailing/static/src/js/mass_mailing_snippets.js"/> <script type="text/javascript" src="/mass_mailing/static/tests/mass_mailing_html_tests.js"/> </xpath> </template> diff --git a/addons/mass_mailing/views/mass_mailing_template.xml b/addons/mass_mailing/views/mass_mailing_template.xml index 359391e95c5..64bfb918d8a 100644 --- a/addons/mass_mailing/views/mass_mailing_template.xml +++ b/addons/mass_mailing/views/mass_mailing_template.xml @@ -7,7 +7,6 @@ <script type="text/javascript" src="/mass_mailing/static/src/js/mass_mailing.js"></script> <script type="text/javascript" src="/mass_mailing/static/src/js/mass_mailing_widget.js"></script> - <script type="text/javascript" src="/mass_mailing/static/src/js/mass_mailing_snippets.js"></script> </xpath> <xpath expr="//script[last()]" position="after"> <script type="text/javascript" src="/mass_mailing/static/src/js/mass_mailing_campaign_kanban_record.js"></script> diff --git a/addons/web/static/src/js/core/widget.js b/addons/web/static/src/js/core/widget.js index b25cd99587b..d3b9cc1033c 100644 --- a/addons/web/static/src/js/core/widget.js +++ b/addons/web/static/src/js/core/widget.js @@ -84,6 +84,32 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, { * @type {null|string[]} */ xmlDependencies: null, + /** + * List of paths to css files that need to be loaded before the widget can + * be rendered. This will not induce loading anything that has already been + * loaded. + * + * @type {null|string[]} + */ + cssLibs: null, + /** + * List of paths to js files that need to be loaded before the widget can + * be rendered. This will not induce loading anything that has already been + * loaded. + * + * @type {null|string[]} + */ + jsLibs: null, + /** + * List of xmlID that need to be loaded before the widget can be rendered. + * The content css (link file or style tag) and js (file or inline) of the + * assets are loaded. + * This will not induce loading anything that has already been + * loaded. + * + * @type {null|string[]} + */ + assetLibs: null, /** * Constructs the widget and sets its parent if a parent is given. @@ -115,13 +141,16 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, { * @returns {Deferred} */ willStart: function () { + var defs = []; if (this.xmlDependencies) { - var defs = _.map(this.xmlDependencies, function (xmlPath) { + defs.push.apply(defs, _.map(this.xmlDependencies, function (xmlPath) { return ajax.loadXML(xmlPath, core.qweb); - }); - return $.when.apply($, defs); + })); } - return $.when(); + if (this.jsLibs || this.cssLibs || this.assetLibs) { + defs.push(ajax.loadLibs(this)); + } + return $.when.apply($, defs); }, /** * Method called after rendering. Mostly used to bind actions, perform diff --git a/addons/web/static/src/js/fields/abstract_field.js b/addons/web/static/src/js/fields/abstract_field.js index 37d2f22ef55..edc7c03ac02 100644 --- a/addons/web/static/src/js/fields/abstract_field.js +++ b/addons/web/static/src/js/fields/abstract_field.js @@ -35,8 +35,6 @@ var field_utils = require('web.field_utils'); var Widget = require('web.Widget'); var AbstractField = Widget.extend({ - cssLibs: [], - jsLibs: [], events: { 'keydown': '_onKeydown', }, @@ -183,14 +181,6 @@ var AbstractField = Widget.extend({ } }, /** - * Loads the libraries listed in this.jsLibs and this.cssLibs - * - * @override - */ - willStart: function () { - return $.when(ajax.loadLibs(this), this._super.apply(this, arguments)); - }, - /** * When a field widget is appended to the DOM, its start method is called, * and will automatically call render. Most widgets should not override this. * diff --git a/addons/web_editor/static/src/js/backend/convert_inline.js b/addons/web_editor/static/src/js/backend/convert_inline.js index 3b09bef5f31..b6b36a388ef 100644 --- a/addons/web_editor/static/src/js/backend/convert_inline.js +++ b/addons/web_editor/static/src/js/backend/convert_inline.js @@ -1,7 +1,6 @@ odoo.define('web_editor.convertInline', function (require) { 'use strict'; -var fonts = require('wysiwyg.fonts'); var FieldHtml = require('web_editor.field.html'); /** @@ -189,6 +188,8 @@ function getMatchedCSSRules(a) { * converted to images */ function fontToImg($editable) { + var fonts = odoo.__DEBUG__.services["wysiwyg.fonts"]; + $editable.find('.fa').each(function () { var $font = $(this); var icon, content; diff --git a/addons/web_editor/static/src/js/backend/field_html.js b/addons/web_editor/static/src/js/backend/field_html.js index 69e32fb815e..b78fcc1d35f 100644 --- a/addons/web_editor/static/src/js/backend/field_html.js +++ b/addons/web_editor/static/src/js/backend/field_html.js @@ -4,12 +4,12 @@ odoo.define('web_editor.field.html', function (require) { var ajax = require('web.ajax'); var basic_fields = require('web.basic_fields'); var core = require('web.core'); -var Wysiwyg = require('web_editor.wysiwyg'); +var Wysiwyg = require('web_editor.wysiwyg.root'); var field_registry = require('web.field_registry'); var TranslatableFieldMixin = basic_fields.TranslatableFieldMixin; - var QWeb = core.qweb; +var assetsLoaded = false; /** * FieldHtml Widget @@ -40,8 +40,23 @@ var FieldHtml = basic_fields.DebouncedField.extend(TranslatableFieldMixin, { */ willStart: function () { this._onUpdateIframeId = 'onLoad_' + _.uniqueId('FieldHtml'); - var defAsset = this.nodeOptions.cssReadonly && ajax.loadAsset(this.nodeOptions.cssReadonly); - return $.when(this._super().then(Wysiwyg.prepare.bind(Wysiwyg, this)), defAsset); + var defAsset = null; + if (this.nodeOptions.cssReadonly) { + defAsset = ajax.loadAsset(this.nodeOptions.cssReadonly); + } + + if (!assetsLoaded) { // avoid flickering when begin to edit + assetsLoaded = $.Deferred(); + var wysiwyg = new Wysiwyg(this, {}); + wysiwyg.attachTo($('<textarea>')).then(function () { + wysiwyg.destroy(); + var def = assetsLoaded; + assetsLoaded = true; + def.resolve(); + }); + } + + return $.when(this._super(), assetsLoaded, defAsset); }, /** * @override @@ -147,7 +162,7 @@ var FieldHtml = basic_fields.DebouncedField.extend(TranslatableFieldMixin, { // by default this is synchronous because the assets are already loaded in willStart // but it can be async in the case of options such as iframe, snippets... return this.wysiwyg.attachTo(this.$target).then(function () { - self.$content = self.wysiwyg.$el; + self.$content = self.wysiwyg.$editor; self._onLoadWysiwyg(); }); }, @@ -444,7 +459,7 @@ var FieldHtml = basic_fields.DebouncedField.extend(TranslatableFieldMixin, { position: 'absolute', right: '+5px', }); - var $toolbar = this.$content.closest('.note-editor').find('.note-toolbar'); + var $toolbar = this.$content.find('.note-toolbar'); $toolbar.css('position', 'relative'); $toolbar.append($button); }, diff --git a/addons/web_editor/static/src/js/common/ace.js b/addons/web_editor/static/src/js/common/ace.js index f242129c4a8..2f9108b4d0d 100644 --- a/addons/web_editor/static/src/js/common/ace.js +++ b/addons/web_editor/static/src/js/common/ace.js @@ -191,7 +191,6 @@ var ViewEditor = Widget.extend({ willStart: function () { return $.when( this._super.apply(this, arguments), - ajax.loadLibs(this), this._loadResources() ); }, diff --git a/addons/web_editor/static/src/js/wysiwyg/plugin/font.js b/addons/web_editor/static/src/js/wysiwyg/plugin/font.js index c52712d7a02..cd4d80a9a45 100644 --- a/addons/web_editor/static/src/js/wysiwyg/plugin/font.js +++ b/addons/web_editor/static/src/js/wysiwyg/plugin/font.js @@ -534,6 +534,11 @@ registry.addJob(function (wysiwyg) { if ('web_editor.colorpicker' in QWeb.templates) { return; } + + if (wysiwyg.isDestroyed()) { + throw new Error('The Wysiwyg are destroyed before this loading'); + } + var options = {}; wysiwyg.trigger_up('getRecordInfo', { recordInfo: options, diff --git a/addons/web_editor/static/src/js/wysiwyg/root.js b/addons/web_editor/static/src/js/wysiwyg/root.js new file mode 100644 index 00000000000..5dd48b6acf7 --- /dev/null +++ b/addons/web_editor/static/src/js/wysiwyg/root.js @@ -0,0 +1,62 @@ +odoo.define('web_editor.wysiwyg.root', function (require) { +'use strict'; + +var Widget = require('web.Widget'); + +var assetsLoaded = false; + +var WysiwygRoot = Widget.extend({ + assetLibs: ['web_editor.compiled_assets_wysiwyg'], + + publicMethods: ['isDirty', 'save', 'getValue', 'setValue', 'getEditable', 'on', 'trigger'], + + /** + * @see 'web_editor.wysiwyg' module + **/ + init: function (parent, params) { + this._super.apply(this, arguments); + this._params = params; + this.$editor = null; + }, + /** + * Load assets + * + * @override + **/ + willStart: function () { + var self = this; + + var $target = this.$el; + this.$el = null; + + return this._super().then(function () { + if (!assetsLoaded) { + var Wysiwyg = odoo.__DEBUG__.services['web_editor.wysiwyg']; + _.each(['getRange', 'setRange', 'setRangeFromNode'], function (methodName) { + WysiwygRoot[methodName] = Wysiwyg[methodName].bind(Wysiwyg); + }); + assetsLoaded = true; + } + + var Wysiwyg = self._getWysiwygContructor(); + var instance = new Wysiwyg(self, self._params); + self._params = null; + + _.each(self.publicMethods, function (methodName) { + self[methodName] = instance[methodName].bind(instance); + }); + + return instance.attachTo($target).then(function () { + self.$editor = instance.$el; + }); + }); + }, + + _getWysiwygContructor: function () { + return odoo.__DEBUG__.services['web_editor.wysiwyg']; + } +}); + +return WysiwygRoot; + +}); diff --git a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js index 8cf1026158d..44f7dd2c6a8 100644 --- a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js +++ b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js @@ -19,7 +19,10 @@ var Wysiwyg = Widget.extend({ wysiwyg_blur: '_onWysiwygBlur', }, defaultOptions: { - codeview: config.debug + codeview: config.debug, + recordInfo: { + context: {}, + }, }, /** @@ -694,41 +697,6 @@ var Wysiwyg = Widget.extend({ //-------------------------------------------------------------------------- /** - * Load wysiwyg assets if needed. - * - * @see Wysiwyg.createReadyFunction - * @param {Widget} parent - * @returns {$.Promise} - */ -Wysiwyg.prepare = (function () { - var assetsLoaded = false; - var def; - return function prepare(parent) { - if (assetsLoaded) { - return $.when(); - } - if (def) { - return def; - } - def = $.Deferred(); - var timeout = setTimeout(function () { - throw _t("Can't load assets of the wysiwyg editor"); - }, 10000); - var wysiwyg = new Wysiwyg(parent, { - recordInfo: { - context: {}, - } - }); - wysiwyg.attachTo($('<textarea>')).then(function () { - assetsLoaded = true; - clearTimeout(timeout); - wysiwyg.destroy(); - def.resolve(); - }); - return def; - }; -})(); -/** * @param {Node} node (editable or node inside) * @returns {Object} * @returns {Node} sc - start container diff --git a/addons/web_editor/static/src/js/wysiwyg/wysiwyg_iframe.js b/addons/web_editor/static/src/js/wysiwyg/wysiwyg_iframe.js index 7bfe76e3d24..9de5c6b4cb7 100644 --- a/addons/web_editor/static/src/js/wysiwyg/wysiwyg_iframe.js +++ b/addons/web_editor/static/src/js/wysiwyg/wysiwyg_iframe.js @@ -3,7 +3,9 @@ odoo.define('web_editor.wysiwyg.iframe', function (require) { var Wysiwyg = require('web_editor.wysiwyg'); var ajax = require('web.ajax'); +var core = require('web.core'); +var qweb = core.qweb; var _fnSummernoteMaster = $.fn.summernote; var _summernoteMaster = $.summernote; @@ -165,48 +167,14 @@ Wysiwyg.include({ console.warn('Wysiwyg immediate iframe double load detected'); return; } - var cwindow = this.$iframe[0].contentWindow; - cwindow.document + var iframeContent = qweb.render('wysiwyg.iframeContent', { + asset: asset, + updateIframeId: this._onUpdateIframeId, + avoidDoubleLoad: _avoidDoubleLoad + }); + this.$iframe[0].contentWindow.document .open("text/html", "replace") - .write( - '<head>' + - '<meta charset="utf-8">' + - '<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>\n' + - '<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>\n' + - _.map(asset.cssLibs, function (cssLib) { - return '<link type="text/css" rel="stylesheet" href="' + cssLib + '"/>'; - }).join('\n') + '\n' + - _.map(asset.cssContents, function (cssContent) { - return '<style type="text/css">' + cssContent + '</style>'; - }).join('\n') + '\n' + - _.map(asset.jsContents, function (jsContent) { - if (jsContent.indexOf('<inline asset>') !== -1) { - return '<script type="text/javascript">' + jsContent + '</script>'; - } - }).join('\n') + '\n' + - '</head>\n' + - '<body class="o_in_iframe">\n' + - '<div id="iframe_target" style="height: calc(100vh - 6px);"></div>\n' + - '<script type="text/javascript">' + - 'window.$ = window.jQuery = window.top.jQuery;' + - 'var _summernoteMaster = $.summernote;' + - 'var _fnSummernoteMaster = $.fn.summernote;' + - 'delete $.summernote;' + - 'delete $.fn.summernote;' + - '</script>\n' + - '<script type="text/javascript" src="/web_editor/static/lib/summernote/summernote.js"></script>\n' + - '<script type="text/javascript">' + - 'window._summernoteSlave = $.summernote;' + - 'window._summernoteSlave.iframe = true;' + - 'window._summernoteSlave.lang = _summernoteMaster.lang;' + - 'window._fnSummenoteSlave = $.fn.summernote;' + - '$.summernote = _summernoteMaster;' + - '$.fn.summernote = _fnSummernoteMaster;' + - 'if (window.top.' + this._onUpdateIframeId + ') {' + - 'window.top.' + this._onUpdateIframeId + '(' + _avoidDoubleLoad + ')' + - '}' + - '</script>\n' + - '</body>'); + .write(iframeContent); }.bind(this)); }.bind(this)); diff --git a/addons/web_editor/static/src/js/wysiwyg_snippets/wysiwyg_snippets.js b/addons/web_editor/static/src/js/wysiwyg_snippets/wysiwyg_snippets.js index 0f411343486..5df48ebf2f9 100644 --- a/addons/web_editor/static/src/js/wysiwyg_snippets/wysiwyg_snippets.js +++ b/addons/web_editor/static/src/js/wysiwyg_snippets/wysiwyg_snippets.js @@ -15,6 +15,7 @@ Wysiwyg.include({ snippet_cloned: '_onSnippetCloned', snippet_dropped: '_onSnippetDropped', snippet_focused: '_onSnippetFocused', + reload_snippet_dropzones: '_onReloadSnippetDropzones', }), selectorEditableArea: '.note-editable', @@ -173,6 +174,14 @@ Wysiwyg.include({ context.invoke('MediaPlugin.hidePopovers'); }, /** + * trigger reload_snippet_dropzones on snippets + * + * @private + */ + _onReloadSnippetDropzones: function () { + this.snippets.trigger('reload_snippet_dropzones'); + }, + /** * Triggered when a snippet is cloned in the editable area * * @private @@ -258,4 +267,6 @@ $.fn.extend({ }, }); +return Wysiwyg; + }); diff --git a/addons/web_editor/static/src/xml/wysiwyg.xml b/addons/web_editor/static/src/xml/wysiwyg.xml index 5d7754dd7c3..d28efeee92b 100644 --- a/addons/web_editor/static/src/xml/wysiwyg.xml +++ b/addons/web_editor/static/src/xml/wysiwyg.xml @@ -2,6 +2,48 @@ <templates id="template" xml:space="preserve"> <!--=================--> + <!-- Edition Iframe --> + <!--=================--> + + <t t-name="wysiwyg.iframeContent"><head> + <meta charset="utf-8"/> + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/> + <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/> + <t t-foreach="asset.cssLibs || []" t-as="cssLib"> + <link type="text/css" rel="stylesheet" t-att-href="cssLib"/> + </t> + <t t-foreach="asset.cssContents || []" t-as="cssContent"> + <style type="text/css" t-raw="cssContent"/> + </t> + <t t-foreach="asset.jsContents || []" t-as="jsContent" t-if="jsContent.indexOf('inline asset') !== -1"> + <script type="text/javascript" t-raw="jsContent"/> + </t> + </head> + <body class="o_in_iframe"> + <div id="iframe_target" style="height: calc(100vh - 6px);"/> + <script type="text/javascript"> + window.$ = window.jQuery = window.top.jQuery; + var _summernoteMaster = $.summernote; + var _fnSummernoteMaster = $.fn.summernote; + delete $.summernote; + delete $.fn.summernote; + </script> + <script type="text/javascript" src="/web_editor/static/lib/summernote/summernote.js"/> + <script type="text/javascript"> + window._summernoteSlave = $.summernote; + window._summernoteSlave.iframe = true; + window._summernoteSlave.lang = _summernoteMaster.lang; + window._fnSummenoteSlave = $.fn.summernote; + $.summernote = _summernoteMaster; + $.fn.summernote = _fnSummernoteMaster; + if (window.top.<t t-esc="updateIframeId"/>) { + window.top.<t t-esc="updateIframeId"/>(<t t-esc="avoidDoubleLoad"/>); + } + </script> + </body> + </t> + + <!--=================--> <!-- Edition Dialogs --> <!--=================--> diff --git a/addons/web_editor/static/tests/field_html_tests.js b/addons/web_editor/static/tests/field_html_tests.js index b01ab48586b..46e66eed81e 100644 --- a/addons/web_editor/static/tests/field_html_tests.js +++ b/addons/web_editor/static/tests/field_html_tests.js @@ -67,7 +67,7 @@ QUnit.module('field html', { } if (xmlId === 'template.assets_all_style') { return $.when({ - cssLibs: $('head link[href]:not([type="image/x-icon"])').map(function () { + cssLibs: $('link[href]:not([type="image/x-icon"])').map(function () { return $(this).attr('href'); }).get(), cssContents: ['body {background-color: red;}'] @@ -815,7 +815,7 @@ QUnit.test('field html translatable', function (assert) { this.data['note.note'].fields.body.translate = true; - testUtils.createAsyncView({ + return testUtils.createAsyncView({ View: FormView, model: 'note.note', data: this.data, @@ -841,7 +841,6 @@ QUnit.test('field html translatable', function (assert) { form.destroy(); _t.database.multi_lang = multiLang; - }); }); diff --git a/addons/web_editor/static/tests/test_utils.js b/addons/web_editor/static/tests/test_utils.js index ff740e52f36..9f89fd2f3a7 100644 --- a/addons/web_editor/static/tests/test_utils.js +++ b/addons/web_editor/static/tests/test_utils.js @@ -101,7 +101,7 @@ function patch() { } if (xmlId === 'template.assets_all_style') { return $.when({ - cssLibs: $('head link[href]:not([type="image/x-icon"])').map(function () { + cssLibs: $('link[href]:not([type="image/x-icon"])').map(function () { return $(this).attr('href'); }).get(), cssContents: ['body {background-color: red;}'] diff --git a/addons/web_editor/static/tests/wysiwyg_tests.js b/addons/web_editor/static/tests/wysiwyg_tests.js index c2033848e67..3146f908520 100644 --- a/addons/web_editor/static/tests/wysiwyg_tests.js +++ b/addons/web_editor/static/tests/wysiwyg_tests.js @@ -3039,8 +3039,10 @@ QUnit.test('CodeView', function (assert) { var defMediaDialogInit; var defMediaDialogSave; +var defMediaDialogClose; var defCropDialogInit; var defCropDialogSave; +var defCropDialogClose; var defAltDialogInit; var defAltDialogSave; var imgWidth = 10; @@ -3051,26 +3053,34 @@ QUnit.module('Media', { testUtils.mock.patch(MediaDialog, { init: function () { this._super.apply(this, arguments); + this.uid = _.uniqueId(); defMediaDialogInit = $.Deferred(); defMediaDialogSave = $.Deferred(); + defMediaDialogClose = $.Deferred(); this.opened(defMediaDialogInit.resolve.bind(defMediaDialogInit)); - }, - save: function () { - $.when(this._super.apply(this, arguments)).then(function () { - var def = defMediaDialogSave; + this.on('closed', this, function () { + var def = defMediaDialogClose; defMediaDialogInit = null; defMediaDialogSave = null; + defMediaDialogClose = null; def.resolve(); }); }, + save: function () { + var def = defMediaDialogSave; + $.when(this._super.apply(this, arguments)) + .then(def.resolve.bind(def)); + }, }); testUtils.mock.patch(CropDialog, { init: function () { $(arguments[2]).attr('src', $(arguments[2]).data('src')); this._super.apply(this, arguments); var self = this; + this.uid = _.uniqueId(); defCropDialogInit = $.Deferred(); defCropDialogSave = $.Deferred(); + defCropDialogClose = $.Deferred(); this.opened(function () { var cropper = self.$cropperImage.data('cropper'); cropper.clone(); @@ -3084,15 +3094,19 @@ QUnit.module('Media', { cropper.render(); defCropDialogInit.resolve(); }); - }, - save: function () { - $.when(this._super.apply(this, arguments)).then(function () { - var def = defCropDialogSave; + this.on('closed', this, function () { + var def = defCropDialogClose; defCropDialogInit = null; defCropDialogSave = null; + defCropDialogClose = null; def.resolve(); }); }, + save: function () { + var def = defCropDialogSave; + $.when(this._super.apply(this, arguments)) + .then(def.resolve.bind(def)); + }, }); testUtils.mock.patch(AltDialog, { init: function () { @@ -3166,24 +3180,23 @@ QUnit.module('Media', { var _clickMedia = function (wysiwyg, assert, callbackInit, test) { wysiwyg.$('.note-insert .fa-file-image-o').mousedown().click(); - defMediaDialogSave.then(function () { + defMediaDialogInit.then(function () { + return callbackInit(); + }); + return $.when(defMediaDialogSave, defMediaDialogClose).then(function () { + var def = $.when(); if (test.check) { - test.check(); - } - if (test.content) { - assert.deepEqual(wysiwyg.getValue(), test.content, testName); + def = $.when(test.check()); } - if (test.start) { - var range = weTestUtils.select(test.start, test.end, $editable); - assert.deepEqual(Wysiwyg.getRange($editable[0]), range, testName + carretTestSuffix); - } - }); - return defMediaDialogInit.then(function () { - callbackInit(); - var def = $.Deferred(); - setTimeout(function () { - def.resolve(); - }, 0); + def.then(function () { + if (test.content) { + assert.deepEqual(wysiwyg.getValue(), test.content, testName); + } + if (test.start) { + var range = weTestUtils.select(test.start, test.end, $editable); + assert.deepEqual(Wysiwyg.getRange($editable[0]), range, testName + carretTestSuffix); + } + }); return def; }); }; @@ -3494,6 +3507,7 @@ QUnit.test('Image crop', function (assert) { $zoomBtn.mousedown().click(); $('.modal-dialog .modal-footer .btn.btn-primary:contains("Save")').mousedown().click(); }); + return $.when(defCropDialogClose, defCropDialogSave); }, }, }, @@ -3519,6 +3533,7 @@ QUnit.test('Image crop', function (assert) { $('.o_crop_image_dialog .o_crop_options .btn:has(.fa-arrows-h)').mousedown().click(); $('.modal-dialog .modal-footer .btn.btn-primary:contains("Save")').mousedown().click(); }); + return $.when(defCropDialogClose, defCropDialogSave); }, }, }, @@ -3554,6 +3569,7 @@ QUnit.test('Image crop', function (assert) { $pointW.trigger('pointerup'); $('.modal-dialog .modal-footer .btn.btn-primary:contains("Save")').mousedown().click(); }); + return $.when(defCropDialogClose, defCropDialogSave); }, }, }, @@ -3659,7 +3675,7 @@ QUnit.test('Pictogram (fontawesome)', function (assert) { }, test: { check: function () { - _clickMedia(wysiwyg, assert, function () { + return _clickMedia(wysiwyg, assert, function () { _insertPictogram('fa-heart'); }, { content: '<p>\u200B<span class="fa fa-heart"></span>\u200B</p>', diff --git a/addons/web_editor/views/editor.xml b/addons/web_editor/views/editor.xml index dae6e7c91ad..cc61084a603 100644 --- a/addons/web_editor/views/editor.xml +++ b/addons/web_editor/views/editor.xml @@ -6,7 +6,11 @@ <t t-call-assets="web.assets_backend" t-js="false"/> </template> -<template id="wysiwyg" name="Wysiwyg Editor"> +<template id="compiled_assets_wysiwyg" name="Wysiwyg Editor"> + <t t-call-assets="web_editor.assets_wysiwyg"/> +</template> + +<template id="assets_wysiwyg" name="Wysiwyg Editor Assets"> <!-- lib --> <link rel="stylesheet" type="text/css" href="/web_editor/static/lib/summernote/summernote.css"/> @@ -16,9 +20,15 @@ <script type="text/javascript" src="/web_editor/static/lib/cropper/js/cropper.js"/> <script type="text/javascript" src="/web_editor/static/lib/jQuery.transfo.js"/> + <!-- odoo utils --> + + <t t-call="web._assets_helpers"> + <link rel="stylesheet" type="text/scss" href="/web_editor/static/src/scss/bootstrap_overridden.scss"/> + <link rel="stylesheet" type="text/scss" href="/web_editor/static/src/scss/wysiwyg_variables.scss"/> + </t> + <!-- integration --> - <link rel="stylesheet" type="text/scss" href="/web_editor/static/src/scss/wysiwyg_variables.scss"/> <link rel="stylesheet" type="text/scss" href="/web_editor/static/src/scss/wysiwyg.scss"/> <link rel="stylesheet" type="text/scss" href="/web_editor/static/src/scss/wysiwyg_iframe.scss"/> @@ -64,7 +74,7 @@ <script type="text/javascript" src="/web_editor/static/src/js/wysiwyg/plugin/help_dialog.js"/> </template> -<template id="wysiwyg_snippets" inherit_id="web_editor.wysiwyg" name="Wysiwyg Editor additional snippets"> +<template id="wysiwyg_snippets" inherit_id="web_editor.assets_wysiwyg" name="Wysiwyg Editor additional snippets"> <xpath expr="." position="inside"> <link rel="stylesheet" type="text/scss" href="/web_editor/static/src/scss/wysiwyg_variables.scss"/> <link rel="stylesheet" type="text/scss" href="/web_editor/static/src/scss/wysiwyg_snippets.scss"/> @@ -93,7 +103,7 @@ <xpath expr="script[last()]" position="after"> <script type="text/javascript" src="/web_editor/static/lib/vkbeautify/vkbeautify.0.99.00.beta.js"/> <script type="text/javascript" src="/web_editor/static/src/js/common/ace.js"/> - <t t-call="web_editor.wysiwyg"/> + <script type="text/javascript" src="/web_editor/static/src/js/wysiwyg/root.js"/> </xpath> </template> @@ -132,6 +142,17 @@ <template id="qunit_suite" inherit_id="web.qunit_suite"> <xpath expr="." position="inside"> + <script type="text/javascript"> + odoo.define('web_editor.wysiwyg.root.test', function (require) { + 'use strict'; + var WysiwygRoot = require('web_editor.wysiwyg.root'); + WysiwygRoot.include({ + assetLibs: null // We need to add the asset because tests performed overwrites (Dialog, Unbreakable...) + }); + }); + </script> + <t t-call="web_editor.compiled_assets_wysiwyg"/> + <script type="text/javascript" src="/web_editor/static/tests/test_utils.js"/> <script type="text/javascript" src="/web_editor/static/tests/field_html_tests.js"/> <script type="text/javascript" src="/web_editor/static/tests/wysiwyg_tests.js"/> diff --git a/addons/web_unsplash/views/web_unsplash_templates.xml b/addons/web_unsplash/views/web_unsplash_templates.xml index 0d11afef632..e6201eaaba5 100644 --- a/addons/web_unsplash/views/web_unsplash_templates.xml +++ b/addons/web_unsplash/views/web_unsplash_templates.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <odoo> - <template id="web_unsplash_assets" inherit_id="web_editor.wysiwyg" name="Unsplash Images Editor Assets"> + <template id="web_unsplash_assets" inherit_id="web_editor.assets_wysiwyg" name="Unsplash Images Editor Assets"> <xpath expr="." position="inside"> <link rel="stylesheet" type="text/scss" href="/web_unsplash/static/src/scss/unsplash.scss"/> <script type="text/javascript" src="/web_unsplash/static/src/js/unsplashapi.js"></script> diff --git a/addons/website/static/src/js/editor/editor_menu.js b/addons/website/static/src/js/editor/editor_menu.js index 5d7621b91e3..19cffd3f3aa 100644 --- a/addons/website/static/src/js/editor/editor_menu.js +++ b/addons/website/static/src/js/editor/editor_menu.js @@ -4,10 +4,17 @@ odoo.define('website.editor.menu', function (require) { var Dialog = require('web.Dialog'); var Widget = require('web.Widget'); var core = require('web.core'); -var WysiwygMultizone = require('web_editor.wysiwyg.multizone'); +var Wysiwyg = require('web_editor.wysiwyg.root'); var _t = core._t; +var WysiwygMultizone = Wysiwyg.extend({ + assetLibs: Wysiwyg.prototype.assetLibs.concat(['website.compiled_assets_wysiwyg']), + _getWysiwygContructor: function () { + return odoo.__DEBUG__.services['web_editor.wysiwyg.multizone']; + } +}); + var EditorMenu = Widget.extend({ template: 'website.editorbar', xmlDependencies: ['/website/static/src/xml/website.editor.xml'], diff --git a/addons/website/static/src/js/editor/editor_menu_translate.js b/addons/website/static/src/js/editor/editor_menu_translate.js index c52c5e140fc..d390c85a949 100644 --- a/addons/website/static/src/js/editor/editor_menu_translate.js +++ b/addons/website/static/src/js/editor/editor_menu_translate.js @@ -5,7 +5,7 @@ require('web.dom_ready'); var core = require('web.core'); var Dialog = require('web.Dialog'); var localStorage = require('web.local_storage'); -var WysiwygTranslate = require('web_editor.wysiwyg.multizone.translate'); +var Wysiwyg = require('web_editor.wysiwyg.root'); var EditorMenu = require('website.editor.menu'); var _t = core._t; @@ -46,6 +46,13 @@ var TranslatorInfoDialog = Dialog.extend({ }, }); +var WysiwygTranslate = Wysiwyg.extend({ + assetLibs: Wysiwyg.prototype.assetLibs.concat(['website.compiled_assets_wysiwyg']), + _getWysiwygContructor: function () { + return odoo.__DEBUG__.services['web_editor.wysiwyg.multizone.translate']; + } +}); + var TranslatorMenu = EditorMenu.extend({ LOCATION_SEARCH: 'edit_translations', diff --git a/addons/website/static/src/js/editor/wysiwyg_multizone.js b/addons/website/static/src/js/editor/wysiwyg_multizone.js index 1441a7ce3e3..1d264eff436 100644 --- a/addons/website/static/src/js/editor/wysiwyg_multizone.js +++ b/addons/website/static/src/js/editor/wysiwyg_multizone.js @@ -6,7 +6,7 @@ var DropzonePlugin = require('web_editor.wysiwyg.plugin.dropzone'); var HelperPlugin = require('web_editor.wysiwyg.plugin.helper'); var TextPlugin = require('web_editor.wysiwyg.plugin.text'); var HistoryPlugin = require('web_editor.wysiwyg.plugin.history'); -var Wysiwyg = require('web_editor.wysiwyg'); +var Wysiwyg = require('web_editor.wysiwyg.snippets'); var _t = core._t; @@ -70,8 +70,6 @@ DropzonePlugin.include({ - - /** * HtmlEditor * Intended to edit HTML content. This widget uses the Wysiwyg editor diff --git a/addons/website/static/src/js/menu/content.js b/addons/website/static/src/js/menu/content.js index d3aa045920c..9bb2f996595 100644 --- a/addons/website/static/src/js/menu/content.js +++ b/addons/website/static/src/js/menu/content.js @@ -412,7 +412,6 @@ var MenuEntryDialog = weWidgets.LinkDialog.extend({ } return this._super.apply(this, arguments); }, - }); var SelectEditMenuDialog = weWidgets.Dialog.extend({ diff --git a/addons/website/static/src/js/menu/edit.js b/addons/website/static/src/js/menu/edit.js index bc9e4646135..a3e68873a7b 100644 --- a/addons/website/static/src/js/menu/edit.js +++ b/addons/website/static/src/js/menu/edit.js @@ -11,6 +11,8 @@ var _t = core._t; * Adds the behavior when clicking on the 'edit' button (+ editor interaction) */ var EditPageMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ + assetLibs: ['web_editor.compiled_assets_wysiwyg', 'website.compiled_assets_wysiwyg'], + xmlDependencies: ['/website/static/src/xml/website.editor.xml'], actions: _.extend({}, websiteNavbarData.WebsiteNavbarActionWidget.prototype.actions, { edit: '_startEditMode', diff --git a/addons/website/static/src/js/menu/translate.js b/addons/website/static/src/js/menu/translate.js index a94d93d1d75..2359987957f 100644 --- a/addons/website/static/src/js/menu/translate.js +++ b/addons/website/static/src/js/menu/translate.js @@ -6,6 +6,8 @@ var TranslatorMenu = require('website.editor.menu.translate'); var websiteNavbarData = require('website.navbar'); var TranslatePageMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({ + assetLibs: ['web_editor.compiled_assets_wysiwyg', 'website.compiled_assets_wysiwyg'], + actions: _.extend({}, websiteNavbarData.WebsiteNavbar.prototype.actions || {}, { edit_master: '_goToMasterPage', translate: '_startTranslateMode', diff --git a/addons/website/static/src/js/tours/rte.js b/addons/website/static/src/js/tours/rte.js index bdc676f4b33..2fd7aab345c 100644 --- a/addons/website/static/src/js/tours/rte.js +++ b/addons/website/static/src/js/tours/rte.js @@ -4,7 +4,7 @@ odoo.define('website.tour.rte', function (require) { var ajax = require('web.ajax'); var session = require('web.session'); var tour = require('web_tour.tour'); -var Wysiwyg = require('web_editor.wysiwyg'); +var Wysiwyg = require('web_editor.wysiwyg.root'); var domReady = $.Deferred(); $(domReady.resolve.bind(domReady)); diff --git a/addons/website/static/src/scss/website.editor.ui.scss b/addons/website/static/src/scss/website.editor.ui.scss index fb1c90666a8..aa5cba39e00 100644 --- a/addons/website/static/src/scss/website.editor.ui.scss +++ b/addons/website/static/src/scss/website.editor.ui.scss @@ -1,359 +1,3 @@ -// TOP BAR (EDIT) -#web_editor-top-edit { - height: $o-navbar-height; - background-color: $o-we-color-dark; - z-index: $zindex-modal - 9; - position: fixed; - top: 0px; - right: 0px; - width: auto; - white-space: nowrap; - - background-color: rgba(0, 0, 0, 0); - transition: background-color 400ms $o-we-md-ease 0s; - font-family: $o-we-font-family; - - form.navbar-form { - height: $o-navbar-height; - z-index: 1060; - margin: 0; - padding: 0; - @include o-position-absolute($top: -1px, $right: -$o-we-sidebar-width); - transition: right 0.4s $o-we-md-ease 0s; - border-left: 1px solid $o-we-color-divider; - background-color: inherit; - - .btn-group { - height: 100%; - } - - .btn { - height: 100%; - margin: 0; - padding: 10px; - line-height: 1.2; - font-size: 13px; - font-family: $o-we-font-family; - - transition: all 0.3s ease 0s; - border: none; - border-radius: 0; - - .fa { - margin-right: $grid-gutter-width/4; - - &.fa-times { - color: $o-we-color-danger; - } - } - - &.btn-primary { - @include button-variant($o-brand-odoo, $o-brand-odoo); - } - - &.btn-secondary { - @include button-variant($o-we-color-dark, $o-we-color-dark); - - &:hover { - background: rgba(black, 0.5); - } - } - - &:focus, - &:active, - &:focus:active { - outline: none; - } - } - - .dropdown-menu { - left: auto; - right: 0; - } - } -} - -// Translations -.oe_translate_examples li { - margin: 10px; - padding: 4px; -} - -html[lang]>body.editor_enable [data-oe-translation-state] { - background: rgba($o-we-content-to-translate-color, 0.5) !important; - - &[data-oe-translation-state="translated"] { - background: rgba($o-we-translated-content-color, 0.5) !important; - } - - &.o_dirty { - background: rgba($o-we-translated-content-color, 0.25) !important; - } -} - -// NOTE EDITOR - -// SNIPPET PANEL -#oe_snippets { - @include o-w-preserve-btn; - @include o-position-absolute(0, auto, 0, -$o-we-sidebar-width); - width: $o-we-sidebar-width; - - border-right: 1px solid $o-we-color-divider; - transition: left 400ms $o-we-md-ease 0s; - background-image: linear-gradient(45deg, $o-we-color-normal, darken($o-we-color-normal, 10%)); - - #snippets_menu { - color: #999999; - background: $o-we-color-dark; - font-family: $o-we-font-family; - height: $o-navbar-height; - line-height: $o-navbar-height; - } - - #o_scroll { - .o_panel_header { - color: #999999; - } - } -} - -.oe_snippet { - background-color: $o-we-color-normal; - - .oe_snippet_thumbnail { - .oe_snippet_thumbnail_img { - border: 1px solid $o-we-color-normal; - } - - img.oe_snippet_thumbnail_img {} - - .oe_snippet_thumbnail_title { - border: 1px solid $o-we-color-dark; - color: $o-we-color-text-light; - } - - &:hover .oe_snippet_thumbnail_title { - color: $o-we-color-text-lighter; - } - } -} - -// SNIPPET OPTIONS -.colorpicker { - .o_colorpicker_sections { - .note-color-palette>div { - color: $o-we-color-text-light; - } - } - - .o_colorpicker_section { - &:after { - content: ""; - display: table; - clear: both; - } - - >button { - - &:hover, - &.selected { - box-shadow: 0px 0px 2px 2px $o-we-color-light; - } - - &[data-event="foreColor"] { - background-color: $o-we-color-normal; - - &:before { - background-color: rgba(white, 0.3); - } - } - } - } - - .note-palette-title { - color: $o-we-color-text-light; - } - - .palette-reset { - .note-color-reset { - color: desaturate(rgba($o-we-color-danger, 0.6), 40%); - - &:hover { - color: $o-we-color-danger; - } - } - } -} - -// DROPZONES -#wrapwrap .oe_drop_zone { - &.oe_insert { - height: $o-we-dropzone-size; - margin: (-$o-we-dropzone-size/2) 0; - - &:after { - border-bottom: $o-we-dropzone-border; - } - - &.oe_vertical { - width: $o-we-dropzone-size; - margin: 0 (-$o-we-dropzone-size/2); - - &:after { - border-right: $o-we-dropzone-border; - } - } - } -} - -// MANIPULATORS -#oe_manipulators { - - // SNIPPET MANIPULATORS - .oe_overlay { - - // OVERLAY OPTIONS - >.oe_overlay_options { - font-family: $o-we-font-family; - - >.btn-group { - .btn { - width: $o-we-overlay-option-size; - height: $o-we-overlay-option-size; - border: 1px solid $o-we-color-dark; - line-height: #{$o-we-overlay-option-size - 2px}; - - color: $o-we-color-text-light; - background-color: $o-we-color-light; - - &:hover { - background-color: lighten($o-we-color-dark, 10%); - } - - &.oe_snippet_remove { - background-color: $o-we-color-danger; - border-color: darken($o-we-color-danger, 20%); - - &:hover { - background-color: darken($o-we-color-danger, 20%); - } - } - - >.fa { - color: $o-we-color-text-light; - } - } - - // CUSTOMIZE MENU BUTTON - >.oe_options { - .btn { - background-color: $o-we-color-dark; - color: $o-we-color-text-light; - - &:hover, - &:active, - &:focus { - background-color: lighten($o-we-color-dark, 5%); - border-color: lighten($o-we-color-dark, 10%); - } - - &:before, - &:after { - background-color: $o-we-color-text-light; - } - } - - // Open menu - &.show .btn { - // background-color: $o-we-color-light; - } - - // CUSTOMIZE MENU - .dropdown-menu { - border: 1px solid $o-we-color-dark; - background-color: $o-we-color-light; - - .dropdown-item { - color: $o-we-color-text-light; - - &:hover { - background-color: fade-out($o-we-color-dark, 0.5); - } - - &.active { - background-color: fade-out($o-we-color-dark, 0.5); - } - } - - .dropdown-header { - color: wheat; - - &.o_parent_editor_header { - color: wheat; - } - } - - .dropdown-submenu { - &::before { - border-left-color: $o-we-color-text-light; - } - } - } - } - } - } - - &.o_top_cover>.oe_overlay_options { - top: $o-we-handle-border-width; - right: $o-we-handle-border-width; - } - - } -} - -// Animations -@keyframes fadeInDownSmall { - 0% { - opacity: 0; - transform: translate(0, -5px); - } - - 100% { - opacity: 1; - transform: translate(0, 0); - } -} - -@keyframes fadeInOut { - 0% { - opacity: 0; - } - - 25% { - opacity: 1; - } - - 75% { - opacity: 1; - } - - 100% { - opacity: 0; - } -} - -@keyframes inputHighlighter { - from { - background: $o-brand-primary; - } - - to { - width: 0; - background: transparent; - } -} - // INPUTS .o_switch { display: flex; @@ -369,11 +13,10 @@ html[lang]>body.editor_enable [data-oe-translation-state] { box-shadow: inset 0 0 0px 1px darken($o-we-switch-inactive-color, 10%); border-radius: 100rem; height: $o-we-switch-size; - width: $o-we-switch-size * 1.81; - margin-right: 0.51em; + width: $o-we-switch-size * 1.8; + margin-right: 0.5em; display: inline-block; transition: all 0.3s $o-we-md-ease; - font-size: 15px; &:after { content: ""; @@ -517,297 +160,3 @@ html[lang]>body.editor_enable [data-oe-translation-state] { } } } - -// MODALS -body .modal { - - // BACKGROUND IMAGE OPTIONS - .o_bg_img_opt_modal .o_bg_img_opt { - margin: 15px 0; - - .help-control { - @include o-position-absolute(15px, 15px); - } - - .help { - margin: 15px 0; - - .simulator { - position: relative; - float: left; - margin-right: 15px; - width: 120px; - height: 100px; - - .bg { - @include o-position-absolute(0, 0, 0, 0); - border: 1px dotted #888787; - background-image: url(/web/image); - background-position: center center; - background-size: cover; - } - - .el { - @include o-position-absolute(10px, 0, 10px, 0); - border: 1px solid #222; - } - - &.contain_bg { - .bg { - @include o-position-absolute(0, 12px, 20px, 12px); - } - - .el { - @include o-position-absolute(0, 0, 20px, 0); - } - } - } - - +* { - clear: left; - } - } - - .o_bg_img_opt_cover_edition { - @include o-we-preview-box; - padding: 0 25px 25px 25px; - - h6 { - color: white; - font-weight: bold; - } - - .o_bg_img_opt_object { - position: relative; - background: white; - min-height: 10px; - @include o-we-preview-content; - - >img { - cursor: crosshair; - border-top: 1px solid #5A5A5A; - border-bottom: 1px solid #111; - } - - &:hover .o_focus_point:before { - opacity: 0.5; - } - } - - .o_bg_img_opt_ui_info { - animation: fadeInOut 2s ease forwards; - @include o-position-absolute($bottom: 1px, $right: 0); - display: block; - padding: 3px 13px; - background-color: rgba(255, 255, 255, 0.8); - color: #333; - text-align: center; - font-weight: bold; - pointer-events: none; - - span { - font-weight: normal; - } - - .o_x { - margin-right: 10px - } - } - - .grid { - @include o-position-absolute($top: 33.33%, $left: 0); - display: block; - width: 100%; - height: 1px; - background: fade-out(lighten($o-brand-primary, 30%), 0.5); - pointer-events: none; - - &.grid-2 { - top: 66.66% - } - - &.grid-3 { - top: 0; - left: 33.33%; - width: 1px; - height: 100% - } - - &.grid-4 { - top: 0; - left: 66.66%; - width: 1px; - height: 100% - } - } - - .o_focus_point { - @include o-position-absolute($top: 0, $left: 0); - width: 30px; - height: 30px; - border: 2px solid white; - border-radius: 100%; - margin-top: -15px; - margin-left: -15px; - box-shadow: 0 0 1px #333; - pointer-events: none; - - &.o_with_transition { - transition: all 0.2s ease 0s; - } - - &:before { - pointer-events: none; - content: ""; - display: block; - width: 100px; - height: 100px; - margin-top: -37px; - margin-left: -37px; - border: 1px solid #EAEAEA; - background: rgba(247, 76, 76, 0); - border-radius: 100em; - opacity: 1; - box-shadow: 0 0 0 100em rgba(0, 0, 0, 0.33); - transition: opacity 0.2s ease 0s; - } - } - } - } -} - -// editor_enable - -body.editor_enable { - overflow: hidden; - padding-top: 0 !important; - - #web_editor-top-edit { - background-color: $o-we-color-dark; - - form.navbar-form { - right: 0; - } - } - - #wrapwrap { - height: calc(100vh - #{$o-navbar-height}); - padding-top: 0px; - - .btn { - -webkit-user-select: none; - } - } -} - -.wysiwyg_multizone.note-editor { - &>.note-toolbar-wrapper .note-toolbar { - height: $o-navbar-height; - - .btn { - height: $o-navbar-height; - } - } - - &>.note-statusbar { - display: none; - } - - &>.note-editing-area { - overflow: visible; - } -} - -.wysiwyg_multizone.note-popover.popover { - border-width: 0 1px; - - .popover-content .btn { - height: $o-navbar-height; - } -} - -.wysiwyg_multizone.note-popover, -.wysiwyg_multizone.note-editor>.note-toolbar-wrapper .note-toolbar { - background-color: $o-we-color-dark; - - .btn { - background-color: $o-we-color-dark; - color: $o-we-color-text-normal; - border: none; - padding: 0.0625rem 0.3125rem !important; // force this because of themes - - >.fa { - color: $o-we-color-text-normal; - } - - &:hover { - color: $o-we-color-text-light; - - >.fa { - color: $o-we-color-text-light; - } - } - - &.active { - background-color: $o-we-color-dark; - color: $o-we-color-text-light; - - >.fa { - color: $o-we-color-text-light; - } - } - } - - >.btn-group { - margin-top: 0; - - &.show, - .btn-group.show { - .dropdown-toggle { - border-top: 2px solid white; - background-color: $o-we-color-darker; - color: white; - box-shadow: none; - - >.fa, - >span { - color: white; - } - } - } - } - - .dropdown-menu { - margin: 0; - border-radius: 0; - background-color: $o-we-color-darker; - color: $o-we-color-text-normal; - white-space: normal; - - .dropdown-item { - width: 100%; - color: $o-we-color-text-light; - - >.fa { - color: $o-we-color-text-light; - } - - &:hover { - background-color: $o-we-tab-active-bg; - color: white; - - >.fa { - color: white; - } - } - } - } - - .note-para .dropdown-menu { - min-width: 147px; - } - - .note-style .dropdown-item * { - color: $o-we-color-text-light; - } -} diff --git a/addons/website/static/src/scss/website.wysiwyg.scss b/addons/website/static/src/scss/website.wysiwyg.scss new file mode 100644 index 00000000000..bed3805eb02 --- /dev/null +++ b/addons/website/static/src/scss/website.wysiwyg.scss @@ -0,0 +1,640 @@ +body.editor_enable { + overflow: hidden; + padding-top: 0 !important; + + // TOP BAR (EDIT) + #web_editor-top-edit { + height: $o-navbar-height; + background-color: $o-we-color-dark; + z-index: $zindex-modal - 9; + position: fixed; + top: 0px; + right: 0px; + width: auto; + white-space: nowrap; + + background-color: rgba(0, 0, 0, 0); + transition: background-color 400ms $o-we-md-ease 0s; + font-family: $o-we-font-family; + + form.navbar-form { + height: $o-navbar-height; + z-index: 1060; + margin: 0; + padding: 0; + position: absolute; + top: -1px; + right: 0; + transition: right 0.4s $o-we-md-ease 0s; + border-left: 1px solid $o-we-color-divider; + background-color: inherit; + + .btn-group { + height: 100%; + } + + .btn { + height: 100%; + margin: 0; + padding: 10px; + line-height: 1.2; + font-size: 13px; + font-family: $o-we-font-family; + + transition: all 0.3s ease 0s; + border: none; + border-radius: 0; + + .fa { + margin-right: $grid-gutter-width/4; + + &.fa-times { + color: $o-we-color-danger; + } + } + + &.btn-primary { + @include button-variant($o-brand-odoo, $o-brand-odoo); + } + + &.btn-secondary { + @include button-variant($o-we-color-dark, $o-we-color-dark); + + &:hover { + background: rgba(black, 0.5); + } + } + + &:focus, + &:active, + &:focus:active { + outline: none; + } + } + + .dropdown-menu { + left: auto; + right: 0; + } + } + } + + #wrapwrap { + height: calc(100vh - #{$o-navbar-height}); + padding-top: 0px; + + .btn { + -webkit-user-select: none; + } + } + + // Translations + .oe_translate_examples li { + margin: 10px; + padding: 4px; + } + + html[lang]>body.editor_enable [data-oe-translation-state] { + background: rgba($o-we-content-to-translate-color, 0.5) !important; + + &[data-oe-translation-state="translated"] { + background: rgba($o-we-translated-content-color, 0.5) !important; + } + + &.o_dirty { + background: rgba($o-we-translated-content-color, 0.25) !important; + } + } + + // NOTE EDITOR + + // SNIPPET PANEL + #oe_snippets { + @include o-w-preserve-btn; + @include o-position-absolute(0, auto, 0, -$o-we-sidebar-width); + width: $o-we-sidebar-width; + + border-right: 1px solid $o-we-color-divider; + transition: left 400ms $o-we-md-ease 0s; + background-image: linear-gradient(45deg, $o-we-color-normal, darken($o-we-color-normal, 10%)); + + #snippets_menu { + color: #999999; + background: $o-we-color-dark; + font-family: $o-we-font-family; + height: $o-navbar-height; + line-height: $o-navbar-height; + } + + #o_scroll { + .o_panel_header { + color: #999999; + } + } + } + + .oe_snippet { + background-color: $o-we-color-normal; + + .oe_snippet_thumbnail { + .oe_snippet_thumbnail_img { + border: 1px solid $o-we-color-normal; + } + + img.oe_snippet_thumbnail_img {} + + .oe_snippet_thumbnail_title { + border: 1px solid $o-we-color-dark; + color: $o-we-color-text-light; + } + + &:hover .oe_snippet_thumbnail_title { + color: $o-we-color-text-lighter; + } + } + } + + // SNIPPET OPTIONS + .colorpicker { + .o_colorpicker_sections { + .note-color-palette>div { + color: $o-we-color-text-light; + } + } + + .o_colorpicker_section { + &:after { + content: ""; + display: table; + clear: both; + } + + >button { + + &:hover, + &.selected { + box-shadow: 0px 0px 2px 2px $o-we-color-light; + } + + &[data-event="foreColor"] { + background-color: $o-we-color-normal; + + &:before { + background-color: rgba(white, 0.3); + } + } + } + } + + .note-palette-title { + color: $o-we-color-text-light; + } + + .palette-reset { + .note-color-reset { + color: desaturate(rgba($o-we-color-danger, 0.6), 40%); + + &:hover { + color: $o-we-color-danger; + } + } + } + } + + // DROPZONES + #wrapwrap .oe_drop_zone { + &.oe_insert { + height: $o-we-dropzone-size; + margin: (-$o-we-dropzone-size/2) 0; + + &:after { + border-bottom: $o-we-dropzone-border; + } + + &.oe_vertical { + width: $o-we-dropzone-size; + margin: 0 (-$o-we-dropzone-size/2); + + &:after { + border-right: $o-we-dropzone-border; + } + } + } + } + + // MANIPULATORS + #oe_manipulators { + + // SNIPPET MANIPULATORS + .oe_overlay { + + // OVERLAY OPTIONS + >.oe_overlay_options { + font-family: $o-we-font-family; + + >.btn-group { + .btn { + height: $o-we-overlay-option-size; + border: 1px solid $o-we-color-dark; + line-height: #{$o-we-overlay-option-size - 2px}; + + color: $o-we-color-text-light; + background-color: $o-we-color-light; + + &:hover { + background-color: lighten($o-we-color-dark, 10%); + } + + &.oe_snippet_remove { + background-color: $o-we-color-danger; + border-color: darken($o-we-color-danger, 20%); + + &:hover { + background-color: darken($o-we-color-danger, 20%); + } + } + + >.fa { + color: $o-we-color-text-light; + } + } + + // CUSTOMIZE MENU BUTTON + >.oe_options { + .btn { + background-color: $o-we-color-dark; + color: $o-we-color-text-light; + + &:hover, + &:active, + &:focus { + background-color: lighten($o-we-color-dark, 5%); + border-color: lighten($o-we-color-dark, 10%); + } + + &:before, + &:after { + background-color: $o-we-color-text-light; + } + } + + // Open menu + &.show .btn { + // background-color: $o-we-color-light; + } + + // CUSTOMIZE MENU + .dropdown-menu { + border: 1px solid $o-we-color-dark; + background-color: $o-we-color-light; + + .dropdown-item { + color: $o-we-color-text-light; + + &:hover { + background-color: fade-out($o-we-color-dark, 0.5); + } + + &.active { + background-color: fade-out($o-we-color-dark, 0.5); + } + } + + .dropdown-header { + color: wheat; + + &.o_parent_editor_header { + color: wheat; + } + } + + .dropdown-submenu { + &::before { + border-left-color: $o-we-color-text-light; + } + } + } + } + } + } + + &.o_top_cover>.oe_overlay_options { + top: $o-we-handle-border-width; + right: $o-we-handle-border-width; + } + + } + } + + // Animations + @keyframes fadeInDownSmall { + 0% { + opacity: 0; + transform: translate(0, -5px); + } + + 100% { + opacity: 1; + transform: translate(0, 0); + } + } + + @keyframes fadeInOut { + 0% { + opacity: 0; + } + + 25% { + opacity: 1; + } + + 75% { + opacity: 1; + } + + 100% { + opacity: 0; + } + } + + @keyframes inputHighlighter { + from { + background: $o-brand-primary; + } + + to { + width: 0; + background: transparent; + } + } + + // MODALS + body .modal { + + // BACKGROUND IMAGE OPTIONS + .o_bg_img_opt_modal .o_bg_img_opt { + margin: 15px 0; + + .help-control { + @include o-position-absolute(15px, 15px); + } + + .help { + margin: 15px 0; + + .simulator { + position: relative; + float: left; + margin-right: 15px; + width: 120px; + height: 100px; + + .bg { + @include o-position-absolute(0, 0, 0, 0); + border: 1px dotted #888787; + background-image: url(/web/image); + background-position: center center; + background-size: cover; + } + + .el { + @include o-position-absolute(10px, 0, 10px, 0); + border: 1px solid #222; + } + + &.contain_bg { + .bg { + @include o-position-absolute(0, 12px, 20px, 12px); + } + + .el { + @include o-position-absolute(0, 0, 20px, 0); + } + } + } + + +* { + clear: left; + } + } + + .o_bg_img_opt_cover_edition { + @include o-we-preview-box; + padding: 0 25px 25px 25px; + + h6 { + color: white; + font-weight: bold; + } + + .o_bg_img_opt_object { + position: relative; + background: white; + min-height: 10px; + @include o-we-preview-content; + + >img { + cursor: crosshair; + border-top: 1px solid #5A5A5A; + border-bottom: 1px solid #111; + } + + &:hover .o_focus_point:before { + opacity: 0.5; + } + } + + .o_bg_img_opt_ui_info { + animation: fadeInOut 2s ease forwards; + @include o-position-absolute($bottom: 1px, $right: 0); + display: block; + padding: 3px 13px; + background-color: rgba(255, 255, 255, 0.8); + color: #333; + text-align: center; + font-weight: bold; + pointer-events: none; + + span { + font-weight: normal; + } + + .o_x { + margin-right: 10px + } + } + + .grid { + @include o-position-absolute($top: 33.33%, $left: 0); + display: block; + width: 100%; + height: 1px; + background: fade-out(lighten($o-brand-primary, 30%), 0.5); + pointer-events: none; + + &.grid-2 { + top: 66.66% + } + + &.grid-3 { + top: 0; + left: 33.33%; + width: 1px; + height: 100% + } + + &.grid-4 { + top: 0; + left: 66.66%; + width: 1px; + height: 100% + } + } + + .o_focus_point { + @include o-position-absolute($top: 0, $left: 0); + width: 30px; + height: 30px; + border: 2px solid white; + border-radius: 100%; + margin-top: -15px; + margin-left: -15px; + box-shadow: 0 0 1px #333; + pointer-events: none; + + &.o_with_transition { + transition: all 0.2s ease 0s; + } + + &:before { + pointer-events: none; + content: ""; + display: block; + width: 100px; + height: 100px; + margin-top: -37px; + margin-left: -37px; + border: 1px solid #EAEAEA; + background: rgba(247, 76, 76, 0); + border-radius: 100em; + opacity: 1; + box-shadow: 0 0 0 100em rgba(0, 0, 0, 0.33); + transition: opacity 0.2s ease 0s; + } + } + } + } + } + + .wysiwyg_multizone.note-editor { + &>.note-toolbar-wrapper .note-toolbar { + height: $o-navbar-height; + + .btn { + height: $o-navbar-height; + } + } + + &>.note-statusbar { + display: none; + } + + &>.note-editing-area { + overflow: visible; + } + } + + .wysiwyg_multizone.note-popover.popover { + border-width: 0 1px; + + .popover-content .btn { + height: $o-navbar-height; + } + } + + .wysiwyg_multizone.note-popover, + .wysiwyg_multizone.note-editor>.note-toolbar-wrapper .note-toolbar { + background-color: $o-we-color-dark; + + .btn { + background-color: $o-we-color-dark; + color: $o-we-color-text-normal; + border: none; + padding: 0.0625rem 0.3125rem !important; // force this because of themes + + >.fa { + color: $o-we-color-text-normal; + } + + &:hover { + color: $o-we-color-text-light; + + >.fa { + color: $o-we-color-text-light; + } + } + + &.active { + background-color: $o-we-color-dark; + color: $o-we-color-text-light; + + >.fa { + color: $o-we-color-text-light; + } + } + } + + >.btn-group { + margin-top: 0; + + &.show, + .btn-group.show { + .dropdown-toggle { + border-top: 2px solid white; + background-color: $o-we-color-darker; + color: white; + box-shadow: none; + + >.fa, + >span { + color: white; + } + } + } + } + + .dropdown-menu { + margin: 0; + border-radius: 0; + background-color: $o-we-color-darker; + color: $o-we-color-text-normal; + white-space: normal; + + .dropdown-item { + width: 100%; + color: $o-we-color-text-light; + + >.fa { + color: $o-we-color-text-light; + } + + &:hover { + background-color: $o-we-tab-active-bg; + color: white; + + >.fa { + color: white; + } + } + } + } + + .note-para .dropdown-menu { + min-width: 147px; + } + + .note-style .dropdown-item * { + color: $o-we-color-text-light; + } + } +} diff --git a/addons/website/views/website_templates.xml b/addons/website/views/website_templates.xml index 809576083c1..8809cd292d4 100644 --- a/addons/website/views/website_templates.xml +++ b/addons/website/views/website_templates.xml @@ -80,6 +80,23 @@ </xpath> </template> +<template id="website.compiled_assets_wysiwyg" name="Website Editor Assets (used in website editor)"> + <t t-call-assets="website.assets_wysiwyg"/> +</template> + +<template id="website.assets_wysiwyg" name="Website Editor Assets (used in website editor)"> + <t t-call="web._assets_helpers"> + <link rel="stylesheet" type="text/scss" href="/web_editor/static/src/scss/bootstrap_overridden.scss"/> + <link rel="stylesheet" type="text/scss" href="/web_editor/static/src/scss/wysiwyg_variables.scss"/> + </t> + <link rel="stylesheet" type="text/scss" href="/website/static/src/scss/website.wysiwyg.scss"/> + + <script type="text/javascript" src="/website/static/src/js/editor/snippets.options.js"/> + <script type="text/javascript" src="/website/static/src/js/editor/wysiwyg_multizone.js"/> + <script type="text/javascript" src="/website/static/src/js/editor/wysiwyg_multizone_translate.js"/> + <script type="text/javascript" src="/website/static/src/js/editor/widget_link.js"/> +</template> + <template id="website.assets_editor" name="Website Editor Assets (used in website editor)"> <t t-call="web._assets_helpers"/> @@ -88,10 +105,6 @@ <script type="text/javascript" src="/website/static/src/js/editor/editor_menu.js"/> <script type="text/javascript" src="/website/static/src/js/editor/editor_menu_translate.js"/> - <script type="text/javascript" src="/website/static/src/js/editor/widget_link.js"/> - <script type="text/javascript" src="/website/static/src/js/editor/snippets.options.js"/> - <script type="text/javascript" src="/website/static/src/js/editor/wysiwyg_multizone.js"/> - <script type="text/javascript" src="/website/static/src/js/editor/wysiwyg_multizone_translate.js"/> <script type="text/javascript" src="/website/static/src/js/menu/content.js"/> <script type="text/javascript" src="/website/static/src/js/menu/customize.js"/> @@ -107,7 +120,6 @@ <script type="text/javascript" src="/website/static/src/js/widgets/ace.js"/> <script type="text/javascript" src="/website/static/src/js/widgets/theme.js"/> - </template> <!-- Layout --> diff --git a/addons/website_forum/static/src/js/website_forum.editor.js b/addons/website_forum/static/src/js/website_forum.editor.js index 40e96893151..f9e03422119 100644 --- a/addons/website_forum/static/src/js/website_forum.editor.js +++ b/addons/website_forum/static/src/js/website_forum.editor.js @@ -3,7 +3,6 @@ odoo.define('website_forum.editor', function (require) { var core = require('web.core'); var Widget = require('web.Widget'); -var Wysiwyg = require('web_editor.wysiwyg'); var WebsiteNewMenu = require('website.newMenu'); var wUtils = require('website.utils'); var websiteRootData = require('website.WebsiteRoot'); diff --git a/addons/website_forum/static/src/js/website_forum.js b/addons/website_forum/static/src/js/website_forum.js index 612704e42bf..613163a045a 100644 --- a/addons/website_forum/static/src/js/website_forum.js +++ b/addons/website_forum/static/src/js/website_forum.js @@ -2,7 +2,7 @@ odoo.define('website_forum.website_forum', function (require) { 'use strict'; var core = require('web.core'); -var Wysiwyg = require('web_editor.wysiwyg'); +var Wysiwyg = require('web_editor.wysiwyg.root'); var sAnimations = require('website.content.snippets.animation'); var session = require('web.session'); var qweb = core.qweb; |
