diff options
| author | Christophe Matthieu <chm@odoo.com> | 2015-02-09 13:40:49 +0100 |
|---|---|---|
| committer | Julien De Coster <jdc@odoo.com> | 2015-02-12 11:58:12 +0100 |
| commit | 28ed28f9451edcb32f70daf7082d2ae91148b79c (patch) | |
| tree | 9ad5ae4a272340247a81332895bd230952dbb5bd /addons/website/static/src/js | |
| parent | a46a060f0fda429109fa1c34784c9267d57e2660 (diff) | |
[IMP] website: create a new web editor in the backend to edit html field with the website builder
Diffstat (limited to 'addons/website/static/src/js')
| -rw-r--r-- | addons/website/static/src/js/website.backend.iframe.js | 55 | ||||
| -rw-r--r-- | addons/website/static/src/js/website.backend.js | 162 | ||||
| -rw-r--r-- | addons/website/static/src/js/website.editor.js | 229 | ||||
| -rw-r--r-- | addons/website/static/src/js/website.snippets.editor.js | 335 |
4 files changed, 452 insertions, 329 deletions
diff --git a/addons/website/static/src/js/website.backend.iframe.js b/addons/website/static/src/js/website.backend.iframe.js new file mode 100644 index 00000000000..86e472708ef --- /dev/null +++ b/addons/website/static/src/js/website.backend.iframe.js @@ -0,0 +1,55 @@ +(function () { + 'use strict'; + + window.top.openerp[callback+"_set_value"] = function (value, fields_values) { + var $editable = $("#wrapwrap .o_editable:first"); + if (value !== $editable.html()) { + openerp.website.editor_bar.rte.historyRecordUndo($editable); + openerp.website.editor_bar.snippets.make_active(false); + $editable.html(value); + } + }; + + openerp.website.EditorBar.include({ + start: function () { + var res = this._super.apply(this, arguments); + if (location.search.indexOf("enable_editor") !== -1) { + this.on('rte:ready', this, function () { + $("#website-top-edit").hide(); + if (window.top.openerp[callback+"_editor"]) { + window.top.openerp[callback+"_editor"](this); + } + + var $editable = $("#wrapwrap .o_editable:first"); + setTimeout(function () { + $($editable.find("*").filter(function () {return !this.children.length;}).first()[0] || $editable) + .focusIn().trigger("mousedown").trigger("keyup"); + },0); + + this.rte.on('change', this, function () { + window.top.openerp[callback+"_downup"]($editable.prop('innerHTML')); + }); + }); + + var style = document.createElement("style"); + style.textContent = "#wrapwrap > main > * { margin-top: 50px; }"; + $("head").append(style); + + this.on("snippets:ready", this, function () { + $(window.top).trigger("resize"); + }); + + } else if (window.top.openerp[callback+"_editor"]) { + window.top.openerp[callback+"_editor"](this); + } + return res; + } + }); + + openerp.website.snippet.BuildingBlock.include({ + _get_snippet_url: function () { + return snippets_url; + } + }); + +})();
\ No newline at end of file diff --git a/addons/website/static/src/js/website.backend.js b/addons/website/static/src/js/website.backend.js index c7988f2ad29..86978502515 100644 --- a/addons/website/static/src/js/website.backend.js +++ b/addons/website/static/src/js/website.backend.js @@ -1,21 +1,153 @@ -openerp.website = function(instance) { -var _t = instance.web._t; +(function () { + 'use strict'; -instance.web.form.WidgetWebsiteButton = instance.web.form.AbstractField.extend({ - template: 'WidgetWebsiteButton', - render_value: function() { - this._super(); - this.$() - .toggleClass("success", this.get_value()) - .toggleClass("danger", !this.get_value()); - if (this.node.attrs.class) { - this.$el.addClass(this.node.attrs.class); +var widgets = openerp.web.form.widgets; +while(!widgets.map.html) { + widgets = widgets.parent; +} +widgets.map.html = "openerp.web.form.FieldTextHtml"; + +var widget = openerp.web.form.AbstractField.extend(openerp.web.form.ReinitializeFieldMixin); +openerp.web.form.FieldTextHtml = widget.extend({ + template: 'FieldTextHtml', + start: function () { + var self = this; + + this.callback = _.uniqueId('FieldTextHtml_'); + window.openerp[this.callback+"_editor"] = function (EditorBar) { + self.on_editor_loaded(EditorBar); + }; + window.openerp[this.callback+"_content"] = function (EditorBar) { + self.on_content_loaded(); + }; + window.openerp[this.callback+"_updown"] = null; + window.openerp[this.callback+"_downup"] = function (value) { + self.dirty = true; + self.internal_set_value(value); + self.trigger('changed_value'); + self.resize(); + }; + + // init jqery objects + this.$iframe = this.$el.find('iframe'); + this.document = null; + this.$body = $(); + this.$content = $(); + + // init resize + this.resize = function resize() { + if ($("body").hasClass("o_form_FieldTextHtml_fullscreen")) { + self.$iframe.css('height', $("body").hasClass('o_form_FieldTextHtml_fullscreen') ? (document.body.clientHeight - self.$iframe.offset().top) + 'px' : ''); + } else if (self.get('effective_readonly')) { + var height = 110; + try { + height += self.$body.height(); + height += parseInt(self.$content.parent().css("margin-top")); + } catch (e) {} + self.$iframe.css("height", height+"px"); + } else { + self.$iframe.css("height", (self.$body.find("#oe_snippets").length ? 500 : 300) + "px"); + } + }; + $(window).on('resize', self.resize); + + return this._super(); + }, + get_url: function () { + var src = this.options.editor_url ? this.options.editor_url+"?" : "/website/field/html?"; + var datarecord = this.view.get_fields_values(); + + var attr = { + 'model': this.view.model, + 'field': this.name, + 'res_id': datarecord.id || '', + 'callback': this.callback + }; + if (this.options.snippets) { + attr['snippets'] = this.options.snippets; + } + if (!this.get("effective_readonly")) { + attr['enable_editor'] = 1; } + if (openerp.session.debug) { + attr['debug'] = 1; + } + + for (var k in attr) { + src += "&"+k+"="+attr[k]; + } + + delete datarecord[this.name]; + src += "&datarecord="+ encodeURIComponent(JSON.stringify(datarecord)); + + return src; }, -}); + initialize_content: function() { + this.$iframe = this.$el.find('iframe'); + this.document = null; + this.$body = $(); + this.$content = $(); + this.dirty = false; + this.editor = false; + window.openerp[this.callback+"_set_value"] = function () {}; + + this.$iframe.attr("src", this.get_url()); + }, + on_content_loaded: function () { + var self = this; + this.document = this.$iframe.contents()[0]; + this.$body = $("body", this.document); + this.$content = this.$body.find("#wrapwrap .o_editable:first"); + setTimeout(this.resize,0); + }, + on_editor_loaded: function (EditorBar) { + var self = this; + this.editor = EditorBar; -instance.web.form.widgets = instance.web.form.widgets.extend({ - 'website_button': 'instance.web.form.WidgetWebsiteButton', + $("body").on('click', function (event) { + if ($("body").hasClass('o_form_FieldTextHtml_fullscreen')) { + $("body").removeClass("o_form_FieldTextHtml_fullscreen"); + self.$iframe.css('height', ''); + event.preventDefault(); + event.stopPropagation(); + } + }); + + setTimeout(function () { + var $fullscreen = $('<span class="btn btn-primary" style="margin: 5px;padding: 1px; position: fixed; top: 0; right: 0; z-index: 2000;"><span class="o_fullscreen fa fa-arrows-alt" style="color: white;margin: 3px 5px;"></span></span>'); + var $nav = $("#website-top-navbar", self.document).append($fullscreen); + $fullscreen.on('click', function () { + $("body").toggleClass("o_form_FieldTextHtml_fullscreen"); + self.resize(); + }); + setTimeout(self.resize,0); + }, 500); + }, + render_value: function() { + if (!this.$content) { + return; + } + if(window.openerp[this.callback+"_set_value"]) { + window.openerp[this.callback+"_set_value"](this.get('value') || '', this.view.get_fields_values()); + this.resize(); + } + }, + is_false: function() { + return this.get('value') === false || this.get('value') === ""; + }, + get_value: function(save_mode) { + if (save_mode && this.editor && this.editor.snippets && this.dirty) { + this.editor.snippets.clean_for_save(); + this.internal_set_value( this.$content.prop('innerHTML') ); + } + return this.get('value'); + }, + destroy: function () { + $(window).off('resize', self.resize); + delete window.openerp[this.callback]; + delete window.openerp[this.callback+"_content"]; + delete window.openerp[this.callback+"_updown"]; + } }); -}; +})();
\ No newline at end of file diff --git a/addons/website/static/src/js/website.editor.js b/addons/website/static/src/js/website.editor.js index aa22abf50f4..f14143feb86 100644 --- a/addons/website/static/src/js/website.editor.js +++ b/addons/website/static/src/js/website.editor.js @@ -51,6 +51,10 @@ define(['summernote/summernote'], function () { var $linkPopover = $popover.find('.note-link-popover'); var $airPopover = $popover.find('.note-air-popover'); + if (window === window.top) { + $popover.children().addClass("hidden-xs"); + } + //////////////// image popover // add center button for images @@ -335,7 +339,7 @@ define(['summernote/summernote'], function () { eventHandler.editor.resizefa = function ($editable, sValue) { var $target = $(getImgTarget()); $editable.data('NoteHistory').recordUndo(); - $target.removeClass('fa-1x fa-2x fa-3x fa-4x fa-5x'); + $target.attr('class', $target.attr('class').replace(/\s*fa-[0-9]+x/g, '')); if (+sValue > 1) { $target.addClass('fa-'+sValue+'x'); } @@ -470,41 +474,10 @@ define(['summernote/summernote'], function () { $(data.sc).closest('.o_editable').data('range', r); return r; } - $(document).mousedown(function (event) { - if (!$(event.target).closest(".o_editable").length) { - return; - } - var r = range.create(); - if (initial_data.range && event.shiftKey) { - initial_data.range.select(); - } - if (event.shiftKey) { - var rect = r && r.getClientRects(); - initial_data.rect = rect && rect.length ? rect[0] : { top: 0, left: 0 }; - } - initial_data.event = event; - }); - $(document).mouseup(function (event) { - if (!$(event.target).closest(".o_editable").length) { - return; - } - if (!initial_data.range || !event.shiftKey) { - setTimeout(function () { - initial_data.range = range.create(); - },0); - } - }); function summernote_mouseup (event) { if ($(event.target).closest("#website-top-navbar, .note-popover").length) { return; } - if ($(event.target).is(":o_editable")) { - var a = summernote_ie_fix(event, function (node) { return node.tagName === "A"; }); - if (a) { - range.create().select(); - } - } - // don't rerange if simple click if (initial_data.event) { var dx = event.clientX - (event.shiftKey ? initial_data.rect.left : initial_data.event.clientX); @@ -513,17 +486,36 @@ define(['summernote/summernote'], function () { 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) { history.splitNext(); + + var $editable = $(event.target).closest(".o_editable"); 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 && last_div.tagName === "A") { - summernote_ie_fix(event, function (node) { return 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(); + } + } } + // remember_selection when click on non editable area var r = range.create(); if ($(r ? dom.node(r.sc) : event.srcElement || event.target).closest('#website-top-navbar, #oe_main_menu_navbar, .note-popover, .modal').length) { if (remember_selection && !$(event.target).is('input, select, label, button, a')) { @@ -536,6 +528,17 @@ define(['summernote/summernote'], function () { } else if (r && $(dom.node(r.sc)).closest('.o_editable, .note-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 }; + } } var last_div; @@ -790,6 +793,8 @@ define(['summernote/summernote'], function () { $editable.html(oSnap.contents).scrollTop(oSnap.scrollTop); $(".oe_overlay").remove(); $(".note-control-selection").hide(); + + $editable.trigger("content_changed"); if (!oSnap.bookmark) { return; @@ -852,7 +857,12 @@ define(['summernote/summernote'], function () { }; var last; - this.recordUndo = function ($editable, event) { + this.recordUndo = function ($editable, event, internal_history) { + if (!internal_history) { + if (!event || !last || !aUndo[pos-1] || aUndo[pos-1].editable !== $editable[0]) { // don't trigger change for all keypress + $(".o_editable.note-editable").trigger("content_changed"); + } + } if (event) { if (last && aUndo[pos-1] && aUndo[pos-1].editable !== $editable[0]) { // => make a snap when the user change editable zone (because: don't make snap for each keydown) @@ -926,20 +936,7 @@ define(['summernote/summernote'], function () { website.add_template_file('/website/static/src/xml/website.editor.xml'); website.dom_ready.done(function () { - var is_smartphone = $(document.body)[0].clientWidth < 767; - - if (!is_smartphone) { - website.ready().then(website.init_editor); - } else { - var resize_smartphone = function () { - is_smartphone = $(document.body)[0].clientWidth < 767; - if (!is_smartphone) { - $(window).off("resize", resize_smartphone); - website.init_editor(); - } - }; - $(window).on("resize", resize_smartphone); - } + website.ready().then(website.init_editor); $(document).on('click', 'a.js_link2post', function (ev) { ev.preventDefault(); @@ -1049,7 +1046,6 @@ define(['summernote/summernote'], function () { var saved = {}; // list of allready saved views and data - observer.disconnect(); var defs = $('.o_editable') .filter('.o_dirty') .removeAttr('contentEditable') @@ -1222,7 +1218,7 @@ define(['summernote/summernote'], function () { * Add a record undo to history * @param {DOM} target where the dom is changed is editable zone */ - historyRecordUndo: function ($target) { + historyRecordUndo: function ($target, internal_history) { var rng = range.create(); var $editable = $($target || (rng && rng.sc)).closest(".o_editable"); if ($editable.length) { @@ -1240,7 +1236,7 @@ define(['summernote/summernote'], function () { } $target = $(rng.sc); $target.mousedown(); - this.history.recordUndo($target); + this.history.recordUndo($target, null, internal_history); $target.mousedown(); }, /** @@ -1310,6 +1306,9 @@ define(['summernote/summernote'], function () { } $target.trigger('mousedown'); // for activate selection on picture + setTimeout(function () { + self.historyRecordUndo($editable, true); + },0); } }); @@ -1336,9 +1335,10 @@ define(['summernote/summernote'], function () { } // start element observation - observer.observe(node, OBSERVER_CONFIG); $(node).one('content_changed', function () { $node.addClass('o_dirty'); + }); + $(node).on('content_changed', function () { self.trigger('change'); }); }); @@ -1392,107 +1392,6 @@ define(['summernote/summernote'], function () { } }); - /* ----- OBSERVER ---- */ - - website.Observer = window.MutationObserver || window.WebKitMutationObserver || window.JsMutationObserver; - var OBSERVER_CONFIG = { - childList: true, - attributes: true, - characterData: true, - subtree: true, - attributeOldValue: true, - }; - var observer = new website.Observer(function (mutations) { - // NOTE: Webkit does not fire DOMAttrModified => webkit browsers - // relying on JsMutationObserver shim (Chrome < 18, Safari < 6) - // will not mark dirty on attribute changes (@class, img/@src, - // a/@href, ...) - _(mutations).chain() - .filter(function (m) { - // ignore any SVG target, these blokes are like weird mon - if (m.target && m.target instanceof SVGElement) { - return false; - } - // ignore any change related to mundane image-edit-button - if (m.target && m.target.className - && m.target.className.indexOf('image-edit-button') !== -1) { - return false; - } - switch(m.type) { - case 'attributes': - // ignore contenteditable modification - if (m.attributeName === 'contenteditable') { return false; } - if (m.attributeName === 'attributeeditable') { return false; } - // remove content editable attribute from firefox - if (m.attributeName.indexOf('_moz') === 0) { - if (!m.oldValue) { - // remove stupid _moz attributes - $(m.target).filter(function () { return this.attributes[m.attributeName]; }).removeAttr(m.attributeName); - } - return false; - } - // ignore id modification - if (m.attributeName === 'id') { return false; } - // style not change - if (m.attributeName === 'style' && (m.oldValue || "") === (m.target.attributes.style ? m.target.attributes.style.value : "")) { return false; } - // if attribute is not a class, can't be .cke_focus change - if (m.attributeName !== 'class') { return true; } - - // find out what classes were added or removed - var oldClasses = (m.oldValue || '').split(/\s+/); - var newClasses = m.target.className.split(/\s+/); - var change = _.union(_.difference(oldClasses, newClasses), - _.difference(newClasses, oldClasses)); - // ignore mutation to create editable zone and add dirty class - var change = _.difference(change, ["note-air-editor", "note-editable", "o_dirty", "o_editable", ""]); - return !!change.length; - case 'childList': - // Remove ignorable nodes from addedNodes or removedNodes, - // if either set remains non-empty it's considered to be an - // impactful change. Otherwise it's ignored. - return !!remove_mundane_nodes(m.addedNodes).length || - !!remove_mundane_nodes(m.removedNodes).length; - default: - return true; - } - }) - .map(function (m) { - var node = m.target; - while (node && (!node.className || node.className.indexOf('o_editable')===-1)) { - node = node.parentNode; - } - if (node) { - $(node).data('last-mutation', m); - } - return node; - }) - .compact() - .uniq() - .each(function (node) { - $(node).trigger('content_changed'); - }); - }); - function remove_mundane_nodes(nodes) { - if (!nodes || !nodes.length) { return []; } - - var output = []; - for(var i=0; i<nodes.length; ++i) { - var node = nodes[i]; - if (node.nodeType === document.ELEMENT_NODE) { - if (node.nodeName === 'BR' && node.getAttribute('type') === '_moz') { - // <br type="_moz"> appears when focusing RTE in FF, ignore - continue; - } else if (node.nodeName === 'DIV' && $(node).hasClass('oe_drop_zone')) { - // ignore dropzone inserted by snippets - continue - } - } - - output.push(node); - } - return output; - } - /* ----- EDITOR: LINK & MEDIA ---- */ website.editor = { }; @@ -2267,8 +2166,12 @@ define(['summernote/summernote'], function () { }); - function getCssSelectors(filter) { - var classes = []; + var cacheCssSelectors = {}; + website.editor.getCssSelectors = function(filter) { + var css = []; + if (cacheCssSelectors[filter]) { + return cacheCssSelectors[filter]; + } var sheets = document.styleSheets; for(var i = 0; i < sheets.length; i++) { var rules = sheets[i].rules || sheets[i].cssRules; @@ -2277,17 +2180,19 @@ define(['summernote/summernote'], function () { var selectorText = rules[r].selectorText; if (selectorText) { var match = selectorText.match(filter); - if (match) classes.push(match[1].slice(1, match[1].length)); + if (match) { + css.push([match[1], rules[r].cssText.replace(/(^.*\{\s*)|(\s*\}\s*$)/g, '')]); + } } } } } - return classes; - } + return cacheCssSelectors[filter] = css; + }; function computeFonts() { _.each(website.editor.fontIcons, function (data) { - data.icons = _.map(getCssSelectors(data.parser), function (css) { - return css.replace(/::?before$/, ''); + data.icons = _.map(website.editor.getCssSelectors(data.parser), function (css) { + return css[0].slice(1, css[0].length).replace(/::?before$/, ''); }); }); } @@ -2366,7 +2271,7 @@ define(['summernote/summernote'], function () { var self = this; this.parent.trigger("save", this.media); var icons = this.icons; - var style = this.media.attributes.style ? this.media.attributes.style.textContent : ''; + var style = this.media.attributes.style ? this.media.attributes.style.value : ''; var classes = (this.media.className||"").split(/\s+/); var non_fa_classes = _.reject(classes, function (cls) { return self.getFont(cls); diff --git a/addons/website/static/src/js/website.snippets.editor.js b/addons/website/static/src/js/website.snippets.editor.js index f67131009c8..b3410aef971 100644 --- a/addons/website/static/src/js/website.snippets.editor.js +++ b/addons/website/static/src/js/website.snippets.editor.js @@ -27,6 +27,9 @@ this.snippets.insertAfter(this.$el); website.snippet.start_animation(true); $editable.find("*").off('mousedown mouseup click'); + this.snippets.on("snippets:ready", this, function () { + self.trigger("snippets:ready"); + }); }); return this._super.apply(this, arguments); @@ -39,14 +42,6 @@ /* ----- SNIPPET SELECTOR ---- */ - var observer = new website.Observer(function (mutations) { - if (!_(mutations).find(function (m) { - return m.type === 'childList' && m.addedNodes.length > 0; - })) { - return; - } - }); - $.extend($.expr[':'],{ o_editable: function(node,i,m){ while (node) { @@ -91,11 +86,6 @@ } this.$active_snipped_id = false; this.snippets = []; - - observer.observe(document.body, { - childList: true, - subtree: true, - }); }, start: function() { var self = this; @@ -122,15 +112,9 @@ }; $(window).on('resize', function () { - if (self.$active_snipped_id) { + 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); } - var $scroll = self.$snippet.find('.scroll:first').css("overflow", ""); - if ($scroll.children().last().height() + $scroll.children().first().height() + 34 > document.body.clientHeight) { - $scroll.css("overflow", "auto").css("width", "216px"); - } else { - $scroll.css("width", ""); - } }); $(document).on('mousemove', function () { @@ -194,135 +178,191 @@ }; } }, + fetch_snippet_templates: function () { var self = this; - openerp.jsonRpc(this._get_snippet_url(), 'call', {}) - .then(function (html) { - var $html = $(html); - - $html.siblings(".scroll").find('> ul li').tooltip({ - delay: { "show": 500, "hide": 100 }, - container: 'body', - title: function () { - return (navigator.appVersion.indexOf('Mac') > -1 ? 'CMD' : 'CTRL')+'+SHIFT+'+($(this).index()+1); - }, - trigger: 'hover', - placement: 'right' - }).on('click', function () {$(this).tooltip('hide');}); - - // t-snippet - $html.find('> .tab-content > div > [data-oe-type="snippet"]').each(function () { - var $div = $('<div/>').insertAfter(this).append(this).attr('name', $(this).data('oe-name')); - }); - // end - - 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), - 'drop-in': $style.data('drop-in') && self._add_check_selector($style.data('drop-in'), no_check), - 'data': $style.data() - }; - website.snippet.templateOptions.push(option); - selector.push(option.selector); - }); - $styles.addClass("hidden"); - website.snippet.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; - }, - 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; - }, - is: function ($from) { - var len = selector.length; - for (var i = 0; i<len; i++) { - if (selector[i].is($from)) { - return true; - } - } - return false; - }, - }; + var url = this._get_snippet_url(); + if (!url || !url.length) { + this.$snippet.detach(); + return; + } + return openerp.jsonRpc(url, 'call', {}).then(function (html) { + self.compute_snippet_templates(html); + self.trigger("snippets:ready"); + }); + }, + compute_snippet_templates: function (html) { + var self = this; + var $html = $(html); + var $left_bar = this.$el.find("#o_left_bar"); + var $ul = $html.siblings("ul"); + var $scroll = $html.siblings("#o_scroll"); - self.$snippets = $html.find(".tab-content > div > div") - .addClass("oe_snippet") - .each(function () { - 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($(this).attr("name")); - $(this).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 - } - $("> *:not(.oe_snippet_thumbnail)", this).addClass('oe_snippet_body'); - }); + if (!$scroll.length) { + throw new Error("Wrong snippets xml definition"); + } - // select all default text to edit (if snippet default text) - self.$snippets.find('.oe_snippet_body, .oe_snippet_body *') - .contents() - .filter(function() { - return this.nodeType === 3 && this.textContent.match(/\S/); - }).parent().addClass("o_default_snippet_text"); - $(document).on("mouseup", ".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"); - }); - // end - - // clean t-oe - $html.find('[data-oe-model]').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--; - } + $ul.children().tooltip({ + delay: { "show": 500, "hide": 100 }, + container: 'body', + title: function () { + return (navigator.appVersion.indexOf('Mac') > -1 ? 'CMD' : 'CTRL')+'+SHIFT+'+($(this).index()+1); + }, + trigger: 'hover', + placement: 'top' + }).on('click', function () {$(this).tooltip('hide');}); + + // t-snippet + $html.find('[data-oe-type="snippet"][data-oe-name]').each(function () { + var $div = $('<div/>').insertAfter(this).append(this).attr('name', $(this).data('oe-name')); + }); + // end + + 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), + 'drop-in': $style.data('drop-in') && self._add_check_selector($style.data('drop-in'), no_check), + 'data': $style.data() + }; + website.snippet.templateOptions.push(option); + selector.push(option.selector); + }); + $styles.addClass("hidden"); + website.snippet.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; } - }); - // end + } + return $target; + }, + 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; + }, + is: function ($from) { + var len = selector.length; + for (var i = 0; i<len; i++) { + if (selector[i].is($from)) { + return true; + } + } + return false; + }, + }; - self.$el.append($html); + // oe_snippet_body + self.$snippets = $scroll.find(".o_panel_body").children() + .addClass("oe_snippet") + .each(function () { + 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($(this).attr("name")); + $(this).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 + } + $("> *:not(.oe_snippet_thumbnail)", this).addClass('oe_snippet_body'); + }); - $(window).trigger('resize'); + // select all default text to edit (if snippet default text) + self.$snippets.find('.oe_snippet_body, .oe_snippet_body *') + .contents() + .filter(function() { + return this.nodeType === 3 && this.textContent.match(/\S/); + }).parent().addClass("o_default_snippet_text"); + $(document).on("mouseup", ".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"); + }); + // end + + // clean t-oe + $html.find('[data-oe-model]').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--; + } + } + }); + // end - self.make_snippet_draggable(self.$snippets); - }); + $left_bar.append($html); + + // animate for list of snippet blocks + $left_bar.on('click', '.scroll-link', function (event) { + event.preventDefault(); + var targetOffset = $($(this).attr("href")).position().top - $ul.outerHeight() + $scroll[0].scrollTop; + $scroll.animate({'scrollTop': targetOffset}, 750); + }); + $scroll.on('scroll', function () { + var middle = $scroll.height()/4; + var $li = $ul.find("a").parent().removeClass('active'); + var last; + for (var k=0; k<$li.length; k++) { + var li = $($li[k]); + if (!li.data('target')) { + li.data('target', $($("a", li).attr("href"))); + } + if (li.data('target').position().top > middle) { + break; + } + last = $li[k]; + } + $(last).addClass("active"); + }); + // end + + // display scrollbar + $(window).on('resize', function () { + $scroll.css("overflow", ""); + var height = $left_bar.height() - $ul.outerHeight(); + $scroll.css("height", height); + var $last = $scroll.children(":visible").last().children(".o_panel_body"); + $last.css({'min-height': (height-$last.prev().outerHeight())+'px'}); + if ($scroll[0].scrollHeight + $ul[0].scrollHeight > document.body.clientHeight) { + $scroll.css("overflow", "auto").css("width", "226px"); + } else { + $scroll.css("width", ""); + } + }).trigger('resize'); + // end + + self.make_snippet_draggable(self.$snippets); }, + cover_target: function ($el, $target){ if($el.data('not-cover_target')) return; var pos = $target.offset(); @@ -442,7 +482,7 @@ for (var k in template) { var Option = options[template[k]['option']]; if (Option && Option.prototype.clean_for_save !== dummy) { - template[k].selector.all().each(function () { + template[k].selector.all().filter(".o_dirty").each(function () { new Option(self, null, $(this), k).clean_for_save(); }); } @@ -777,19 +817,10 @@ var timer; $target.closest('.o_editable').on("content_changed", function (event) { - if ($target[0] === $(event.target).data('last-mutation').target || - $.contains($target[0], $(event.target).data('last-mutation').target)) { - - $target.data('need_recover', true); + if ($target.data('overlay') && $target.data('overlay').hasClass("oe_active")) { clearTimeout(timer); timer = setTimeout(function () { - $(':data(need_recover)').each(function () { - var $snippet = $(this); - $snippet.data('need_recover', null); - if ($snippet.data('overlay')) { - self.cover_target($snippet.data('overlay'), $snippet); - } - }); + self.cover_target($target.data('overlay'), $target); },50); } }); |
