From f296992317e96562c66bd7ad59a5080d6c551ed5 Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Thu, 10 Jan 2019 11:07:17 +0000 Subject: [IMP] web_editor,*: Refactoring the wysiwyg editor and 'html' field * Creating a new structure by transforming all the plugins in the library using the odoo inheritance system. Plugins are easier to implement with the AbstractPlugin to add Odoo behaviors. * From now on, the methods of the library (in this case Summernote) can no longer be called by other modules or files. Only the wysiwyg widgets can access it, to simplify the updating process. The wysiwyg object serves as an interface. * Depending on the options the snippets will be loaded or not, the editor will be in an iframe or not... all of this is transparent from the outside. * Regarding iframes, all controllers related to editing have been removed: the new API no longer needs them. This speeds up loading, eases testing and removes complexity for the same features. PUBLIC FEATURES There are several public methods on the Wysiwyg class: * Wysiwyg.prepare (WidgetParent): returns a deferred resolved when the library (xml, lazy, assets...) is loaded. * Wysiwyg.getRange (DOM): returns the range (selection in the dom) * Wysiwyg.setRange (startNode, startOffset, endNode, endOffset): creates a range (selection in the dom) * Wysiwyg.setRangeFromNode (DOM, options) that creates a range from an element (option available to select all, start or end) A jQuery selector was added: :o_editable, which indicates whether the current element is editable. That is, if it is contained in a tag with the attribute 'contentEditable = "true"' or in a tag with the class o_editable. Several methods are also present: * focusIn: makes a focus and places the cursor at the beginning of the element * focusInEnd: makes a focus and places the cursor at the end of the element * selectContent: makes a focus and selects the content HTML FIELD The HTML field can receive different options: * style-inline: {boolean} transforms a class into an inline style when saving and vice versa when reading. * no-attachment: {boolean} prevents the use of attachments (in media dialog) * cssEdit: {xml_id} to use a template containing the css to loaded in an iframe when editing * cssReadonly: {xml_id} to use a template containing the css to load into an iframe when viewing in readonly * snippets: {xml_id} snippets template (can be used with or without cssEdit) * wrapper: {template} qweb static template (containing a tag: id = "wrapper") that will include the content during editing (removed on save) MASS MAILING A widget was created for mass mailing. There are now two fields: body_html and body_arch. body_arch contains the code with the class without conversion into inline style, useful when editing and one with the inline style that is visible in readonly mode and sent by email. Advantage: no spreading errors, able to update css/theme, able to do more changes when converting to inline style so that a maximum of mail clients have an impeccable rendering. Co-authored-by: Antoine Guenet --- addons/web_editor/static/src/js/iframe.js | 153 ------------------------------ 1 file changed, 153 deletions(-) delete mode 100644 addons/web_editor/static/src/js/iframe.js (limited to 'addons/web_editor/static/src/js/iframe.js') diff --git a/addons/web_editor/static/src/js/iframe.js b/addons/web_editor/static/src/js/iframe.js deleted file mode 100644 index f2c5e3be661..00000000000 --- a/addons/web_editor/static/src/js/iframe.js +++ /dev/null @@ -1,153 +0,0 @@ -odoo.define('web_editor.iframe', function (require) { -'use strict'; - -var core = require('web.core'); -var editor = require('web_editor.editor'); -var translator = require('web_editor.translate'); -var rte = require('web_editor.rte'); - -var callback = window ? window['callback'] : undefined; -window.top.odoo[callback + '_updown'] = function (value, fields_values, field_name) { - var $editable = $('#editable_area'); - if (value === $editable.prop('innerHTML')) { - return; - } - - if ($('body').hasClass('editor_enable')) { - if (value !== fields_values[field_name]) { - rte.history.recordUndo($editable); - } - core.bus.trigger('deactivate_snippet'); - } - - $editable.html(value); - - if ($('body').hasClass('editor_enable') && value !== fields_values[field_name]) { - $editable.trigger('content_changed'); - } -}; - -editor.Class.include({ - start: function () { - this.on('rte:start', this, function () { - this.$('form').hide(); - - if (window.top.odoo[callback + '_editor']) { - window.top.odoo[callback + '_editor'](this); - } - - var $editable = $('#editable_area'); - setTimeout(function () { - $($editable.find('*').filter(function () {return !this.children.length;}).first()[0] || $editable) - .focusIn().trigger('mousedown').trigger('keyup'); - },0); - - $editable.on('content_changed', this, function () { - if (window.top.odoo[callback + '_downup']) { - window.top.odoo[callback + '_downup']($editable.prop('innerHTML')); - } - }); - }); - - return this._super.apply(this, arguments).then(function () { - $(window.top).trigger('resize'); // TODO check, probably useless - }); - } -}); - -rte.Class.include({ - /** - * @override - */ - _getDefaultConfig: function ($editable) { - var config = this._super.apply(this, arguments); - if ($.deparam($.param.querystring()).debug !== undefined) { - config.airPopover.splice(7, 0, ['view', ['codeview']]); - } - return config; - }, -}); - -translator.Class.include({ - start: function () { - var res = this._super.apply(this, arguments); - $('button[data-action=save]').hide(); - if (window.top.odoo[callback + '_editor']) { - window.top.odoo[callback + '_editor'](this); - } - return res; - }, -}); -}); - -//============================================================================== - -odoo.define('root.widget', function (require) { -'use strict'; - -require('web.dom_ready'); -var iframeRootData = require('web_editor.IframeRoot'); - -var iframeRoot = new iframeRootData.IframeRoot(null); -return iframeRoot.attachTo(document.body).then(function () { - return iframeRoot; -}); -}); - -//============================================================================== - -odoo.define('web_editor.IframeRoot', function (require) { -'use strict'; - -var BodyManager = require('web_editor.BodyManager'); -var weContext = require('web_editor.context'); -var editor = require('web_editor.editor'); -var rootWidget = require('web_editor.root_widget'); -var translate = require('web_editor.translate'); - -var iframeRootRegistry = new rootWidget.RootWidgetRegistry(); - -var IframeRoot = BodyManager.extend({ - /** - * @override - * @todo this is somehow a duplicate of website features - */ - start: function () { - var defs = [this._super.apply(this, arguments)]; - - var ctx = weContext.getExtra(); - - if (ctx.editable && window.location.search.indexOf('enable_editor') >= 0) { - var editorInstance = new (editor.Class)(this); - defs.push(editorInstance.prependTo(this.$el)); - } - - if (ctx.edit_translations) { - var translator = new (translate.Class)(this, this.$('#wrapwrap')); - defs.push(translator.prependTo(this.$el)); - } - - return $.when.apply($, defs); - }, - - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - - /** - * As the IframeRoot instance is designed to be unique, the associated - * registry has been instantiated outside of the class and is simply - * returned here. - * - * @override - */ - _getRegistry: function () { - return iframeRootRegistry; - }, -}); - -return { - IframeRoot: IframeRoot, - iframeRootRegistry: iframeRootRegistry, -}; -}); -- cgit v1.2.3