diff options
Diffstat (limited to 'addons/web_editor/static/src/js/snippets.editor.js')
| -rw-r--r-- | addons/web_editor/static/src/js/snippets.editor.js | 1154 |
1 files changed, 0 insertions, 1154 deletions
diff --git a/addons/web_editor/static/src/js/snippets.editor.js b/addons/web_editor/static/src/js/snippets.editor.js deleted file mode 100644 index a0bfb8b300c..00000000000 --- a/addons/web_editor/static/src/js/snippets.editor.js +++ /dev/null @@ -1,1154 +0,0 @@ -odoo.define('web_editor.snippet.editor', function (require) { -'use strict'; - -var Class = require('web.Class'); -var ajax = require('web.ajax'); -var core = require('web.core'); -var dom = require('web.dom'); -var Widget = require('web.Widget'); -var editor = require('web_editor.editor'); -var animation = require('web_editor.snippets.animation'); -var options = require('web_editor.snippets.options'); - -var qweb = core.qweb; -var _t = core._t; - -ajax.loadXML('/web_editor/static/src/xml/snippets.xml', qweb); - -var data = {}; - -/* ----- SNIPPET SELECTOR ---- */ - -data.globalSelector = { - closest: function () { return $(); }, - all: function () { return $(); }, - is: function () { return false; }, -}; - -/** - * Snippet editor main class. - * Management of drag&drop and focus/blur of snippets. - * Previously named "BuildingBlock". - */ -data.Class = Widget.extend({ - id: "oe_snippets", - activeSnippets: [], - init: function (parent, $editable) { - this.$editable = $editable; - - this._super.apply(this, arguments); - if(!$('#oe_manipulators').length) { - $("<div/>", {id: "oe_manipulators", 'class': "o_css_editor"}).appendTo('body'); - } - this.$active_snipped_id = false; - this.snippets = []; - - data.instance = this; - }, - start: function () { - var self = this; - - $(window).resize(function () { - _.defer(function () { $(document).click(); }); - }); - - this.fetch_snippet_templates(); - this.bind_snippet_click_editor(); - - $(document).on('click', '.dropdown-submenu a[tabindex]', function (e) { - e.preventDefault(); - }); - - var _isNotBreakable = $.summernote.core.dom.isNotBreakable; - $.summernote.core.dom.isNotBreakable = function (node) { - return _isNotBreakable(node) || $(node).is('div') || data.globalSelector.is($(node)); - }; - - $(window).on('resize', function () { - if (self.$active_snipped_id && self.$active_snipped_id.data("snippet-editor")) { - self.cover_target(self.$active_snipped_id.data("snippet-editor").$overlay, self.$active_snipped_id); - } - }); - - $(document).on('mousemove', function () { - if (self.$active_snipped_id && self.$active_snipped_id.data("snippet-editor")) { - self.$active_snipped_id.data("snippet-editor").$overlay.removeClass('o_keypress'); - } - }); - $(document).on('keydown', function (event) { - if (self.$active_snipped_id && self.$active_snipped_id.data("snippet-editor")) { - self.$active_snipped_id.data("snippet-editor").$overlay.addClass('o_keypress'); - } - if ((event.metaKey || (event.ctrlKey && !event.altKey)) && event.shiftKey && event.keyCode >= 48 && event.keyCode <= 57) { - self.$('.scroll:first > ul li:eq('+(event.keyCode-49)+') a').trigger("click"); - event.preventDefault(); - } - }); - }, - - _get_snippet_url: function () { - return '/web_editor/snippets'; - }, - _add_check_selector : function (selector, no_check, is_children) { - var self = this; - selector = selector.split(/\s*,/).join(":not(.o_snippet_not_selectable), ") + ":not(.o_snippet_not_selectable)"; - - if (no_check) { - return { - closest: function ($from, parentNode) { - return $from.closest(selector, parentNode); - }, - all: function ($from) { - return $from ? dom.cssFind($from, selector) : $(selector); - }, - is: function ($from) { - return $from.is(selector); - } - }; - } else { - selector = selector.split(/\s*,/).join(":o_editable, ") + ":o_editable"; - return { - closest: function ($from, parentNode) { - var parents = self.$editable.get(); - return $from.closest(selector, parentNode).filter(function () { - var node = this; - while (node.parentNode) { - if (parents.indexOf(node)!==-1) { - return true; - } - node = node.parentNode; - } - return false; - }); - }, - all: is_children ? function ($from) { - return dom.cssFind($from || self.$editable, selector); - } : function ($from) { - $from = $from || self.$editable; - return $from.filter(selector).add(dom.cssFind($from, selector)); - }, - is: function ($from) { - return $from.is(selector); - } - }; - } - }, - - fetch_snippet_templates: function () { - var self = this; - var url = this._get_snippet_url(); - if (!url || !url.length) { - this.$el.detach(); - return; - } - return ajax.jsonRpc(url, 'call', {}).then(function (html) { - self.compute_snippet_templates(html); - self.trigger("snippets:ready"); - }, function () { - console.warn('Snippets template not found:', url); - }); - }, - compute_snippet_templates: function (html) { - var self = this; - var $html = $(html); - var $scroll = $html.siblings("#o_scroll"); - - if (!$scroll.length) { - throw new Error("Wrong snippets xml definition"); - } - - // t-snippet - $html.find('[data-oe-type="snippet"]').each(function () { - $(this).children().attr('data-oe-type', "snippet").attr('data-oe-thumbnail', $(this).data('oe-thumbnail')); - }); - // end - - self.templateOptions = []; - var selector = []; - var $styles = $html.find("[data-js], [data-selector]"); - $styles.each(function () { - var $style = $(this); - var no_check = $style.data('no-check'); - var option_id = $style.data('js'); - var option = { - 'option' : option_id, - 'base_selector': $style.data('selector'), - 'selector': self._add_check_selector($style.data('selector'), no_check), - '$el': $style, - 'drop-near': $style.data('drop-near') && self._add_check_selector($style.data('drop-near'), no_check, true), - 'drop-in': $style.data('drop-in') && self._add_check_selector($style.data('drop-in'), no_check), - 'data': $style.data() - }; - self.templateOptions.push(option); - selector.push(option.selector); - }); - - $styles.addClass("hidden"); - data.globalSelector.closest = function ($from) { - var $temp; - var $target; - var len = selector.length; - for (var i = 0; i<len; i++) { - $temp = selector[i].closest($from, $target && $target[0]); - if (!$target || $temp.length) { - $target = $temp; - } - } - return $target; - }; - data.globalSelector.all = function ($from) { - var $target; - var len = selector.length; - for (var i = 0; i<len; i++) { - if (!$target) $target = selector[i].all($from); - else $target = $target.add(selector[i].all($from)); - } - return $target; - }; - data.globalSelector.is = function ($from) { - var len = selector.length; - for (var i = 0; i<len; i++) { - if (selector[i].is($from)) { - return true; - } - } - return false; - }; - - var number = 0; - - // oe_snippet_body - self.$snippets = $scroll.find(".o_panel_body").children() - .addClass("oe_snippet") - .each(function () { - var $snippet = $(this); - if (!$('.oe_snippet_thumbnail', this).size()) { - var $div = $( - '<div class="oe_snippet_thumbnail">'+ - '<div class="oe_snippet_thumbnail_img"/>'+ - '<span class="oe_snippet_thumbnail_title"></span>'+ - '</div>'); - $div.find('span').text($snippet.attr("name")); - $snippet.prepend($div); - - // from t-snippet - var thumbnail = $("[data-oe-thumbnail]", this).data("oe-thumbnail"); - if (thumbnail) { - $div.find('.oe_snippet_thumbnail_img').css('background-image', 'url(' + thumbnail + ')'); - } - // end - - var moduleID = $snippet.data('moduleId'); - if (moduleID) { - $snippet.addClass('o_snippet_install'); - var $installBtn = $('<a/>', { - class: 'btn btn-primary btn-sm o_install_btn', - target: '_blank', - href: '/web#id=' + moduleID + '&view_type=form&model=ir.module.module&action=base.open_module_tree', - text: _t("Install"), - }); - $div.append($installBtn); - } - } - if (!$snippet.data("selector")) { - $("> *:not(.oe_snippet_thumbnail)", this).addClass('oe_snippet_body'); - } - number++; - }) - .not('[data-module-id]'); - - // hide scroll if no snippets defined - if (!number) { - this.$el.detach(); - } - $("body").toggleClass("editor_has_snippets", !!number); - - // select all default text to edit (if snippet default text) - this.add_default_snippet_text_classes(); - $(document).on("click", ".o_default_snippet_text", function (event) { - $(event.target).selectContent(); - }); - $(document).on("keyup", function (event) { - var r = $.summernote.core.range.create(); - $(r && r.sc).closest(".o_default_snippet_text").removeClass("o_default_snippet_text"); - }); - - // clean t-oe - $html.find('[data-oe-model], [data-oe-type]').each(function () { - for (var k=0; k<this.attributes.length; k++) { - if (this.attributes[k].name.indexOf('data-oe-') === 0) { - $(this).removeAttr(this.attributes[k].name); - k--; - } - } - }); - - $html.find('.o_not_editable').attr("contentEditable", false); - - this.$el.html($html); - - self.make_snippet_draggable(self.$snippets); - this.associate_snippet_names(this.$snippets); - - this.show_blocks(); - this.$el.on("snippet-dropped snippet-removed", this.show_blocks.bind(this)); - }, - - associate_snippet_names: function ($snippets) { - _.each($snippets, function (snippet) { - var $snippet = $(snippet); - var $sbody = $snippet.find(".oe_snippet_body"); - var snippet_classes = $sbody.attr("class").match(/s_[^ ]+/g); - if (snippet_classes && snippet_classes.length) { - snippet_classes = snippet_classes.join("."); - } - $("#wrapwrap ." + snippet_classes).data("name", $snippet.find(".oe_snippet_thumbnail_title").text()); - }); - }, - - add_default_snippet_text_classes: function ($in) { - if ($in === undefined) { - $in = this.$snippets.find(".oe_snippet_body"); - } - - $in.find("*").addBack() - .contents() - .filter(function () { - return this.nodeType === 3 && this.textContent.match(/\S/); - }).parent().addClass("o_default_snippet_text"); - }, - - cover_target: function ($el, $target) { - if ($el.data('not-cover_target')) { - return; - } - var pos = $target.offset(); - var mt = parseInt($target.css("margin-top") || 0); - $el.css({ - width: $target.outerWidth(), - left: pos.left, - top: pos.top - mt, - }); - $el.find('.oe_handles').css({ - height: $target.outerHeight(true), - }); - - $el.toggleClass('o_top_cover', pos.top <= (this.$('#o_scroll').position().top + 15)); - }, - - show_blocks: function () { - var self = this; - var cache = {}; - this.$snippets.each(function () { - var $snippet = $(this); - var $snippet_body = $snippet.find(".oe_snippet_body"); - - var check = false; - _.each(self.templateOptions, function (option, k) { - if (check || !$snippet_body.is(option.base_selector)) return; - - cache[k] = cache[k] || { - 'drop-near': option['drop-near'] ? option['drop-near'].all().length : 0, - 'drop-in': option['drop-in'] ? option['drop-in'].all().length : 0 - }; - check = (cache[k]['drop-near'] || cache[k]['drop-in']); - }); - - $snippet.toggleClass("disable", !check); - }); - }, - bind_snippet_click_editor: function () { - var self = this; - var snipped_event_flag; - $(document).on('click', '*', function (event) { - var srcElement = event.srcElement || (event.originalEvent && (event.originalEvent.originalTarget || event.originalEvent.target) || event.target); - if (self.editor_busy || snipped_event_flag===srcElement || !srcElement) { - return; - } - snipped_event_flag = srcElement; - - setTimeout(function () {snipped_event_flag = false;}, 0); - var $target = $(srcElement); - - if ($target.closest(".oe_overlay, .note-popover").length) { - return; - } - - if (!data.globalSelector.is($target)) { - $target = data.globalSelector.closest($target); - } - - if (self.$active_snipped_id && self.$active_snipped_id.is($target)) { - return; - } - self.make_active($target); - }); - }, - snippet_blur: function ($snippet) { - if ($snippet) { - if ($snippet.data("snippet-editor")) { - $snippet.data("snippet-editor").on_blur(); - } - } - }, - snippet_focus: function ($snippet) { - if ($snippet) { - if ($snippet.data("snippet-editor")) { - $snippet.data("snippet-editor").on_focus(); - } - } - }, - clean_for_save: function () { - var self = this; - var opt = options.registry; - var template = self.templateOptions; - for (var k in template) { - var Option = opt[template[k]['option']]; - if (Option && Option.prototype.clean_for_save !== editor.dummy) { - template[k].selector.all().filter(function () { - var node = this; - while (!/o_dirty|o_editable/.test(node.className) && node !== document) { - node = node.parentNode; - } - return node.className.indexOf("o_dirty") !== -1; - }).each(function () { - new Option(self, null, $(this), k).clean_for_save(); - }); - } - } - this.$editable.find("*[contentEditable], *[attributeEditable]") - .removeAttr('contentEditable') - .removeProp('contentEditable') - .removeAttr('attributeEditable') - .removeProp('attributeEditable'); - }, - make_active: function ($snippet) { - if ($snippet && this.$active_snipped_id && this.$active_snipped_id.get(0) === $snippet.get(0)) { - return; - } - if (this.$active_snipped_id) { - this.snippet_blur(this.$active_snipped_id); - this.$active_snipped_id = false; - } - if ($snippet && $snippet.length) { - if(_.indexOf(this.snippets, $snippet.get(0)) === -1) { - this.snippets.push($snippet.get(0)); - } - this.$active_snipped_id = $snippet; - this.create_snippet_editor(this.$active_snipped_id); - this.cover_target($snippet.data('overlay'), $snippet); - this.snippet_focus($snippet); - } - this.$el.trigger('snippet-activated', $snippet); - if ($snippet) { - $snippet.trigger('snippet-activated', $snippet); - } - }, - create_snippet_editor: function ($snippet) { - if (typeof $snippet.data("snippet-editor") === 'undefined') { - if (!this.activate_overlay_zones($snippet).length) return; - $snippet.data("snippet-editor", new data.Editor(this, $snippet)); - } - }, - - // activate drag and drop for the snippets in the snippet toolbar - make_snippet_draggable: function ($snippets) { - var self = this; - var $tumb = $snippets.find(".oe_snippet_thumbnail_img:first"); - var left = $tumb.outerWidth()/2; - var top = $tumb.outerHeight()/2; - var $toInsert, dropped, $snippet; - - $snippets.draggable({ - greedy: true, - helper: 'clone', - zIndex: '1000', - appendTo: 'body', - cursor: "move", - handle: ".oe_snippet_thumbnail", - distance: 30, - cursorAt: { - 'left': left, - 'top': top - }, - start: function () { - dropped = false; - // snippet_selectors => to get drop-near, drop-in - $snippet = $(this); - var $base_body = $snippet.find('.oe_snippet_body'); - var $selector_siblings = $(); - var $selector_children = $(); - var temp = self.templateOptions; - for (var k in temp) { - if ($base_body.is(temp[k].base_selector)) { - if (temp[k]['drop-near']) { - if (!$selector_siblings) $selector_siblings = temp[k]['drop-near'].all(); - else $selector_siblings = $selector_siblings.add(temp[k]['drop-near'].all()); - } - if (temp[k]['drop-in']) { - if (!$selector_children) $selector_children = temp[k]['drop-in'].all(); - else $selector_children = $selector_children.add(temp[k]['drop-in'].all()); - } - } - } - - $toInsert = $base_body.clone().data("name", $snippet.find(".oe_snippet_thumbnail_title").text()); - - if (!$selector_siblings.length && !$selector_children.length) { - console.warn($snippet.find(".oe_snippet_thumbnail_title").text() + " have not insert action: data-drop-near or data-drop-in"); - return; - } - - self.make_active(false); - self.activate_insertion_zones($selector_siblings, $selector_children); - - $('.oe_drop_zone').droppable({ - over: function () { - dropped = true; - $(this).first().after($toInsert).addClass('hidden'); - }, - out: function () { - var prev = $toInsert.prev(); - if(this === prev[0]) { - dropped = false; - $toInsert.detach(); - $(this).removeClass('hidden'); - } - }, - }); - }, - stop: function (ev, ui) { - $toInsert.removeClass('oe_snippet_body'); - - if (! dropped && self.$editable.find('.oe_drop_zone') && ui.position.top > 3 && ui.position.left + 50 > self.$el.outerWidth()) { - var el = self.$editable.find('.oe_drop_zone').nearest({x: ui.position.left, y: ui.position.top}).first(); - if (el.length) { - el.after($toInsert); - dropped = true; - } - } - - self.$editable.find('.oe_drop_zone').droppable('destroy').remove(); - - if (dropped) { - - var prev = $toInsert.first()[0].previousSibling; - var next = $toInsert.last()[0].nextSibling; - var rte = self.getParent().rte; - - if (prev) { - $toInsert.detach(); - rte.historyRecordUndo($(prev)); - $toInsert.insertAfter(prev); - } else if (next) { - $toInsert.detach(); - rte.historyRecordUndo($(next)); - $toInsert.insertBefore(next); - } else { - var $parent = $toInsert.parent(); - $toInsert.detach(); - rte.historyRecordUndo($parent); - $parent.prepend($toInsert); - } - - $toInsert.closest(".o_editable").trigger("content_changed"); - - var $target = false; - $target = $toInsert; - - setTimeout(function () { - self.$el.trigger('snippet-dropped', $target); - - animation.start(true, $target); - - self.call_for_all_snippets($target, function (editor, $snippet) { - _.defer(function () { editor.drop_and_build_snippet(); }); - }); - self.create_snippet_editor($target); - self.cover_target($target.data('overlay'), $target); - $target.closest(".o_editable").trigger("content_changed"); - - self.make_active($target); - },0); - } else { - $toInsert.remove(); - } - }, - }); - }, - - // call a method on a snippet and all his children - call_for_all_snippets: function ($snippet, callback) { - var self = this; - $snippet.add(data.globalSelector.all($snippet)).each(function () { - var $snippet = $(this); - self.create_snippet_editor($snippet); - if ($snippet.data("snippet-editor")) { - callback.call(self, $snippet.data("snippet-editor"), $snippet); - } - }); - }, - - // return the original snippet in the editor bar from a snippet id (string) - get_snippet_from_id: function (id) { - return $('.oe_snippet').filter(function () { - return $(this).data('option') === id; - }).first(); - }, - - // Create element insertion drop zones. two css selectors can be provided - // selector.children -> will insert drop zones as direct child of the selected elements - // in case the selected elements have children themselves, dropzones will be interleaved - // with them. - // selector.siblings -> will insert drop zones after and before selected elements - activate_insertion_zones: function ($selector_siblings, $selector_children) { - var self = this; - var zone_template = $("<div class='oe_drop_zone oe_insert'/>"); - - if ($selector_children) { - $selector_children.each(function () { - var $zone = $(this); - var css = window.getComputedStyle(this); - var float = css.float || css.cssFloat; - var $drop = zone_template.clone(); - - $zone.append($drop); - var node = $drop[0].previousSibling; - var test = !!(node && ((!node.tagName && node.textContent.match(/\S/)) || node.tagName === "BR")); - if (test) { - $drop.addClass("oe_vertical").css({ - 'height': parseInt(window.getComputedStyle($zone[0]).lineHeight), - 'float': 'none', - 'display': 'inline-block' - }); - } else if (float === "left" || float === "right") { - $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.children().last().outerHeight()), 30)); - } - - $drop = $drop.clone(); - - $zone.prepend($drop); - node = $drop[0].nextSibling; - test = !!(node && ((!node.tagName && node.textContent.match(/\S/)) || node.tagName === "BR")); - if (test) { - $drop.addClass("oe_vertical").css({ - 'height': parseInt(window.getComputedStyle($zone[0]).lineHeight), - 'float': 'none', - 'display': 'inline-block' - }); - } else if (float === "left" || float === "right") { - $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.children().first().outerHeight()), 30)); - } - if (test) { - $drop.css({'float': 'none', 'display': 'inline-block'}); - } - }); - - // add children near drop zone - $selector_siblings = $(_.uniq(($selector_siblings || $()).add($selector_children.children()).get())); - } - - if ($selector_siblings) { - $selector_siblings.filter(':not(.oe_drop_zone):not(.oe_drop_clone)').each(function () { - var $zone = $(this); - var $drop; - var css = window.getComputedStyle(this); - var float = css.float || css.cssFloat; - - if($zone.prev('.oe_drop_zone:visible').length === 0) { - $drop = zone_template.clone(); - if (float === "left" || float === "right") { - $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.prev().outerHeight() || Infinity), 30)); - } - $zone.before($drop); - } - if($zone.next('.oe_drop_zone:visible').length === 0) { - $drop = zone_template.clone(); - if (float === "left" || float === "right") { - $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.next().outerHeight() || Infinity), 30)); - } - $zone.after($drop); - } - }); - } - - var count; - do { - count = 0; - $zones = self.$editable.find('.oe_drop_zone > .oe_drop_zone').remove(); // no recursive zones - count += $zones.length; - $zones.remove(); - } while (count > 0); - - // Cleaning consecutive zone and up zones placed between floating or inline elements. We do not like these kind of zones. - var $zones = self.$editable.find('.oe_drop_zone:not(.oe_vertical)'); - $zones.each(function () { - var zone = $(this); - var prev = zone.prev(); - var next = zone.next(); - // remove consecutive zone - if (prev.is('.oe_drop_zone') || next.is('.oe_drop_zone')) { - zone.remove(); - return; - } - var float_prev = prev.css('float') || 'none'; - var float_next = next.css('float') || 'none'; - var disp_prev = prev.css('display') || null; - var disp_next = next.css('display') || null; - if( (float_prev === 'left' || float_prev === 'right') - && (float_next === 'left' || float_next === 'right') ) { - zone.remove(); - }else if( !( disp_prev === null - || disp_next === null - || disp_prev === 'block' - || disp_next === 'block' )) { - zone.remove(); - } - }); - }, - - // generate drop zones covering the elements selected by the selector - // we generate overlay drop zones only to get an idea of where the snippet are, the drop - activate_overlay_zones: function ($targets) { - var self = this; - - // filter out invisible elements - $targets = $targets.filter(':visible:hasVisibility:hasOpacity'); - - $targets.each(function () { - var $target = $(this); - if (!$target.data('overlay')) { - var $zone = $(qweb.render('web_editor.snippet_overlay')); - - // fix for pointer-events: none with ie9 - if (document.body && document.body.addEventListener) { - $zone.on("click mousedown mousedown", function passThrough(event) { - event.preventDefault(); - $target.each(function () { - // check if clicked point (taken from event) is inside element - event.srcElement = this; - $(this).trigger(event.type); - }); - return false; - }); - } - - $zone.appendTo('#oe_manipulators'); - $zone.data('target', $target); - $target.data('overlay', $zone); - - var timer; - $target.closest('.o_editable').on("content_changed", function (event) { - clearTimeout(timer); - timer = setTimeout(function () { - if ($target.data('overlay') && $target.data('overlay').hasClass("oe_active")) { - self.cover_target($target.data('overlay'), $target); - } - }, 50); - }); - - var resize = function () { - if ($zone.parent().length) { - self.cover_target($zone, $target); - } else { - $('body').off("resize", resize); - } - }; - $('body').on("resize", resize); - } - self.cover_target($target.data('overlay'), $target); - }); - return $targets; - } -}); - -/** - * Snippet editor Editor class. - * Management of the overlay and option list for a snippet. - */ -data.Editor = Class.extend({ - init: function (BuildingBlock, dom) { - this.buildingBlock = BuildingBlock; - this.$target = $(dom); - this.$overlay = this.$target.data('overlay'); - - // Initialize parent button - this.init_parent_options(); - - // Load overlay options content - this.load_style_options(); - - // Initialize move/clone/remove buttons - if (!this.$target.parent().is(':o_editable')) { - this.$overlay.find('.oe_snippet_move, .oe_snippet_clone, .oe_snippet_remove').remove(); - } else { - this.$overlay.on('click', '.oe_snippet_clone', _.bind(this.on_clone, this)); - this.$overlay.on('click', '.oe_snippet_remove', _.bind(this.on_remove, this)); - this._drag_and_drop(); - } - }, - - getName: function () { - if (this.$target.data("name") !== undefined) { - return this.$target.data("name"); - } - if (this.$target.parent(".row").length) { - return _t("Column"); - } - return _t("Block"); - }, - - // activate drag and drop for the snippets in the snippet toolbar - _drag_and_drop: function () { - var self = this; - this.dropped = false; - this.$overlay.draggable({ - greedy: true, - appendTo: 'body', - cursor: "move", - handle: ".oe_snippet_move", - cursorAt: { - left: 18, - top: 14 - }, - helper: function () { - var $clone = $(this).clone().css({width: "24px", height: "24px", border: 0}); - $clone.find(".oe_overlay_options >:not(:contains(.oe_snippet_move)), .oe_handle").remove(); - $clone.find(":not(.glyphicon)").css({position: 'absolute', top: 0, left: 0}); - $clone.appendTo("body").removeClass("hidden"); - return $clone; - }, - start: _.bind(self._drag_and_drop_start, self), - stop: _.bind(self._drag_and_drop_stop, self) - }); - }, - _drag_and_drop_after_insert_dropzone: function () {}, - _drag_and_drop_active_drop_zone: function ($zones) { - var self = this; - $zones.droppable({ - over: function () { - $(".oe_drop_zone.hide").removeClass("hide"); - $(this).addClass("hide").first().after(self.$target); - self.dropped = true; - }, - out: function () { - $(this).removeClass("hide"); - self.$target.detach(); - self.dropped = false; - }, - }); - }, - _drag_and_drop_start: function () { - var self = this; - self.buildingBlock.editor_busy = true; - self.size = { - width: self.$target.width(), - height: self.$target.height() - }; - self.$target.after("<div class='oe_drop_clone' style='display: none;'/>"); - self.$target.detach(); - self.$overlay.addClass("hidden"); - - var $selector_siblings; - for (var i = 0 ; i < self.selector_siblings.length ; i++) { - if (!$selector_siblings) $selector_siblings = self.selector_siblings[i].all(); - else $selector_siblings = $selector_siblings.add(self.selector_siblings[i].all()); - } - var $selector_children; - for (i = 0 ; i < self.selector_children.length ; i++) { - if (!$selector_children) $selector_children = self.selector_children[i].all(); - else $selector_children = $selector_children.add(self.selector_children[i].all()); - } - - self.buildingBlock.make_active(false); - self.buildingBlock.activate_insertion_zones($selector_siblings, $selector_children); - - $("body").addClass('move-important'); - - self._drag_and_drop_after_insert_dropzone(); - self._drag_and_drop_active_drop_zone($('.oe_drop_zone')); - }, - _drag_and_drop_stop: function () { - var self = this; - - $(".oe_drop_zone").droppable('destroy').remove(); - - var prev = this.$target.first()[0].previousSibling; - var next = this.$target.last()[0].nextSibling; - var $parent = this.$target.parent(); - - var $clone = $(".oe_drop_clone"); - if (prev === $clone[0]) { - prev = $clone[0].previousSibling; - } else if (next === $clone[0]) { - next = $clone[0].nextSibling; - } - $clone.after(this.$target); - - this.$overlay.removeClass("hidden"); - $("body").removeClass('move-important'); - $clone.remove(); - - if (this.dropped) { - this.buildingBlock.getParent().rte.historyRecordUndo(this.$target); - - if (prev) { - this.$target.insertAfter(prev); - } else if (next) { - this.$target.insertBefore(next); - } else { - $parent.prepend(this.$target); - } - - for (var i in this.styles) { - this.styles[i].on_move(); - } - } - - self.buildingBlock.editor_busy = false; - - self.init_parent_options(); - _.defer(function () { - self.buildingBlock.cover_target(self.$target.data('overlay'), self.$target); - }); - }, - - load_style_options: function () { - var self = this; - var $styles = this.$overlay.find('.oe_options'); - var $ul = $styles.find('ul:first'); - this.styles = {}; - this.selector_siblings = []; - this.selector_children = []; - - var i = 0; - $ul.append($("<li/>", {"class": "dropdown-header o_main_header", text: this.getName()}).data("editor", this)); - _.each(this.buildingBlock.templateOptions, function (val, option_id) { - if (!val.selector.is(self.$target)) { - return; - } - if (val['drop-near']) self.selector_siblings.push(val['drop-near']); - if (val['drop-in']) self.selector_children.push(val['drop-in']); - - var option = val['option']; - self.styles[option] = new (options.registry[option] || options.Class)(self.buildingBlock, self, self.$target, option_id); - $ul.append(self.styles[option].$el.addClass("snippet-option-" + option)); - self.styles[option].start(); - self.styles[option].__order = i++; - }); - $ul.append($("<li/>", {"class": "divider"})); - - var $parents = this.$target.parents(); - _.each($parents, function (parent) { - var parentEditor = $(parent).data("snippet-editor"); - if (parentEditor) { - for (var styleName in parentEditor.styles) { - if (!parentEditor.styles[styleName].preventChildPropagation) { - $ul.append($("<li/>", {"class": "dropdown-header o_parent_editor_header", text: parentEditor.getName()}).data("editor", parentEditor)); - break; - } - } - } - }); - - if (!this.selector_siblings.length && !this.selector_children.length) { - this.$overlay.find(".oe_snippet_move, .oe_snippet_clone").addClass('hidden'); - } - - this.$overlay.find('[data-toggle="dropdown"]').dropdown(); - }, - - /** - * The init_parent_options method initializes the "go to parent" button and create the editor options - * management for them if they do not already have one. - */ - init_parent_options: function () { - var self = this; - var $button = this.$overlay.find('.oe_snippet_parent'); - var $parent = data.globalSelector.closest(this.$target.parent()); - if (!$parent.data("snippet-editor")) { - this.buildingBlock.create_snippet_editor($parent); - } - - $button.toggleClass("hidden", $parent.length === 0); - $button.off("click").on('click', function (event) { - event.preventDefault(); - _.defer(function () { - self.buildingBlock.make_active($parent); - }); - }); - }, - - on_clone: function (event) { - event.preventDefault(); - var $clone = this.$target.clone(false); - - this.buildingBlock.getParent().rte.historyRecordUndo(this.$target); - - this.$target.after($clone); - this.buildingBlock.call_for_all_snippets($clone, function (editor, $snippet) { - for (var i in editor.styles) { - editor.styles[i].on_clone($snippet, { - isCurrent: ($snippet.is($clone)), - }); - } - }); - return false; - }, - - on_remove: function (event) { - if (event !== undefined) { - event.preventDefault(); - this.buildingBlock.getParent().rte.historyRecordUndo(this.$target); - } - - this.on_blur(); - - var index = _.indexOf(this.buildingBlock.snippets, this.$target.get(0)); - this.buildingBlock.call_for_all_snippets(this.$target, function (editor, $snippet) { - for (var i in editor.styles) { - editor.styles[i].on_remove(); - } - }); - delete this.buildingBlock.snippets[index]; - - var $parent = this.$target.parent(); - this.$target.find("*").andSelf().tooltip("destroy"); - this.$target.remove(); - this.$overlay.remove(); - - var node = $parent[0]; - if (node && node.firstChild) { - $.summernote.core.dom.removeSpace(node, node.firstChild, 0, node.lastChild, 1); - if (!node.firstChild.tagName && node.firstChild.textContent === " ") { - node.removeChild(node.firstChild); - } - } - - if($parent.closest(":data(\"snippet-editor\")").length) { - while (!$parent.data("snippet-editor")) { - var $nextParent = $parent.parent(); - if ($parent.children().length === 0 && $parent.text().trim() === "" && !$parent.hasClass("oe_structure")) { - $parent.remove(); - } - $parent = $nextParent; - } - if ($parent.children().length === 0 && $parent.text().trim() === "" && !$parent.hasClass("oe_structure")) { - _.defer(function () { - $parent.data("snippet-editor").on_remove(); - }); - } - } - - // clean editor if they are image or table in deleted content - $(".note-control-selection").hide(); - $('.o_table_handler').remove(); - - this.buildingBlock.$el.trigger("snippet-removed"); - - return false; - }, - - /* - * drop_and_build_snippet - * This method is called just after that a thumbnail is drag and dropped into a drop zone - * (after the insertion of this.$body, if this.$body exists) - */ - drop_and_build_snippet: function () { - for (var i in this.styles) { - this.styles[i].drop_and_build_snippet(); - } - }, - - /* on_focus - * This method is called when the user click inside the snippet in the dom - */ - on_focus: function () { - this._on_focus_blur(true); - }, - - /* on_focus - * This method is called when the user click outside the snippet in the dom, after a focus - */ - on_blur: function () { - this._on_focus_blur(false); - }, - - _on_focus_blur: function (focus) { - var do_action = (focus ? _do_action_focus : _do_action_blur); - - // Attach own and parent options on the current overlay - var $style_button = this.$overlay.find(".oe_options"); - var $ul = $style_button.find("ul:first"); - var $headers = $ul.find(".dropdown-header:data(editor)"); - _.each($headers, (function (el) { - var $el = $(el); - var styles = _.values($el.data("editor").styles); - if ($el.data("editor") !== this) { - styles = _.filter(styles, function (option) { return !option.preventChildPropagation; }); - } - - var count = 0; - _.each(_.sortBy(styles, "__order").reverse(), function (style) { - if (do_action(style, $el)) { - count++; - } - }); - $el.toggleClass("hidden", count === 0); - }).bind(this)); - - // Activate the overlay - $style_button.toggleClass("hidden", $ul.children(":not(.o_main_header):not(.divider):not(.hidden)").length === 0); - this.$overlay.toggleClass("oe_active", !!focus); - - function _do_action_focus(style, $dest) { - style.$el.insertAfter($dest); - style.on_focus(); - return (style.$el.length > 0); - } - function _do_action_blur(style, $dest) { - style.$el.detach(); - style.on_blur(); - return false; - } - }, -}); - -/** - * Add the ability on the main editor class to instantiate the snippet editor component - */ -editor.Class.include({ - init: function () { - var self = this; - var res = this._super.apply(this, arguments); - var $editable = this.rte.editable(); - this.buildingBlock = new data.Class(this, $editable); - this.buildingBlock.on("snippets:ready", this, function () { - self.trigger("snippets:ready"); - }); - return res; - }, - start: function () { - this.buildingBlock.insertAfter(this.$el); - this.rte.editable().find("*").off('mousedown mouseup click'); - return this._super.apply(this, arguments); - }, - save: function () { - this.buildingBlock.clean_for_save(); - return this._super.apply(this, arguments); - }, -}); - -/** - * Add the ability the restart the animations - */ -editor.Class.include({ - start: function () { - return this._super.apply(this, arguments).then(function () { - animation.start(true); - }); - }, -}); - -return data; -}); |
