summaryrefslogtreecommitdiff
path: root/addons/web_editor/static/src/js/editor/rte.summernote.js
diff options
context:
space:
mode:
authorRobot Odoo <xmo+roboto@odoo.com>2019-01-17 19:17:22 +0100
committerGitHub <noreply@github.com>2019-01-17 19:17:22 +0100
commit22efdfbecc1e8c688000be98903a5a355d1ece8a (patch)
treee097625171b2b67ed5f5288ced67446608b9f633 /addons/web_editor/static/src/js/editor/rte.summernote.js
parentf50fbc6d168f0d17fa1e932b4ecc968a92b02b65 (diff)
parenteb0ea8efbe932c140302e9f8da33a839bcd73146 (diff)
[IMP] web_editor,*: Refactoring the wysiwyg editor and 'html' field
_Task #1878502_ - The refactoring allows for the update of the _Summernote_ library. - A new structure was created 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. - The cleanup allowed us to remove some of the code that was in `web_editor` but only used in `website` or in `mass_mailing`. Some parts are still in `web_editor` but will be moved at a later time. - The refactoring also had to be done in order to create a set of unit tests. Each behavior can be tested, including the behaviors performed as a consequence of keyboard interactions (for instance: Enter, Tab...). - 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. A lot of tests are done, ensuring the consistency of outside behavior. - 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)` which 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)` which 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. **REMAINING KNOW ISSUES** These will be fixed in a subsequent commit. - A few committed changes made during the development of this refactoring were lost in the process and should be reapplied. - Some minor (mostly range) issues remain with Firefox. -- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr closes odoo/odoo#29775
Diffstat (limited to 'addons/web_editor/static/src/js/editor/rte.summernote.js')
-rw-r--r--addons/web_editor/static/src/js/editor/rte.summernote.js1274
1 files changed, 0 insertions, 1274 deletions
diff --git a/addons/web_editor/static/src/js/editor/rte.summernote.js b/addons/web_editor/static/src/js/editor/rte.summernote.js
deleted file mode 100644
index 62586a53b5c..00000000000
--- a/addons/web_editor/static/src/js/editor/rte.summernote.js
+++ /dev/null
@@ -1,1274 +0,0 @@
-odoo.define('web_editor.rte.summernote', function (require) {
-'use strict';
-
-var ajax = require('web.ajax');
-var Class = require('web.Class');
-var core = require('web.core');
-var ColorpickerDialog = require('web.colorpicker');
-var mixins = require('web.mixins');
-var base = require('web_editor.base');
-var weContext = require('web_editor.context');
-var rte = require('web_editor.rte');
-var weWidgets = require('web_editor.widget');
-
-var QWeb = core.qweb;
-var _t = core._t;
-
-ajax.jsonRpc('/web/dataset/call', 'call', {
- 'model': 'ir.ui.view',
- 'method': 'read_template',
- 'args': ['web_editor.colorpicker', weContext.get()]
-}).done(function (data) {
- QWeb.add_template(data);
-});
-
-// Summernote Lib (neek change to make accessible: method and object)
-var dom = $.summernote.core.dom;
-var range = $.summernote.core.range;
-var eventHandler = $.summernote.eventHandler;
-var renderer = $.summernote.renderer;
-
-var tplButton = renderer.getTemplate().button;
-var tplIconButton = renderer.getTemplate().iconButton;
-var tplDropdown = renderer.getTemplate().dropdown;
-
-function _rgbToHex(cssColor) {
- var rgba = cssColor.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/);
- if (!rgba) {
- return cssColor;
- }
- if (rgba[4]) {
- return cssColor;
- }
- var hex = ColorpickerDialog.prototype.convertRgbToHex(
- parseInt(rgba[1]),
- parseInt(rgba[2]),
- parseInt(rgba[3])
- );
- if (!hex) {
- return cssColor; // TODO handle error
- }
- return hex.hex.toUpperCase();
-}
-
-// Update and change the popovers content, and add history button
-var fn_createPalette = renderer.createPalette;
-renderer.createPalette = function ($container, options) {
- fn_createPalette.call(this, $container, options);
-
- if (!QWeb.has_template('web_editor.colorpicker')) {
- return;
- }
-
- var $clpicker = $(QWeb.render('web_editor.colorpicker'));
-
- var groups;
- if ($clpicker.is("colorpicker")) {
- groups = _.map($clpicker.find('[data-name="theme"]'), function (el) {
- return $(el).find("button").empty();
- });
- } else {
- groups = [$clpicker.find("button").empty()];
- }
-
- var html = "<h6 class='mt-2'>" + _t("Theme colors") + "</h6>" + _.map(groups, function ($group) {
- var $row = $("<div/>", {"class": "note-color-row mb8"}).append($group);
- var $after_breaks = $row.find(".o_small + :not(.o_small)");
- if ($after_breaks.length === 0) {
- $after_breaks = $row.find(":nth-child(8n+9)");
- }
- $after_breaks.addClass("o_clear");
- return $row[0].outerHTML;
- }).join("") + "<h6 class='mt-2'>" + _t("Common colors") + "</h6>";
- var $palettes = $container.find(".note-color .note-color-palette");
- $palettes.prepend(html);
-
- // Find the custom colors which are used in the page and add them to the color palette
- var colors = [];
- var $editable = window.__EditorMenuBar_$editable || $();
- _.each($editable.find('[style*="color"]'), function (element) {
- if (element.style.color) {
- colors.push(element.style.color);
- }
- if (element.style.backgroundColor) {
- colors.push(element.style.backgroundColor);
- }
- });
-
- var $customColorPalettes = $container.find('.note-color .note-custom-color-palette').append($('<div/>', {class: "note-color-row"}));
- var $customColorRows = $customColorPalettes.find('.note-color-row');
- _.each(_.uniq(colors), function (color) {
- var hexColor = _rgbToHex(color);
- if (_.indexOf(_.flatten(options.colors), hexColor) < 0) {
- // Create button for used custom color for backColor and foreColor both and add them into palette
- $customColorRows.append('<button type="button" class="o_custom_color" data-color="' + color + '" style="background-color:' + color + ';" />');
- }
- });
-
- $palettes.push.apply($palettes, $customColorPalettes);
-
- var $fore = $palettes.filter(":even").find("button:not(.note-color-btn)").addClass("note-color-btn");
- var $bg = $palettes.filter(":odd").find("button:not(.note-color-btn)").addClass("note-color-btn");
- $fore.each(function () {
- var $el = $(this);
- var className = $el.hasClass('o_custom_color') ? $el.data('color') : 'text-' + $el.data('color');
- $el.attr('data-event', 'foreColor').attr('data-value', className).addClass($el.hasClass('o_custom_color') ? '' : 'bg-' + $el.data('color'));
- });
- $bg.each(function () {
- var $el = $(this);
- var className = $el.hasClass('o_custom_color') ? $el.data('color') : 'bg-' + $el.data('color');
- $el.attr('data-event', 'backColor').attr('data-value', className).addClass($el.hasClass('o_custom_color') ? '' : className);
- });
-};
-
-var fn_tplPopovers = renderer.tplPopovers;
-renderer.tplPopovers = function (lang, options) {
- var $popover = $(fn_tplPopovers.call(this, lang, options));
-
- var $imagePopover = $popover.find('.note-image-popover');
- var $linkPopover = $popover.find('.note-link-popover');
- var $airPopover = $popover.find('.note-air-popover');
-
- //////////////// image popover
-
- // add center button for images
- $(tplIconButton('fa fa-align-center', {
- title: _t('Center'),
- event: 'floatMe',
- value: 'center'
- })).insertAfter($imagePopover.find('[data-event="floatMe"][data-value="left"]'));
- $imagePopover.find('button[data-event="removeMedia"]').parent().remove();
- $imagePopover.find('button[data-event="floatMe"][data-value="none"]').remove();
-
- // padding button
- var $padding = $('<div class="btn-group"/>');
- $padding.insertBefore($imagePopover.find('.btn-group:first'));
- var dropdown_content = [
- '<li><a class="dropdown-item" data-event="padding" href="#" data-value="">'+_t('None')+'</a></li>',
- '<li><a class="dropdown-item" data-event="padding" href="#" data-value="small">'+_t('Small')+'</a></li>',
- '<li><a class="dropdown-item" data-event="padding" href="#" data-value="medium">'+_t('Medium')+'</a></li>',
- '<li><a class="dropdown-item" data-event="padding" href="#" data-value="large">'+_t('Large')+'</a></li>',
- '<li><a class="dropdown-item" data-event="padding" href="#" data-value="xl">'+_t('Xl')+'</a></li>',
- ];
- $(tplIconButton('fa fa-plus-square-o', {
- title: _t('Padding'),
- dropdown: tplDropdown(dropdown_content)
- })).appendTo($padding);
-
- // circle, boxed... options became toggled
- $imagePopover.find('[data-event="imageShape"]:not([data-value])').remove();
- var $button = $(tplIconButton('fa fa-sun-o', {
- title: _t('Shadow'),
- event: 'imageShape',
- value: 'shadow'
- })).insertAfter($imagePopover.find('[data-event="imageShape"][data-value="rounded-circle"]'));
-
- // add spin for fa
- var $spin = $('<div class="btn-group d-none only_fa"/>').insertAfter($button.parent());
- $(tplIconButton('fa fa-refresh', {
- title: _t('Spin'),
- event: 'imageShape',
- value: 'fa-spin'
- })).appendTo($spin);
-
- // resize for fa
- var $resizefa = $('<div class="btn-group d-none only_fa"/>')
- .insertAfter($imagePopover.find('.btn-group:has([data-event="resize"])'));
- for (var size=1; size<=5; size++) {
- $(tplButton('<span class="note-fontsize-10">'+size+'x</span>', {
- title: size+"x",
- event: 'resizefa',
- value: size+''
- })).appendTo($resizefa);
- }
- var $colorfa = $airPopover.find('.note-color').clone();
- $colorfa.find(".dropdown-menu").css('min-width', '172px');
- $resizefa.after($colorfa);
-
- // show dialog box and delete
- var $imageprop = $('<div class="btn-group"/>');
- $imageprop.appendTo($imagePopover.find('.popover-body'));
- $(tplIconButton('fa fa-file-image-o', {
- title: _t('Edit'),
- event: 'showImageDialog'
- })).appendTo($imageprop);
- $(tplIconButton('fa fa-trash-o', {
- title: _t('Remove'),
- event: 'delete'
- })).appendTo($imageprop);
-
- $(tplIconButton('fa fa-crop', {
- title: _t('Crop Image'),
- event: 'cropImage',
- })).insertAfter($imagePopover.find('[data-event="imageShape"][data-value="img-thumbnail"]'));
-
- $imagePopover.find('.popover-body').append($airPopover.find(".note-history").clone());
-
- $imagePopover.find('[data-event="showImageDialog"]').before($airPopover.find('[data-event="showLinkDialog"]').clone());
-
- var $alt = $('<div class="btn-group"/>');
- $alt.appendTo($imagePopover.find('.popover-body'));
- $alt.append('<button class="btn btn-secondary" data-event="alt"><strong>' + _t('Description') + ': </strong><span class="o_image_alt"/></button>');
-
- //////////////// link popover
-
- $linkPopover.find('.popover-body').append($airPopover.find(".note-history").clone());
-
- $linkPopover.find('button[data-event="showLinkDialog"] i').attr("class", "fa fa-link");
- $linkPopover.find('button[data-event="unlink"]').before($airPopover.find('button[data-event="showImageDialog"]').clone());
-
- //////////////// text/air popover
-
- //// highlight the text format
- $airPopover.find('.note-style .dropdown-toggle').on('mousedown', function () {
- var $format = $airPopover.find('[data-event="formatBlock"]');
- var node = range.create().sc;
- var formats = $format.map(function () { return $(this).data("value"); }).get();
- while (node && (!node.tagName || (!node.tagName || formats.indexOf(node.tagName.toLowerCase()) === -1))) {
- node = node.parentNode;
- }
- $format.removeClass('active');
- $format.filter('[data-value="'+(node ? node.tagName.toLowerCase() : "p")+'"]')
- .addClass("active");
- });
-
- //////////////// tooltip
-
- setTimeout(function () {
- $airPopover.add($linkPopover).add($imagePopover).find("button")
- .tooltip('dispose')
- .tooltip({
- container: 'body',
- trigger: 'hover',
- placement: 'bottom'
- }).on('click', function () {$(this).tooltip('hide');});
- });
-
- return $popover;
-};
-
-var fn_boutton_update = eventHandler.modules.popover.button.update;
-eventHandler.modules.popover.button.update = function ($container, oStyle) {
- // stop animation when edit content
- var previous = $(".note-control-selection").data('target');
- if (previous) {
- var $previous = $(previous);
- $previous.css({"-webkit-animation-play-state": "", "animation-play-state": "", "-webkit-transition": "", "transition": "", "-webkit-animation": "", "animation": ""});
- $previous.find('.o_we_selected_image').addBack('.o_we_selected_image').removeClass('o_we_selected_image');
- }
- // end
-
- fn_boutton_update.call(this, $container, oStyle);
-
- $container.find('.note-color').removeClass('d-none');
-
- if (oStyle.image) {
- $container.find('[data-event]').removeClass("active");
-
- $container.find('a[data-event="padding"][data-value="small"]').toggleClass("active", $(oStyle.image).hasClass("padding-small"));
- $container.find('a[data-event="padding"][data-value="medium"]').toggleClass("active", $(oStyle.image).hasClass("padding-medium"));
- $container.find('a[data-event="padding"][data-value="large"]').toggleClass("active", $(oStyle.image).hasClass("padding-large"));
- $container.find('a[data-event="padding"][data-value="xl"]').toggleClass("active", $(oStyle.image).hasClass("padding-xl"));
- $container.find('a[data-event="padding"][data-value=""]').toggleClass("active", !$container.find('li a.active[data-event="padding"]').length);
-
- $(oStyle.image).addClass('o_we_selected_image');
-
- if (dom.isImgFont(oStyle.image)) {
- $container.find('[data-event="customColor"][data-value="foreColor"]').attr('data-color', $(oStyle.image).css('color'));
- $container.find('[data-event="customColor"][data-value="backColor"]').attr('data-color', $(oStyle.image).css('background-color'));
- $container.find('.note-fore-color-preview > button').css('border-bottom-color', $(oStyle.image).css('color'));
- $container.find('.note-back-color-preview > button').css('border-bottom-color', $(oStyle.image).css('background-color'));
-
- $container.find('.btn-group:not(.only_fa):has(button[data-event="resize"],button[data-value="img-thumbnail"])').addClass('d-none');
- $container.find('.only_fa').removeClass('d-none');
- $container.find('button[data-event="resizefa"][data-value="2"]').toggleClass("active", $(oStyle.image).hasClass("fa-2x"));
- $container.find('button[data-event="resizefa"][data-value="3"]').toggleClass("active", $(oStyle.image).hasClass("fa-3x"));
- $container.find('button[data-event="resizefa"][data-value="4"]').toggleClass("active", $(oStyle.image).hasClass("fa-4x"));
- $container.find('button[data-event="resizefa"][data-value="5"]').toggleClass("active", $(oStyle.image).hasClass("fa-5x"));
- $container.find('button[data-event="resizefa"][data-value="1"]').toggleClass("active", !$container.find('.active[data-event="resizefa"]').length);
-
- $container.find('button[data-event="imageShape"][data-value="fa-spin"]').toggleClass("active", $(oStyle.image).hasClass("fa-spin"));
- $container.find('button[data-event="imageShape"][data-value="shadow"]').toggleClass("active", $(oStyle.image).hasClass("shadow"));
- $container.find('.btn-group:has(button[data-event="imageShape"])').removeClass("d-none");
-
- } else {
- $container.find('.d-none:not(.only_fa, .note-recent-color)').removeClass('d-none');
- $container.find('.only_fa').addClass('d-none');
- var width = ($(oStyle.image).attr('style') || '').match(/(^|;|\s)width:\s*([0-9]+%)/);
- if (width) {
- width = width[2];
- }
- $container.find('button[data-event="resize"][data-value="auto"]').toggleClass("active", width !== "100%" && width !== "50%" && width !== "25%");
- $container.find('button[data-event="resize"][data-value="1"]').toggleClass("active", width === "100%");
- $container.find('button[data-event="resize"][data-value="0.5"]').toggleClass("active", width === "50%");
- $container.find('button[data-event="resize"][data-value="0.25"]').toggleClass("active", width === "25%");
-
- $container.find('button[data-event="imageShape"][data-value="shadow"]').toggleClass("active", $(oStyle.image).hasClass("shadow"));
-
- if (!$(oStyle.image).is("img")) {
- $container.find('.btn-group:has(button[data-event="imageShape"])').addClass('d-none');
- }
-
- $container.find('.note-color').addClass('d-none');
- }
-
- $container.find('button[data-event="floatMe"][data-value="left"]').toggleClass("active", $(oStyle.image).hasClass("float-left"));
- $container.find('button[data-event="floatMe"][data-value="center"]').toggleClass("active", $(oStyle.image).hasClass("d-block mx-auto"));
- $container.find('button[data-event="floatMe"][data-value="right"]').toggleClass("active", $(oStyle.image).hasClass("float-right"));
-
- $(oStyle.image).trigger('attributes_change');
- } else {
- $container.find('[data-event="customColor"][data-value="foreColor"]').attr('data-color', oStyle.color);
- $container.find('[data-event="customColor"][data-value="backColor"]').attr('data-color', oStyle['background-color']);
- $container.find('.note-fore-color-preview > button').css('border-bottom-color', oStyle.color);
- $container.find('.note-back-color-preview > button').css('border-bottom-color', oStyle['background-color']);
- }
-};
-
-var fn_popover_update = eventHandler.modules.popover.update;
-eventHandler.modules.popover.update = function ($popover, oStyle, isAirMode) {
- var $imagePopover = $popover.find('.note-image-popover');
- var $linkPopover = $popover.find('.note-link-popover');
- var $airPopover = $popover.find('.note-air-popover');
-
- fn_popover_update.call(this, $popover, oStyle, isAirMode);
-
- if (oStyle.image) {
- if (oStyle.image.parentNode.className.match(/(^|\s)media_iframe_video(\s|$)/i)) {
- oStyle.image = oStyle.image.parentNode;
- }
- var alt = $(oStyle.image).attr("alt");
-
- $imagePopover.find('.o_image_alt').text( (alt || "").replace(/&quot;/g, '"') ).parent().toggle(oStyle.image.tagName === "IMG");
- $imagePopover.show();
-
- // for video tag (non-void) we select the range over the tag,
- // for other media types we get the first descendant leaf element
- var target_node = oStyle.image;
- if (!oStyle.image.className.match(/(^|\s)media_iframe_video(\s|$)/i)) {
- target_node = dom.firstChild(target_node);
- }
- range.createFromNode(target_node).select();
- // save range on the editor so it is not lost if restored
- eventHandler.modules.editor.saveRange(dom.makeLayoutInfo(target_node).editable());
- } else {
- $(".note-control-selection").hide();
- }
-
- if (oStyle.image || (oStyle.range && (!oStyle.range.isCollapsed() || (oStyle.range.sc.tagName && !dom.isAnchor(oStyle.range.sc)))) || (oStyle.image && !$(oStyle.image).closest('a').length)) {
- $linkPopover.hide();
- oStyle.anchor = false;
- }
-
- if (oStyle.image || oStyle.anchor || (oStyle.range && !$(oStyle.range.sc).closest('.note-editable').length)) {
- $airPopover.hide();
- } else {
- $airPopover.show();
- }
-};
-
-var fn_handle_update = eventHandler.modules.handle.update;
-eventHandler.modules.handle.update = function ($handle, oStyle, isAirMode) {
- fn_handle_update.call(this, $handle, oStyle, isAirMode);
- if (oStyle.image) {
- $handle.find('.note-control-selection').hide();
- }
-};
-
-// Hack for image and link editor
-function getImgTarget($editable) {
- var $handle = $editable ? dom.makeLayoutInfo($editable).handle() : undefined;
- return $(".note-control-selection", $handle).data('target');
-}
-eventHandler.modules.editor.padding = function ($editable, sValue) {
- var $target = $(getImgTarget($editable));
- var paddings = "small medium large xl".split(/\s+/);
- $editable.data('NoteHistory').recordUndo();
- if (sValue.length) {
- paddings.splice(paddings.indexOf(sValue),1);
- $target.toggleClass('padding-'+sValue);
- }
- $target.removeClass("padding-" + paddings.join(" padding-"));
-};
-eventHandler.modules.editor.resize = function ($editable, sValue) {
- var $target = $(getImgTarget($editable));
- $editable.data('NoteHistory').recordUndo();
- var width = ($target.attr('style') || '').match(/(^|;|\s)width:\s*([0-9]+)%/);
- if (width) {
- width = width[2]/100;
- }
- $target.css('width', (width !== sValue && sValue !== "auto") ? (sValue * 100) + '%' : '');
-};
-eventHandler.modules.editor.resizefa = function ($editable, sValue) {
- var $target = $(getImgTarget($editable));
- $editable.data('NoteHistory').recordUndo();
- $target.attr('class', $target.attr('class').replace(/\s*fa-[0-9]+x/g, ''));
- if (+sValue > 1) {
- $target.addClass('fa-'+sValue+'x');
- }
-};
-eventHandler.modules.editor.floatMe = function ($editable, sValue) {
- var $target = $(getImgTarget($editable));
- $editable.data('NoteHistory').recordUndo();
- switch (sValue) {
- case 'center': $target.toggleClass('d-block mx-auto').removeClass('float-right float-left'); break;
- case 'left': $target.toggleClass('float-left').removeClass('float-right d-block mx-auto'); break;
- case 'right': $target.toggleClass('float-right').removeClass('float-left d-block mx-auto'); break;
- }
-};
-eventHandler.modules.editor.imageShape = function ($editable, sValue) {
- var $target = $(getImgTarget($editable));
- $editable.data('NoteHistory').recordUndo();
- $target.toggleClass(sValue);
-};
-
-eventHandler.modules.linkDialog.showLinkDialog = function ($editable, $dialog, linkInfo) {
- $editable.data('range').select();
- $editable.data('NoteHistory').recordUndo();
-
- var def = new $.Deferred();
- core.bus.trigger('link_dialog_demand', {
- $editable: $editable,
- linkInfo: linkInfo,
- onSave: function (linkInfo) {
- linkInfo.range.select();
- $editable.data('range', linkInfo.range);
- def.resolve(linkInfo);
- $editable.trigger('keyup');
- $('.note-popover .note-link-popover').show();
- },
- onCancel: def.reject.bind(def),
- });
- return def;
-};
-eventHandler.modules.imageDialog.showImageDialog = function ($editable) {
- var r = $editable.data('range');
- if (r.sc.tagName && r.sc.childNodes.length) {
- r.sc = r.sc.childNodes[r.so];
- }
- var media = $(r.sc).parents().addBack().filter(function (i, el) {
- return dom.isImg(el);
- })[0];
- core.bus.trigger('media_dialog_demand', {
- $editable: $editable,
- media: media,
- options: {
- lastFilters: ['background'],
- onUpload: $editable.data('callbacks').onUpload,
- noVideos: $editable.data('oe-model') === "mail.compose.message",
- },
- });
- return new $.Deferred().reject();
-};
-$.summernote.pluginEvents.alt = function (event, editor, layoutInfo, sorted) {
- var $editable = layoutInfo.editable();
- var $selection = layoutInfo.handle().find('.note-control-selection');
- core.bus.trigger('alt_dialog_demand', {
- $editable: $editable,
- media: $selection.data('target'),
- });
-};
-$.summernote.pluginEvents.customColor = function (event, editor, layoutInfo, customColor) {
- var defaultColor = event.target.dataset.color;
- core.bus.trigger('color_picker_dialog_demand', {
- color: defaultColor === 'rgba(0, 0, 0, 0)' ? 'rgb(255, 0, 0)' : defaultColor,
- onSave: function (color) {
- var $palettes = $(event.currentTarget).find('.note-custom-color-palette > .note-color-row')
- .append(('<button type="button" class="note-color-btn" data-value="' + color + '" style="background-color:' + color + ';" />'));
- $palettes.filter(':odd').find('button:not([data-event])').attr('data-event', 'backColor');
- $palettes.filter(':even').find('button:not([data-event])').attr('data-event', 'foreColor');
- if (customColor === 'foreColor') {
- $(event.currentTarget).find('.note-fore-color-preview > button').css('border-bottom-color', color);
- $.summernote.pluginEvents.foreColor(event, editor, layoutInfo, color);
- } else {
- $(event.currentTarget).find('.note-back-color-preview > button').css('border-bottom-color', color);
- $.summernote.pluginEvents.backColor(event, editor, layoutInfo, color);
- }
- }
- });
-};
-$.summernote.pluginEvents.cropImage = function (event, editor, layoutInfo, sorted) {
- var $editable = layoutInfo.editable();
- var $selection = layoutInfo.handle().find('.note-control-selection');
- core.bus.trigger('crop_image_dialog_demand', {
- $editable: $editable,
- media: $selection.data('target'),
- });
-};
-
-// Utils
-var fn_is_void = dom.isVoid || function () {};
-dom.isVoid = function (node) {
- return fn_is_void(node) || dom.isImgFont(node) || (node && node.className && node.className.match(/(^|\s)media_iframe_video(\s|$)/i));
-};
-var fn_is_img = dom.isImg || function () {};
-dom.isImg = function (node) {
- return fn_is_img(node) || dom.isImgFont(node) || (node && (node.nodeName === "IMG" || (node.className && node.className.match(/(^|\s)(media_iframe_video|o_image)(\s|$)/i)) ));
-};
-var fn_is_forbidden_node = dom.isForbiddenNode || function () {};
-dom.isForbiddenNode = function (node) {
- if (node.tagName === "BR") {
- return false;
- }
- return fn_is_forbidden_node(node) || $(node).is(".media_iframe_video");
-};
-var fn_is_img_font = dom.isImgFont || function () {};
-dom.isImgFont = function (node) {
- if (fn_is_img_font(node)) return true;
-
- var nodeName = node && node.nodeName.toUpperCase();
- var className = (node && node.className || "");
- if (node && (nodeName === "SPAN" || nodeName === "I") && className.length) {
- var classNames = className.split(/\s+/);
- for (var k=0; k<base.fontIcons.length; k++) {
- if (_.intersection(base.fontIcons[k].alias, classNames).length) {
- return true;
- }
- }
- }
- return false;
-};
-var fn_is_font = dom.isFont; // re-overwrite font to include theme icons
-dom.isFont = function (node) {
- return fn_is_font(node) || dom.isImgFont(node);
-};
-
-var fn_visible = $.summernote.pluginEvents.visible;
-$.summernote.pluginEvents.visible = function (event, editor, layoutInfo) {
- var res = fn_visible.apply(this, arguments);
- var rng = range.create();
- if (!rng) return res;
- var $node = $(dom.node(rng.sc));
- if (($node.is('[data-oe-type="html"]') || $node.is('[data-oe-field="arch"]')) &&
- $node.hasClass("o_editable") &&
- !$node[0].children.length &&
- "h1 h2 h3 h4 h5 h6 p b bold i u code sup strong small pre th td span label".toUpperCase().indexOf($node[0].nodeName) === -1) {
- var p = $('<p><br/></p>')[0];
- $node.append( p );
- range.createFromNode(p.firstChild).select();
- }
- return res;
-};
-
-function prettify_html(html) {
- html = html.trim();
- var result = '',
- level = 0,
- get_space = function (level) {
- var i = level, space = '';
- while (i--) space += ' ';
- return space;
- },
- reg = /^<\/?(a|span|font|u|em|i|strong|b)(\s|>)/i,
- inline_level = Infinity,
- tokens = _.compact(_.flatten(_.map(html.split(/</), function (value) {
- value = value.replace(/\s+/g, ' ').split(/>/);
- value[0] = /\S/.test(value[0]) ? '<' + value[0] + '>' : '';
- return value;
- })));
-
- // reduce => merge inline style + text
-
- for (var i = 0, l = tokens.length; i < l; i++) {
- var token = tokens[i];
- var inline_tag = reg.test(token);
- var inline = inline_tag || inline_level <= level;
-
- if (token[0] === '<' && token[1] === '/') {
- if (inline_tag && inline_level === level) {
- inline_level = Infinity;
- }
- level--;
- }
-
- if (!inline && !/\S/.test(token)) {
- continue;
- }
- if (!inline || (token[1] !== '/' && inline_level > level)) {
- result += get_space(level);
- }
-
- if (token[0] === '<' && token[1] !== '/') {
- level++;
- if (inline_tag && inline_level > level) {
- inline_level = level;
- }
- }
-
- if (token.match(/^<(img|hr|br)/)) {
- level--;
- }
-
- // don't trim inline content (which could change appearance)
- if (!inline) {
- token = token.trim();
- }
-
- result += token.replace(/\s+/, ' ');
-
- if (inline_level > level) {
- result += '\n';
- }
- }
- return result;
-}
-
-/*
- * This override when clicking on the 'Code View' button has two aims:
- *
- * - have our own code view implementation for FieldTextHtml
- * - add an 'enable' paramater to call the function directly and allow us to
- * disable (false) or enable (true) the code view mode.
- */
-$.summernote.pluginEvents.codeview = function (event, editor, layoutInfo, enable) {
- if (layoutInfo === undefined) {
- return;
- }
- if (layoutInfo.toolbar) {
- // if editor inline (FieldTextHtmlSimple)
- var is_activated = $.summernote.eventHandler.modules.codeview.isActivated(layoutInfo);
- if (is_activated === enable) {
- return;
- }
- return eventHandler.modules.codeview.toggle(layoutInfo);
- } else {
- // if editor iframe (FieldTextHtml)
- var $editor = layoutInfo.editor();
- var $textarea = $editor.prev('textarea');
- if ($textarea.is('textarea') === enable) {
- return;
- }
-
- if (!$textarea.length) {
- // init and create texarea
- var html = prettify_html($editor.prop("innerHTML"));
- $editor.parent().css({
- 'position': 'absolute',
- 'top': 0,
- 'bottom': 0,
- 'left': 0,
- 'right': 0
- });
- $textarea = $('<textarea/>').css({
- 'margin': '0 -4px',
- 'padding': '0 4px',
- 'border': 0,
- 'top': '51px',
- 'left': '620px',
- 'width': '100%',
- 'font-family': 'sans-serif',
- 'font-size': '13px',
- 'height': '98%',
- 'white-space': 'pre',
- 'word-wrap': 'normal'
- }).val(html).data('init', html);
- $editor.before($textarea);
- $editor.hide();
- } else {
- // save changes
- $editor.prop('innerHTML', $textarea.val().replace(/\s*\n\s*/g, '')).trigger('content_changed');
- $textarea.remove();
- $editor.show();
- }
- }
-};
-
-// Fix ie and re-range to don't break snippet
-var last_div;
-var last_div_change;
-var last_editable;
-var initial_data = {};
-function reRangeSelectKey(event) {
- initial_data.range = null;
- if (event.shiftKey && event.keyCode >= 37 && event.keyCode <= 40 && !$(event.target).is("input, textarea, select")) {
- var r = range.create();
- if (r) {
- var rng = r.reRange(event.keyCode <= 38);
- if (r !== rng) {
- rng.select();
- }
- }
- }
-}
-function reRangeSelect(event, dx, dy) {
- var r = range.create();
- if (!r || r.isCollapsed()) return;
-
- // check if the user move the caret on up or down
- var data = r.reRange(dy < 0 || (dy === 0 && dx < 0));
-
- if (data.sc !== r.sc || data.so !== r.so || data.ec !== r.ec || data.eo !== r.eo) {
- setTimeout(function () {
- data.select();
- $(data.sc.parentNode).closest('.note-popover');
- },0);
- }
-
- $(data.sc).closest('.o_editable').data('range', r);
- return r;
-}
-function summernote_mouseup(event) {
- if ($(event.target).closest("#web_editor-top-navbar, .note-popover").length) {
- return;
- }
- // don't rerange if simple click
- if (initial_data.event) {
- var dx = event.clientX - (event.shiftKey && initial_data.rect ? initial_data.rect.left : initial_data.event.clientX);
- var dy = event.clientY - (event.shiftKey && initial_data.rect ? initial_data.rect.top : initial_data.event.clientY);
- if (10 < Math.pow(dx, 2)+Math.pow(dy, 2)) {
- reRangeSelect(event, dx, dy);
- }
- }
-
- if (!$(event.target).closest(".o_editable").length) {
- return;
- }
- if (!initial_data.range || !event.shiftKey) {
- setTimeout(function () {
- initial_data.range = range.create();
- },0);
- }
-}
-var remember_selection;
-function summernote_mousedown(event) {
- rte.history.splitNext();
-
- var $editable = $(event.target).closest(".o_editable, .note-editor");
- var r;
-
- if (document.documentMode) {
- summernote_ie_fix(event, function (node) { return node.tagName === "DIV" || node.tagName === "IMG" || (node.dataset && node.dataset.oeModel); });
- } else if (last_div && event.target !== last_div) {
- if (last_div.tagName === "A") {
- summernote_ie_fix(event, function (node) { return node.dataset && node.dataset.oeModel; });
- } else if ($editable.length) {
- if (summernote_ie_fix(event, function (node) { return node.tagName === "A"; })) {
- r = range.create();
- r.select();
- }
- }
- }
-
- // restore range if range lost after clicking on non-editable area
- try {
- r = range.create();
- } catch (e) {
- // If this code is running inside an iframe-editor and that the range
- // is outside of this iframe, this will fail as the iframe does not have
- // the permission to check the outside content this way. In that case,
- // we simply ignore the exception as it is as if there was no range.
- return;
- }
- var editables = $(".o_editable[contenteditable], .note-editable[contenteditable]");
- var r_editable = editables.has((r||{}).sc).addBack(editables.filter((r||{}).sc));
- if (!r_editable.closest('.note-editor').is($editable) && !r_editable.filter('.o_editable').is(editables)) {
- var saved_editable = editables.has((remember_selection||{}).sc);
- if ($editable.length && !saved_editable.closest('.o_editable, .note-editor').is($editable)) {
- remember_selection = range.create(dom.firstChild($editable[0]), 0);
- } else if (!saved_editable.length) {
- remember_selection = undefined;
- }
- if (remember_selection) {
- try {
- remember_selection.select();
- } catch (e) {
- console.warn(e);
- }
- }
- } else if (r_editable.length) {
- remember_selection = r;
- }
-
- initial_data.event = event;
-
- // keep selection when click with shift
- if (event.shiftKey && $editable.length) {
- if (initial_data.range) {
- initial_data.range.select();
- }
- var rect = r && r.getClientRects();
- initial_data.rect = rect && rect.length ? rect[0] : { top: 0, left: 0 };
- }
-}
-
-function summernote_ie_fix(event, pred) {
- var editable;
- var div;
- var node = event.target;
- while (node.parentNode) {
- if (!div && pred(node)) {
- div = node;
- }
- if (last_div !== node && (node.getAttribute('contentEditable')==='false' || node.className && (node.className.indexOf('o_not_editable') !== -1))) {
- break;
- }
- if (node.className && node.className.indexOf('o_editable') !== -1) {
- if (!div) {
- div = node;
- }
- editable = node;
- break;
- }
- node = node.parentNode;
- }
-
- if (!editable) {
- $(last_div_change).removeAttr("contentEditable").removeProp("contentEditable");
- $(last_editable).attr("contentEditable", "true").prop("contentEditable", "true");
- last_div_change = null;
- last_editable = null;
- return;
- }
-
- if (div === last_div) {
- return;
- }
-
- last_div = div;
-
- $(last_div_change).removeAttr("contentEditable").removeProp("contentEditable");
-
- if (last_editable !== editable) {
- if ($(editable).is("[contentEditable='true']")) {
- $(editable).removeAttr("contentEditable").removeProp("contentEditable");
- last_editable = editable;
- } else {
- last_editable = null;
- }
- }
- if (!$(div).attr("contentEditable") && !$(div).is("[data-oe-type='many2one'], [data-oe-type='contact']")) {
- $(div).attr("contentEditable", "true").prop("contentEditable", "true");
- last_div_change = div;
- } else {
- last_div_change = null;
- }
- return editable !== div ? div : null;
-}
-
-var fn_attach = eventHandler.attach;
-eventHandler.attach = function (oLayoutInfo, options) {
- fn_attach.call(this, oLayoutInfo, options);
-
- oLayoutInfo.editor().on('dragstart', 'img', function (e) { e.preventDefault(); });
- $(document).on('mousedown', summernote_mousedown).on('mouseup', summernote_mouseup);
- oLayoutInfo.editor().off('click').on('click', function (e) {e.preventDefault();}); // if the content editable is a link
-
- /**
- * Open Media Dialog on double click on an image/video/icon.
- * Shows a tooltip on click to say to the user he can double click.
- */
- create_dblclick_feature("img, .media_iframe_video, i.fa, span.fa, a.o_image", function () {
- eventHandler.modules.imageDialog.show(oLayoutInfo);
- });
-
- /**
- * Open Link Dialog on double click on a link/button.
- * Shows a tooltip on click to say to the user he can double click.
- */
- create_dblclick_feature("a[href], a.btn, button.btn", function () {
- eventHandler.modules.linkDialog.show(oLayoutInfo);
- });
-
- oLayoutInfo.editable().on('mousedown', function (e) {
- if (dom.isImg(e.target) && dom.isContentEditable(e.target)) {
- range.createFromNode(e.target).select();
- }
- });
- $(document).on("keyup", reRangeSelectKey);
-
- var clone_data = false;
-
- if (options.model) {
- oLayoutInfo.editable().data({'oe-model': options.model, 'oe-id': options.id});
- }
- if (options.getMediaDomain) {
- oLayoutInfo.editable().data('oe-media-domain', options.getMediaDomain);
- }
-
- var $node = oLayoutInfo.editor();
- if ($node.data('oe-model') || $node.data('oe-translation-id')) {
- $node.on('content_changed', function () {
- var $nodes = $('[data-oe-model], [data-oe-translation-id]')
- .filter(function () { return this !== $node[0];});
-
- if ($node.data('oe-model')) {
- $nodes = $nodes.filter('[data-oe-model="'+$node.data('oe-model')+'"]')
- .filter('[data-oe-id="'+$node.data('oe-id')+'"]')
- .filter('[data-oe-field="'+$node.data('oe-field')+'"]');
- }
- if ($node.data('oe-translation-id')) $nodes = $nodes.filter('[data-oe-translation-id="'+$node.data('oe-translation-id')+'"]');
- if ($node.data('oe-type')) $nodes = $nodes.filter('[data-oe-type="'+$node.data('oe-type')+'"]');
- if ($node.data('oe-expression')) $nodes = $nodes.filter('[data-oe-expression="'+$node.data('oe-expression')+'"]');
- if ($node.data('oe-xpath')) $nodes = $nodes.filter('[data-oe-xpath="'+$node.data('oe-xpath')+'"]');
- if ($node.data('oe-contact-options')) $nodes = $nodes.filter('[data-oe-contact-options="'+$node.data('oe-contact-options')+'"]');
-
- var nodes = $node.get();
-
- if ($node.data('oe-type') === "many2one") {
- $nodes = $nodes.add($('[data-oe-model]')
- .filter(function () { return this !== $node[0] && nodes.indexOf(this) === -1; })
- .filter('[data-oe-many2one-model="'+$node.data('oe-many2one-model')+'"]')
- .filter('[data-oe-many2one-id="'+$node.data('oe-many2one-id')+'"]')
- .filter('[data-oe-type="many2one"]'));
-
- $nodes = $nodes.add($('[data-oe-model]')
- .filter(function () { return this !== $node[0] && nodes.indexOf(this) === -1; })
- .filter('[data-oe-model="'+$node.data('oe-many2one-model')+'"]')
- .filter('[data-oe-id="'+$node.data('oe-many2one-id')+'"]')
- .filter('[data-oe-field="name"]'));
- }
-
- if (!clone_data) {
- clone_data = true;
- $nodes.html(this.innerHTML);
- clone_data = false;
- }
- });
- }
-
- var custom_toolbar = oLayoutInfo.toolbar ? oLayoutInfo.toolbar() : undefined;
- var $toolbar = $(oLayoutInfo.popover()).add(custom_toolbar);
- $('button[data-event="undo"], button[data-event="redo"]', $toolbar).attr('disabled', true);
-
- $(oLayoutInfo.editor())
- .add(oLayoutInfo.handle())
- .add(oLayoutInfo.popover())
- .add(custom_toolbar)
- .on('click content_changed', function () {
- $('button[data-event="undo"]', $toolbar).attr('disabled', !oLayoutInfo.editable().data('NoteHistory').hasUndo());
- $('button[data-event="redo"]', $toolbar).attr('disabled', !oLayoutInfo.editable().data('NoteHistory').hasRedo());
- });
-
- function create_dblclick_feature(selector, callback) {
- var show_tooltip = true;
-
- oLayoutInfo.editor().on("dblclick", selector, function (e) {
- var $target = $(e.target);
- if (!dom.isContentEditable($target)) {
- // Prevent edition of non editable parts
- return;
- }
-
- show_tooltip = false;
- callback();
- e.stopImmediatePropagation();
- });
-
- oLayoutInfo.editor().on("click", selector, function (e) {
- var $target = $(e.target);
- if (!dom.isContentEditable($target)) {
- // Prevent edition of non editable parts
- return;
- }
-
- show_tooltip = true;
- setTimeout(function () {
- if (!show_tooltip) return;
- $target.tooltip({title: _t('Double-click to edit'), trigger: 'manuel', container: 'body'}).tooltip('show');
- setTimeout(function () {
- $target.tooltip('dispose');
- }, 800);
- }, 400);
- });
- }
-};
-var fn_detach = eventHandler.detach;
-eventHandler.detach = function (oLayoutInfo, options) {
- fn_detach.call(this, oLayoutInfo, options);
- oLayoutInfo.editable().off('mousedown');
- oLayoutInfo.editor().off("dragstart");
- oLayoutInfo.editor().off('click');
- $(document).off('mousedown', summernote_mousedown);
- $(document).off('mouseup', summernote_mouseup);
- oLayoutInfo.editor().off("dblclick");
- $(document).off("keyup", reRangeSelectKey);
-};
-
-// Translation for odoo
-$.summernote.lang.odoo = {
- font: {
- bold: _t('Bold'),
- italic: _t('Italic'),
- underline: _t('Underline'),
- strikethrough: _t('Strikethrough'),
- subscript: _t('Subscript'),
- superscript: _t('Superscript'),
- clear: _t('Remove Font Style'),
- height: _t('Line Height'),
- name: _t('Font Family'),
- size: _t('Font Size')
- },
- image: {
- image: _t('File / Image'),
- insert: _t('Insert Image'),
- resizeFull: _t('Resize Full'),
- resizeHalf: _t('Resize Half'),
- resizeQuarter: _t('Resize Quarter'),
- floatLeft: _t('Float Left'),
- floatRight: _t('Float Right'),
- floatNone: _t('Float None'),
- dragImageHere: _t('Drag an image here'),
- selectFromFiles: _t('Select from files'),
- url: _t('Image URL'),
- remove: _t('Remove Image')
- },
- link: {
- link: _t('Link'),
- insert: _t('Insert Link'),
- unlink: _t('Unlink'),
- edit: _t('Edit'),
- textToDisplay: _t('Text to display'),
- url: _t('To what URL should this link go?'),
- openInNewWindow: _t('Open in new window')
- },
- video: {
- video: _t('Video'),
- videoLink: _t('Video Link'),
- insert: _t('Insert Video'),
- url: _t('Video URL?'),
- providers: _t('(YouTube, Vimeo, Vine, Instagram, DailyMotion or Youku)')
- },
- table: {
- table: _t('Table')
- },
- hr: {
- insert: _t('Insert Horizontal Rule')
- },
- style: {
- style: _t('Style'),
- normal: _t('Normal'),
- blockquote: _t('Quote'),
- pre: _t('Code'),
- small: _t('Small'),
- h1: _t('Header 1'),
- h2: _t('Header 2'),
- h3: _t('Header 3'),
- h4: _t('Header 4'),
- h5: _t('Header 5'),
- h6: _t('Header 6')
- },
- lists: {
- unordered: _t('Unordered list'),
- ordered: _t('Ordered list')
- },
- options: {
- help: _t('Help'),
- fullscreen: _t('Full Screen'),
- codeview: _t('Code View')
- },
- paragraph: {
- paragraph: _t('Paragraph'),
- outdent: _t('Outdent'),
- indent: _t('Indent'),
- left: _t('Align left'),
- center: _t('Align center'),
- right: _t('Align right'),
- justify: _t('Justify full')
- },
- color: {
- custom: _t('Custom Color'),
- background: _t('Background Color'),
- foreground: _t('Font Color'),
- transparent: _t('Transparent'),
- setTransparent: _t('None'),
- },
- shortcut: {
- shortcuts: _t('Keyboard shortcuts'),
- close: _t('Close'),
- textFormatting: _t('Text formatting'),
- action: _t('Action'),
- paragraphFormatting: _t('Paragraph formatting'),
- documentStyle: _t('Document Style')
- },
- history: {
- undo: _t('Undo'),
- redo: _t('Redo')
- }
-};
-
-//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-
-/**
- * @todo get rid of this. This has been implemented as a fix to be able to
- * instantiate media, link and alt dialogs outside the main editor: in the
- * simple HTML fields and forum textarea.
- */
-var SummernoteManager = Class.extend(mixins.EventDispatcherMixin, {
- /**
- * @constructor
- */
- init: function (parent) {
- mixins.EventDispatcherMixin.init.call(this);
- this.setParent(parent);
-
- core.bus.on('alt_dialog_demand', this, this._onAltDialogDemand);
- core.bus.on('color_picker_dialog_demand', this, this._onColorPickerDialogDemand);
- core.bus.on('crop_image_dialog_demand', this, this._onCropImageDialogDemand);
- core.bus.on('link_dialog_demand', this, this._onLinkDialogDemand);
- core.bus.on('media_dialog_demand', this, this._onMediaDialogDemand);
- },
- /**
- * @override
- */
- destroy: function () {
- mixins.EventDispatcherMixin.destroy.call(this);
-
- core.bus.off('alt_dialog_demand', this, this._onAltDialogDemand);
- core.bus.off('color_picker_dialog_demand', this, this._onColorPickerDialogDemand);
- core.bus.off('crop_image_dialog_demand', this, this._onCropImageDialogDemand);
- core.bus.off('link_dialog_demand', this, this._onLinkDialogDemand);
- core.bus.off('media_dialog_demand', this, this._onMediaDialogDemand);
- },
-
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
-
- /**
- * Called when a demand to open a alt dialog is received on the bus.
- *
- * @private
- * @param {Object} data
- */
- _onAltDialogDemand: function (data) {
- if (data.__alreadyDone) {
- return;
- }
- data.__alreadyDone = true;
- var altDialog = new weWidgets.AltDialog(this,
- data.options || {},
- data.$editable,
- data.media
- );
- if (data.onSave) {
- altDialog.on('save', this, data.onSave);
- }
- if (data.onCancel) {
- altDialog.on('cancel', this, data.onCancel);
- }
- altDialog.open();
- },
-/**
- * Called when a demand to open a color picker dialog is received on the bus.
- *
- * @private
- * @param {Object} data
- */
- _onColorPickerDialogDemand: function (data) {
- if (data.__alreadyDone) {
- return;
- }
- data.__alreadyDone = true;
- var colorpicker = new ColorpickerDialog(this, {
- defaultColor: data.color,
- });
- if (data.onSave) {
- colorpicker.on('colorpicker:saved', this, function (ev) {
- data.onSave(ev.data.cssColor);
- });
- }
- colorpicker.open();
- },
- /**
- * Called when a demand to open a crop dialog is received on the bus.
- *
- * @private
- * @param {Object} data
- */
- _onCropImageDialogDemand: function (data) {
- if (data.__alreadyDone) {
- return;
- }
- data.__alreadyDone = true;
- var cropImageDialog = new weWidgets.CropImageDialog(this,
- _.extend({
- res_model: data.$editable.data('oe-model'),
- res_id: data.$editable.data('oe-id'),
- }, data.options || {}),
- data.$editable,
- data.media
- );
- if (data.onSave) {
- cropImageDialog.on('save', this, data.onSave);
- }
- if (data.onCancel) {
- cropImageDialog.on('cancel', this, data.onCancel);
- }
- cropImageDialog.open();
- },
- /**
- * Called when a demand to open a link dialog is received on the bus.
- *
- * @private
- * @param {Object} data
- */
- _onLinkDialogDemand: function (data) {
- if (data.__alreadyDone) {
- return;
- }
- data.__alreadyDone = true;
- var linkDialog = new weWidgets.LinkDialog(this,
- data.options || {},
- data.$editable,
- data.linkInfo
- );
- if (data.onSave) {
- linkDialog.on('save', this, data.onSave);
- }
- if (data.onCancel) {
- linkDialog.on('cancel', this, data.onCancel);
- }
- linkDialog.open();
- },
- /**
- * Called when a demand to open a media dialog is received on the bus.
- *
- * @private
- * @param {Object} data
- */
- _onMediaDialogDemand: function (data) {
- if (data.__alreadyDone) {
- return;
- }
- data.__alreadyDone = true;
-
- var mediaDialog = new weWidgets.MediaDialog(this,
- _.extend({
- res_model: data.$editable.data('oe-model'),
- res_id: data.$editable.data('oe-id'),
- domain: data.$editable.data('oe-media-domain'),
- }, data.options),
- data.$editable,
- data.media
- );
- if (data.onSave) {
- mediaDialog.on('save', this, data.onSave);
- }
- if (data.onCancel) {
- mediaDialog.on('cancel', this, data.onCancel);
- }
- mediaDialog.open();
- },
-});
-/**
- * @todo cannot do this without include because it would make a loop in the
- * JS module dependencies otherwise.
- */
-rte.Class.include({
- /**
- * @override
- */
- start: function () {
- this._summernoteManager = new SummernoteManager(this);
- return this._super.apply(this, arguments);
- },
- /**
- * @override
- */
- cancel: function () {
- this._super.apply(this, arguments);
- this._summernoteManager.destroy();
- },
-});
-return SummernoteManager;
-});