summaryrefslogtreecommitdiff
path: root/addons/website/static/src/js
diff options
context:
space:
mode:
authorChristophe Matthieu <chm@odoo.com>2015-02-09 13:40:49 +0100
committerJulien De Coster <jdc@odoo.com>2015-02-12 11:58:12 +0100
commit28ed28f9451edcb32f70daf7082d2ae91148b79c (patch)
tree9ad5ae4a272340247a81332895bd230952dbb5bd /addons/website/static/src/js
parenta46a060f0fda429109fa1c34784c9267d57e2660 (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.js55
-rw-r--r--addons/website/static/src/js/website.backend.js162
-rw-r--r--addons/website/static/src/js/website.editor.js229
-rw-r--r--addons/website/static/src/js/website.snippets.editor.js335
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);
}
});