[REF] web_editor,website,mass_mailing: JS/XML update

* Adapt DOM selectors
* Refactore dialog XMLs to have odoo styling
* New editor options (background-position, ...)
* Various improvements
This commit is contained in:
qsm-odoo
2016-02-24 13:47:36 +01:00
parent 58c5ff1d4f
commit 6610d05549
38 changed files with 1646 additions and 2114 deletions
@@ -165,7 +165,7 @@ web_editor.Class.include({
}
var $editable = $("#editable_area");
$(".o_table_handler").remove();
$editable.parent().add("#oe_snippets, #templates, .note-popover").toggleClass("hidden");
$editable.add("#oe_snippets, #templates, .note-popover").toggleClass("hidden");
$("#choose_template").children().toggleClass("hidden");
$("body").trigger("resize");
$(window.top).trigger('resize');
@@ -177,7 +177,7 @@ web_editor.Class.include({
var $editable = $("#editable_area");
this.rte.historyRecordUndo($editable);
$editable.html( $(event.target).closest(".theme_thumbnail").find(".js_content").html() );
$editable.parent().add("#oe_snippets, #templates, .note-popover").toggleClass("hidden");
$editable.add("#oe_snippets, #templates, .note-popover").toggleClass("hidden");
$("#choose_template").children().toggleClass("hidden");
setTimeout(function () {
$("body").trigger("resize");
@@ -191,8 +191,8 @@ web_editor.Class.include({
event.preventDefault();
},
set_snippet_theme: function (theme) {
$("#o_left_bar .o_panel_body > div").addClass("hidden");
$("#o_left_bar .o_panel_body > div."+theme).removeClass("hidden");
$("#oe_snippets .o_panel_body > div").addClass("hidden");
$("#oe_snippets .o_panel_body > div."+theme).removeClass("hidden");
$("#editable_area").trigger("content_changed");
},
get_snippet_template: function (mailing_model) {
@@ -225,7 +225,7 @@ snippets_editor.Class.include({
clean_for_save: function () {
this._super();
var $editable = $("#editable_area");
var theme = ($("#o_left_bar .o_panel_body > div:not(.hidden)").attr("class") || "").replace(/^\s*|\s*o_mail_block[^\s]+\s*|\s*oe_snippet\s*|\s*ui-draggable\s*|\s*$/g, '');
var theme = ($("#oe_snippets .o_panel_body > div:not(.hidden)").attr("class") || "").replace(/^\s*|\s*o_mail_block[^\s]+\s*|\s*oe_snippet\s*|\s*ui-draggable\s*|\s*$/g, '');
var $theme = $("#editable_area [data-snippet-theme]").removeAttr("data-snippet-theme").removeData("snippet-theme");
$editable.children().first().attr("data-snippet-theme", theme);
$editable.find(":not(br):hidden").remove();
@@ -31,11 +31,10 @@ define([
var title = options.title;
var className = options.className;
var dropdown = options.dropdown;
var dropdown2 = options.dropdown2;
var wrapper = options.wrapper;
var no_caret = options.no_caret;
var hide = options.hide;
var btn = (dropdown ? '<div class="btn-group' +
return (dropdown ? '<div class="btn-group' +
(className ? ' ' + className : '') + '">' : '') +
'<button type="button"' +
' class="btn btn-default btn-sm' +
@@ -49,14 +48,10 @@ define([
(hide ? ' data-hide=\'' + hide + '\'' : '') +
' tabindex="-1">' +
label +
(dropdown ? ' <span class="caret"></span>' : '') +
((dropdown && !no_caret)? ' <span class="caret"></span>' : '') +
'</button>' +
(dropdown || '') +
(dropdown ? '</div>' : '');
if (wrapper) btn = $(wrapper).html(btn).prop('outerHTML');
return btn;
};
/**
@@ -230,77 +225,52 @@ define([
value: '{"backColor":"#B35E9B"}'
});
var foreground = '<ul class="dropdown-menu">' +
'<li>' +
'<div class="note-palette-title">' + lang.color.foreground + '</div>' +
'<div class="btn-group palette-reset">' +
'<div class="note-color-reset" data-event="foreColor"' +
' data-value="inherit" title="' + lang.color.reset + '"><i class="material-icons">&#xE23B;</i> '+
'</div>' +
'</div>' +
// This is a copy of web_editor.snippet.option.colorpicker qweb template
var colorpicker_template = '' +
'<div class="dropdown-menu">' +
'<div class="colorpicker">' +
'<div class="note-palette-title">{0}</div>' +
'<div class="btn-group palette-reset">' +
'<div class="note-color-reset" data-event="{2}" data-value="inherit" title="{1}">' +
'<i class="fa fa-ban"></i>' +
'</div>' +
'</div>' +
'<div class="o_colorpicker_sections">' +
'<ul class="nav nav-pills o_colorpicker_section_menu">' +
'<li><a href="#o_palette_spectrum"><i class="fa fa-eyedropper"></i></a></li>' +
'</ul>' +
'<div class="tab-content o_colorpicker_section_tabs">' +
'<div class="tab-pane" id="o_palette_spectrum">' +
'<div class="note-color-palette" data-target-event="{2}"></div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>';
'<div class="tabs_container">' +
'<ul class="tabs_toggles">'+
'<li class="on"><a href="#" data-tab-target=".palette_theme"><i class="material-icons">&#xE3B7;</i></a></li>' +
'<li><a href="#" data-tab-target=".palette_grayscale"><i class="material-icons">&#xE3E9;</i></a></li>' +
'<li><a href="#" data-tab-target=".palette_ui"><i class="material-icons">&#xE41D;</i></a></li>' +
'<li><a href="#" data-tab-target=".palette_spectrum"><i class="material-icons">&#xE3B8;</i></a></li>' +
'</ul>' +
'<div class="tabs">' +
'<div class="tab palette_theme on"/>'+
'<div class="tab palette_grayscale"/>'+
'<div class="tab palette_ui"/>'+
'<div class="tab palette_spectrum">'+
'<div class="note-color-palette" data-target-event="foreColor"></div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</li>' +
'</ul>';
var background = '<ul class="dropdown-menu">' +
'<li>' +
'<div class="note-palette-title">' + lang.color.background + '</div>' +
'<div class="btn-group palette-reset">' +
'<div class="note-color-reset" data-event="backColor"' +
' data-value="inherit" title="' + lang.color.transparent + '"><i class="material-icons">&#xE23B;</i> '+
'</div>' +
'</div>' +
'<div class="tabs_container">' +
'<ul class="tabs_toggles">'+
'<li class="on"><a href="#" data-tab-target=".palette_theme"><i class="material-icons">&#xE3B7;</i></a></li>' +
'<li><a href="#" data-tab-target=".palette_grayscale"><i class="material-icons">&#xE3E9;</i></a></li>' +
'<li><a href="#" data-tab-target=".palette_ui"><i class="material-icons">&#xE41D;</i></a></li>' +
'<li><a href="#" data-tab-target=".palette_spectrum"><i class="material-icons">&#xE3B8;</i></a></li>' +
'</ul>' +
'<div class="tabs">' +
'<div class="tab palette_theme on"/>'+
'<div class="tab palette_grayscale"/>'+
'<div class="tab palette_ui"/>'+
'<div class="tab palette_spectrum">'+
'<div class="note-color-palette" data-target-event="backColor"></div>' +
'</div>' +
'</div>' +
'</div>' +
'</li>' +
'</ul>';
var foreground = formatStr(colorpicker_template, [lang.color.foreground, lang.color.reset, 'foreColor']);
var background = formatStr(colorpicker_template, [lang.color.background, lang.color.transparent, 'backColor']);
var foregroundButton = tplButton('', {
title: lang.color.foreground,
wrapper: '<span class="btn-group foreground_toggle" />',
dropdown: foreground
className: 'o_foreground_toggle',
dropdown: foreground,
no_caret: true,
});
var backgroundButton = tplButton('', {
title: lang.color.background,
wrapper: '<span class="btn-group background_toggle" />',
dropdown: background
className: 'o_background_toggle',
dropdown: background,
no_caret: true,
});
return colorButton + foregroundButton + backgroundButton;
function formatStr(str, values) {
return str.replace(/{(\d+)}/g, function (match, number) {
return (values[number] !== undefined)? values[number] : match;
});
};
},
bold: function (lang, options) {
return tplIconButton(options.iconPrefix + options.icons.font.bold, {
@@ -848,13 +818,13 @@ define([
});
var body = document.body;
var container = $('#web_editor-toolbars')
var $container = $('#web_editor-toolbars')
// create Popover
var $popover = $(this.tplPopovers(langInfo, options)); // ODOO: user (maybe) overrided method
$popover.addClass('note-air-layout');
$popover.attr('id', 'note-popover-' + id);
$popover.appendTo(container);
$popover.appendTo($container);
createTooltip($popover, keyMap);
this.createPalette($popover, options); // ODOO: use (maybe) overrided method
@@ -862,7 +832,7 @@ define([
var $handle = $(tplHandles(options));
$handle.addClass('note-air-layout');
$handle.attr('id', 'note-handle-' + id);
$handle.appendTo(container);
$handle.appendTo($container);
// create Dialog
var $dialog = $(tplDialogs(langInfo, options));
@@ -871,7 +841,7 @@ define([
$dialog.find('button.close, a.modal-close').click(function () {
$(this).closest('.modal').modal('hide');
});
$dialog.appendTo(container);
$dialog.appendTo($container);
};
/**
+11 -11
View File
@@ -51,7 +51,7 @@ var FieldTextHtmlSimple = widget.extend({
}
return config;
},
start: function() {
start: function () {
var def = this._super.apply(this, arguments);
this.$translate.remove();
this.$translate = $();
@@ -59,7 +59,7 @@ var FieldTextHtmlSimple = widget.extend({
this.$content.trigger('mouseup');
return def;
},
initialize_content: function() {
initialize_content: function () {
var self = this;
this.$textarea = this.$("textarea").val(this.get('value') || "<p><br/></p>");
this.$content = $();
@@ -118,20 +118,20 @@ var FieldTextHtmlSimple = widget.extend({
return value;
},
focus: function() {
if (this.get("effective_readonly")) {
if (!(!this.get("effective_readonly") && this.$textarea)) {
return false;
}
// on IE an error may occur when creating range on not displayed element
try {
return this.$content.focusInEnd();
return this.$textarea.focusInEnd();
} catch (e) {
return this.$content.focus();
return this.$textarea.focus();
}
},
resize: function() {
this.$('iframe').css('height', '0px').css('height', Math.max(30, Math.min(this.$content[0] ? this.$content[0].scrollHeight : 0, 500)) + 'px');
},
render_value: function() {
render_value: function () {
var value = this.get('value');
this.$textarea.val(value || '');
this.$content.html(this.text_to_html(value));
@@ -148,10 +148,10 @@ var FieldTextHtmlSimple = widget.extend({
this.$('.note-toolbar').find('button[data-event="undo"]').attr('disabled', false);
}
},
is_false: function() {
is_false: function () {
return !this.get('value') || this.get('value') === "<p><br/></p>" || !this.get('value').match(/\S/);
},
before_save: function() {
before_save: function () {
if (this.options['style-inline']) {
transcoder.class_to_style(this.$content);
transcoder.font_to_img(this.$content);
@@ -268,7 +268,7 @@ var FieldTextHtml = widget.extend({
return src;
},
initialize_content: function() {
initialize_content: function () {
this.$el.closest('.modal-body').css('max-height', 'none');
this.$iframe = this.$el.find('iframe');
this.document = null;
@@ -334,7 +334,7 @@ var FieldTextHtml = widget.extend({
self.initialize_content();
});
},
render_value: function() {
render_value: function () {
if (this.lang !== this.view.dataset.context.lang || this.$iframe.attr('src').match(/[?&]edit_translations=1/)) {
return;
}
@@ -354,7 +354,7 @@ var FieldTextHtml = widget.extend({
}
}
},
is_false: function() {
is_false: function () {
return this.get('value') === false || !this.$content.html() || !this.$content.html().match(/\S/);
},
before_save: function () {
+5 -5
View File
@@ -30,7 +30,7 @@ data.dom_ready = dom_ready;
// todo: remove and load a bundle of translated templates
var all_ready;
data.ready = function() {
data.ready = function () {
if (!all_ready) {
all_ready = $.when(dom_ready, ajax.loadXML()).then(translations);
} else if(all_ready.state() === "resolved") { // can add async template
@@ -40,9 +40,9 @@ data.ready = function() {
};
function translations() {
function translate_node(node){
function translate_node(node) {
if(node.nodeType === 3) { // TEXT_NODE
if(node.nodeValue.match(/\S/)){
if(node.nodeValue.match(/\S/)) {
var space = node.nodeValue.match(/^([\s]*)([\s\S]*?)([\s]*)$/);
node.nodeValue = space[1] + $.trim(_t(space[2])) + space[3];
}
@@ -55,11 +55,11 @@ function translations() {
'mods': ['web_editor'],
'lang': data.get_context().lang
})
.then(function(trans) {
.then(function (trans) {
_t.database.set_bundle(trans);
}).then(function () {
var keys = _.keys(qweb.templates);
for (var i = 0; i < keys.length; i++){
for (var i = 0; i < keys.length; i++) {
translate_node(qweb.templates[keys[i]]);
}
}).promise();
+5 -8
View File
@@ -63,9 +63,9 @@ editor.Class = Widget.extend({
template: 'web_editor.editorbar',
events: {
'click button[data-action=save]': 'save',
'click a[data-action=cancel]': 'cancel',
'click button[data-action=cancel]': 'cancel',
},
init: function(parent) {
init: function (parent) {
var self = this;
var res = this._super.apply(this, arguments);
this.parent = parent;
@@ -75,7 +75,7 @@ editor.Class = Widget.extend({
});
return res;
},
start: function() {
start: function () {
var self = this;
$('.dropdown-toggle').dropdown();
@@ -86,14 +86,13 @@ editor.Class = Widget.extend({
this.rte.start();
var flag = false;
window.onbeforeunload = function(event) {
window.onbeforeunload = function (event) {
if (rte.history.getEditableHasUndo().length && !flag) {
flag = true;
setTimeout(function () {flag=false;},0);
return _t('This document is not saved!');
}
};
this.$('button[data-action="save"]').prop('disabled', true);
return this._super();
},
display_placeholder: function () {
@@ -119,9 +118,7 @@ editor.Class = Widget.extend({
}
});
},
rte_changed: function () {
this.$('button[data-action=save]').prop('disabled', !rte.history.getEditableHasUndo().length);
},
rte_changed: function () {},
save: function () {
return this.rte.save().then(function () {
editor.reload();
+3 -3
View File
@@ -57,10 +57,10 @@ snippet_editor.Class.include({
transcoder.class_to_style($editable);
// fix outlook image rendering bug
_.each(['width', 'height'], function(attribute) {
$editable.find('img[style*="width"], img[style*="height"]').attr(attribute, function(){
_.each(['width', 'height'], function (attribute) {
$editable.find('img[style*="width"], img[style*="height"]').attr(attribute, function () {
return $(this)[attribute]();
}).css(attribute, function(){
}).css(attribute, function () {
return $(this).get(0).style[attribute] || 'auto';
});
});
+3 -3
View File
@@ -203,7 +203,7 @@ var history = new History();
// add focusIn to jQuery to allow to move caret into a div of a contentEditable area
$.extend($.expr[':'],{
o_editable: function(node,i,m){
o_editable: function (node,i,m) {
while (node) {
if (node.className) {
if (node.className.indexOf('o_not_editable')!==-1 ) {
@@ -423,11 +423,11 @@ var RTE = Widget.extend({
/**
* Get HTML cloned element with text nodes escaped for XML storage
*/
getEscapedElement: function($el) {
getEscapedElement: function ($el) {
var escaped_el = $el.clone();
var to_escape = escaped_el.find('*').addBack();
to_escape = to_escape.not(to_escape.filter('object,iframe,script,style,[data-oe-model][data-oe-model!="ir.ui.view"]').find('*').addBack());
to_escape.contents().each(function(){
to_escape.contents().each(function () {
if(this.nodeType == 3) {
this.nodeValue = $('<div />').text(this.nodeValue).html();
}
@@ -44,27 +44,68 @@ renderer.createPalette = function ($container, options) {
return;
}
var $color = $container.find('.note-color');
var html = $(QWeb.render('web_editor.colorpicker'));
var theme = html.find('.theme')
var $clpicker = $(QWeb.render('web_editor.colorpicker'));
$color.find('.palette_theme').prepend(html.find('.theme'));
$color.find('.palette_ui').prepend(html.find('.ui'));
$color.find('.palette_grayscale').prepend(html.find('.grayscale'));
$container.find('.colorpicker').each(function (i, picker) {
var $picker = $(picker);
var $bg = $color.find('.background_toggle .dropdown-menu button');
var $fore = $color.find('.foreground_toggle .dropdown-menu button');
var $sections = $clpicker.find('.o_colorpicker_section').clone(true);
var $toggles = $picker.find('.o_colorpicker_section_menu');
var $tabs = $picker.find('.o_colorpicker_section_tabs');
var $defaultToggle = $toggles.find('li');
var $defaultTab = $tabs.find('.tab-pane');
var newDefaultID = _.uniqueId();
$defaultToggle.children('a').attr('href', $defaultToggle.children('a').attr('href') + newDefaultID);
$defaultTab.attr('id', $defaultTab.attr('id') + newDefaultID);
if ($sections.length) {
$sections.each(function () {
var $section = $(this);
var id = 'o_palette_' + $section.data('name') + _.uniqueId();
var $li = $('<li/>')
.append($('<a/>', {href: '#' + id})
.append($('<i/>', {'class': $section.data('iconClass') || '', html: $section.data('iconContent') || ''})));
$defaultToggle.before($li);
$defaultTab.before($section.addClass('tab-pane').attr('id', id));
});
} else {
var id = 'o_palette_other' + _.uniqueId();
var $li = $('<li/>')
.append($('<a/>', {href: '#' + id, 'aria-controls': id})
.append($('<i/>', {'class': 'fa fa-magic'})));
$toggles.prepend($li);
$tabs.prepend($('<div/>', {'class': 'tab-pane', id: id}).append($clpicker.clone(true)));
}
$toggles.find('li:first-child').addClass('active');
$tabs.find('div:first-child').addClass('active');
$toggles.on('click mouseover', '> li > a', function (e) {
e.preventDefault();
e.stopPropagation();
$(this).tab('show');
});
});
var $bg = $container.find('.o_background_toggle .dropdown-menu button');
var $fore = $container.find('.o_foreground_toggle .dropdown-menu button');
$bg.each(function () {
$(this).attr('data-event', 'backColor').attr('data-value',
$(this).attr($(this).attr('class') == 'note-color-btn' ?'title':'class')
);
var $el = $(this);
var className = $el.hasClass('note-color-btn')? $el.attr('title') : ('bg-' + $el.data('color'));
$el.attr('data-event', 'backColor').attr('data-value', className).addClass(className);
});
$fore.each(function () {
$(this).attr('data-event', 'foreColor').attr('data-value',
$(this).attr($(this).attr('class') == 'note-color-btn' ?'title':'class').replace(/bg-/, 'text-')
);
});
var $el = $(this);
var className = $el.hasClass('note-color-btn')? $el.attr('title') : ('text-' + $el.data('color'));
$el.attr('data-event', 'foreColor').attr('data-value', className).addClass(className);
});
};
var fn_tplPopovers = renderer.tplPopovers;
@@ -92,7 +133,7 @@ renderer.tplPopovers = function (lang, options) {
var $alt = $('<div class="btn-group"/>');
$alt.prependTo($imagePopover.find('.popover-content'));
$alt.append('<button class="btn btn-default btn-sm btn-small" data-event="alt"><strong>Alt: </strong><span class="o_image_alt"></span></button>');
$alt.append('<button class="btn btn-default btn-sm btn-small" data-event="alt"><strong>' + _t('Description') + ': </strong><span class="o_image_alt"/></button>');
// padding button
var $padding = $('<div class="btn-group"/>');
@@ -209,24 +250,7 @@ eventHandler.modules.popover.button.update = function ($container, oStyle) {
fn_boutton_update.call(this, $container, oStyle);
$container.find('.note-color').removeClass("hidden")
// ACTIVATE TABS
$container.find('[data-tab-target]').each(function(){
var $el = $(this);
var target = $el.data('tab-target');
var $parent = $el.parent().closest('.tabs_container');
var $parentLi = $el.parent().closest('li');
$parentLi.on('click', function(){return false});
$el.on('click', function(){
$parent.find('.tab, .tabs_toggles li').removeClass('on');
$parent.find(target).add($parentLi).addClass('on')
return false;
})
})
$container.find('.note-color').removeClass("hidden");
if (oStyle.image) {
$container.find('[data-event]').parent().removeClass("active");
@@ -728,17 +752,33 @@ eventHandler.attach = function (oLayoutInfo, options) {
$(document).on('mousedown', summernote_mousedown);
$(document).on('mouseup', summernote_mouseup);
oLayoutInfo.editor().off('click').on('click', function (e) {e.preventDefault();}); // if the content editable is a link
oLayoutInfo.editor().on('dblclick', 'img, .media_iframe_video, span.fa, i.fa, span.fa, a.o_image', function (event) {
var imageSelector = 'img, .media_iframe_video, span.fa, i.fa, span.fa, a.o_image';
var show_tooltip = true;
oLayoutInfo.editor().on('dblclick', imageSelector, function (event) {
show_tooltip = false;
if (!$(event.target).closest(".note-toolbar").length) { // prevent icon edition of top bar for default summernote
new widgets.MediaDialog(oLayoutInfo.editor(), event.target).appendTo(document.body);
}
});
oLayoutInfo.editor().on('click', imageSelector, function (event) {
if (!$(event.target).closest(".note-toolbar").length) { // prevent icon edition of top bar for default summernote
setTimeout(function () {
if (show_tooltip) {
$(event.target).tooltip({title: _t('Double-click to edit'), trigger: 'manuel', container: 'body'}).tooltip('show');
setTimeout(function () {
$(event.target).tooltip('destroy');
}, 800);
}
}, 400);
show_tooltip = true;
}
});
if(oLayoutInfo.editor().is('[data-oe-model][data-oe-type="image"]')) {
oLayoutInfo.editor().on('click', 'img', function (event) {
$(event.target).trigger("dblclick");
});
}
oLayoutInfo.editable().on('mousedown', function(e) {
oLayoutInfo.editable().on('mousedown', function (e) {
if(dom.isImg(e.target)) {
range.createFromNode(e.target).select();
}
@@ -898,7 +938,7 @@ $.summernote.lang.odoo = {
recent: _t('Recent Color'),
more: _t('More Color'),
background: _t('Background Color'),
foreground: _t('Foreground Color'),
foreground: _t('Font Color'),
transparent: _t('Transparent'),
setTransparent: _t('Set transparent'),
reset: _t('Reset'),
@@ -43,7 +43,7 @@ var start = function (editable_mode, $target) {
else continue;
}
$(selector).each(function() {
$(selector).each(function () {
var $snipped_id = $(this);
if ( !$snipped_id.parents("#oe_snippets").length &&
!$snipped_id.parent("body").length &&
@@ -58,7 +58,7 @@ var start = function (editable_mode, $target) {
};
var stop = function () {
$(ready).each(function() {
$(ready).each(function () {
var $snipped_id = $(this);
if ($snipped_id.data("snippet-view")) {
$snipped_id.data("snippet-view").stop();
@@ -18,7 +18,7 @@ var dummy = editor.dummy;
ajax.loadXML('/web_editor/static/src/xml/snippets.xml', qweb);
editor.Class.include({
init: function() {
init: function () {
var self = this;
var res = this._super.apply(this, arguments);
var $editable = this.rte.editable();
@@ -46,10 +46,10 @@ editor.Class.include({
/* ----- SNIPPET SELECTOR ---- */
$.extend($.expr[':'],{
hasData: function(node,i,m){
hasData: function (node,i,m) {
return !!_.toArray(node.dataset).length;
},
data: function(node,i,m){
data: function (node,i,m) {
return $(node).data(m[3]);
}
});
@@ -75,28 +75,23 @@ $.fn.extend({
/* ----- BuildingBlock (managment of drag&drop and focus/blur snippets) ---- */
var BuildingBlock = Widget.extend({
template: 'web_editor.snippets',
id: "oe_snippets",
activeSnippets: [],
init: function (parent, $editable) {
this.parent = parent;
this.$editable = $editable;
this._super.apply(this, arguments);
if(!$('#oe_manipulators').length){
$("<div id='oe_manipulators' class='o_css_editor'></div>").appendTo('body');
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() {
start: function () {
var self = this;
this.$snippet = $("#oe_snippets");
this.$el
.on("mouseenter", function () { self.show(); })
.on("mouseleave", function (event) { if (event.clientX>0 && event.clientY>0) self.hide(); });
$(window).resize(function () {
setTimeout('$(document).click()',0);
@@ -130,8 +125,7 @@ var BuildingBlock = Widget.extend({
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.$snippet.find('.scroll:first > ul li:eq('+(event.keyCode-49)+') a').trigger("click");
self.show();
self.$('.scroll:first > ul li:eq('+(event.keyCode-49)+') a').trigger("click");
event.preventDefault();
}
});
@@ -188,22 +182,19 @@ var BuildingBlock = Widget.extend({
var self = this;
var url = this._get_snippet_url();
if (!url || !url.length) {
this.$snippet.detach();
this.$el.detach();
return;
}
this.$el.find("#o_left_bar").addClass("hidden");
return ajax.jsonRpc(url, 'call', {}).then(function (html) {
self.compute_snippet_templates(html);
self.trigger("snippets:ready");
}, function () {
self.$snippet.hide();
console.warn('Snippets template not found:', url);
});
},
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");
@@ -309,16 +300,14 @@ var BuildingBlock = Widget.extend({
// hide scroll if no snippets defined
if (!number) {
this.$snippet.detach();
} else {
this.$el.find("#o_left_bar").removeClass("hidden");
this.$el.detach();
}
$("body").toggleClass("editor_has_snippets", !!number);
// select all default text to edit (if snippet default text)
self.$snippets.find('.oe_snippet_body, .oe_snippet_body *')
.contents()
.filter(function() {
.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) {
@@ -328,7 +317,6 @@ var BuildingBlock = Widget.extend({
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], [data-oe-type]').each(function () {
@@ -339,14 +327,13 @@ var BuildingBlock = Widget.extend({
}
}
});
// end
$html.find('.o_not_editable').attr("contentEditable", false);
$left_bar.html($html);
this.$el.html($html);
// animate for list of snippet blocks
$left_bar.on('click', '.scroll-link', function (event) {
this.$el.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);
@@ -367,55 +354,33 @@ var BuildingBlock = Widget.extend({
}
$(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", "100%");
} 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;
cover_target: function ($el, $target) {
if ($el.data('not-cover_target')) {
return;
}
var pos = $target.offset();
var mt = parseInt($target.css("margin-top") || 0);
var mb = parseInt($target.css("margin-bottom") || 0);
var width = $target.outerWidth();
var bigger = pos.left+width > $("body").outerWidth()-8;
$el.css({
'width': width,
'top': pos.top - mt - 5,
'left': pos.left-1
width: $target.outerWidth(),
left: pos.left,
top: pos.top - mt,
});
$el.find(".oe_handle.e,.oe_handle.w").css({'height': $target.outerHeight() + mt + mb+1});
if (bigger) {
$el.find(".oe_handle.e").css({right: 0, margin: 0})
.find("div").css({right: 0, left: 'auto'});
} else {
$el.find(".oe_handle.e").css({right: "", margin: ""})
.find("div").css({right: "", left: ""});
}
$el.find(".oe_handle.s").css({'top': $target.outerHeight() + mt + mb});
$el.find(".oe_handle.size").css({'top': $target.outerHeight() + mt});
$el.find(".oe_handle.s,.oe_handle.n").css({'width': width-2});
$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.$snippet.find(".o_panel").each(function () {
this.$(".o_panel").each(function () {
var catcheck = false;
var $category = $(this);
$category.find(".oe_snippet_body").each(function () {
@@ -450,15 +415,6 @@ var BuildingBlock = Widget.extend({
$('#oe_snippets .scroll a[data-toggle="tab"][href="#' + $category.attr("id") + '"]').toggle(catcheck);
});
},
show: function () {
var self = this;
this.make_active(false);
this.$el.addClass("o_open");
this.show_blocks();
},
hide: function () {
this.$el.removeClass("o_open");
},
bind_snippet_click_editor: function () {
var self = this;
var snipped_event_flag;
@@ -541,7 +497,7 @@ var BuildingBlock = Widget.extend({
this.cover_target($snippet.data('overlay'), $snippet);
this.snippet_focus($snippet);
}
this.$snippet.trigger('snippet-activated', $snippet);
this.$el.trigger('snippet-activated', $snippet);
if ($snippet) {
$snippet.trigger('snippet-activated', $snippet);
}
@@ -554,7 +510,7 @@ var BuildingBlock = Widget.extend({
},
// activate drag and drop for the snippets in the snippet toolbar
make_snippet_draggable: function($snippets){
make_snippet_draggable: function ($snippets) {
var self = this;
var $tumb = $snippets.find(".oe_snippet_thumbnail_img:first");
var left = $tumb.outerWidth()/2;
@@ -572,8 +528,7 @@ var BuildingBlock = Widget.extend({
'left': left,
'top': top
},
start: function(){
self.hide();
start: function () {
dropped = false;
// snippet_selectors => to get drop-near, drop-in
$snippet = $(this);
@@ -602,23 +557,25 @@ var BuildingBlock = Widget.extend({
return;
}
self.make_active(false);
self.activate_insertion_zones($selector_siblings, $selector_children);
$('.oe_drop_zone').droppable({
over: function(){
over: function () {
dropped = true;
$(this).first().after($toInsert);
$(this).first().after($toInsert).addClass('hidden');
},
out: function(){
out: function () {
var prev = $toInsert.prev();
if(this === prev[0]){
if(this === prev[0]) {
dropped = false;
$toInsert.detach();
$(this).removeClass('hidden');
}
}
},
});
},
stop: function(ev, ui){
stop: function (ev, ui) {
$toInsert.removeClass('oe_snippet_body');
if (! dropped && self.$editable.find('.oe_drop_zone') && ui.position.top > 3) {
@@ -658,7 +615,7 @@ var BuildingBlock = Widget.extend({
$target = $toInsert;
setTimeout(function () {
self.$snippet.trigger('snippet-dropped', $target);
self.$el.trigger('snippet-dropped', $target);
animation.start(true, $target);
@@ -693,8 +650,8 @@ var BuildingBlock = Widget.extend({
},
// return the original snippet in the editor bar from a snippet id (string)
get_snippet_from_id: function(id){
return $('.oe_snippet').filter(function(){
get_snippet_from_id: function (id) {
return $('.oe_snippet').filter(function () {
return $(this).data('option') === id;
}).first();
},
@@ -704,12 +661,12 @@ var BuildingBlock = Widget.extend({
// 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){
activate_insertion_zones: function ($selector_siblings, $selector_children) {
var self = this;
var zone_template = $("<div class='oe_drop_zone oe_insert'></div>");
var zone_template = $("<div class='oe_drop_zone oe_insert'/>");
if ($selector_children) {
$selector_children.each(function (){
$selector_children.each(function () {
var $zone = $(this);
var css = window.getComputedStyle(this);
var float = css.float || css.cssFloat;
@@ -719,7 +676,7 @@ var BuildingBlock = Widget.extend({
var node = $drop[0].previousSibling;
var test = !!(node && ((!node.tagName && node.textContent.match(/\S/)) || node.tagName === "BR"));
if (test) {
$drop.addClass("oe_vertical oe_vertical_text").css({
$drop.addClass("oe_vertical").css({
'height': parseInt(window.getComputedStyle($zone[0]).lineHeight),
'float': 'none',
'display': 'inline-block'
@@ -734,7 +691,7 @@ var BuildingBlock = Widget.extend({
var node = $drop[0].nextSibling;
var test = !!(node && ((!node.tagName && node.textContent.match(/\S/)) || node.tagName === "BR"));
if (test) {
$drop.addClass("oe_vertical oe_vertical_text").css({
$drop.addClass("oe_vertical").css({
'height': parseInt(window.getComputedStyle($zone[0]).lineHeight),
'float': 'none',
'display': 'inline-block'
@@ -752,20 +709,20 @@ var BuildingBlock = Widget.extend({
}
if ($selector_siblings) {
$selector_siblings.filter(':not(.oe_drop_zone):not(.oe_drop_clone)').each(function (){
$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){
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){
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));
@@ -785,7 +742,7 @@ var BuildingBlock = Widget.extend({
// 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 (){
$zones.each(function () {
var zone = $(this);
var prev = zone.prev();
var next = zone.next();
@@ -799,12 +756,12 @@ var BuildingBlock = Widget.extend({
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') ){
&& (float_next === 'left' || float_next === 'right') ) {
zone.remove();
}else if( !( disp_prev === null
|| disp_next === null
|| disp_prev === 'block'
|| disp_next === 'block' )){
|| disp_next === 'block' )) {
zone.remove();
}
});
@@ -812,21 +769,21 @@ var BuildingBlock = Widget.extend({
// 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){
activate_overlay_zones: function ($targets) {
var self = this;
function is_visible($el){
function is_visible($el) {
return $el.css('display') != 'none'
&& $el.css('opacity') != '0'
&& $el.css('visibility') != 'hidden';
}
// filter out invisible elements
$targets = $targets.filter(function(){ return is_visible($(this)); });
$targets = $targets.filter(function () { return is_visible($(this)); });
// filter out elements with invisible parents
$targets = $targets.filter(function(){
var parents = $(this).parents().filter(function(){ return !is_visible($(this)); });
$targets = $targets.filter(function () {
var parents = $(this).parents().filter(function () { return !is_visible($(this)); });
return parents.length === 0;
});
@@ -839,7 +796,7 @@ var BuildingBlock = Widget.extend({
if (document.body && document.body.addEventListener) {
$zone.on("click mousedown mousedown", function passThrough(event) {
event.preventDefault();
$target.each(function() {
$target.each(function () {
// check if clicked point (taken from event) is inside element
event.srcElement = this;
$(this).trigger(event.type);
@@ -849,8 +806,8 @@ var BuildingBlock = Widget.extend({
}
$zone.appendTo('#oe_manipulators');
$zone.data('target',$target);
$target.data('overlay',$zone);
$zone.data('target', $target);
$target.data('overlay', $zone);
var timer;
$target.closest('.o_editable').on("content_changed", function (event) {
@@ -890,7 +847,7 @@ var Editor = Class.extend({
},
// activate drag and drop for the snippets in the snippet toolbar
_drag_and_drop: function(){
_drag_and_drop: function () {
var self = this;
this.dropped = false;
this.$overlay.draggable({
@@ -902,7 +859,7 @@ var Editor = Class.extend({
left: 18,
top: 14
},
helper: function() {
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});
@@ -913,25 +870,24 @@ var Editor = Class.extend({
stop: _.bind(self._drag_and_drop_stop, self)
});
},
_drag_and_drop_after_insert_dropzone: function (){},
_drag_and_drop_active_drop_zone: function ($zones){
_drag_and_drop_after_insert_dropzone: function () {},
_drag_and_drop_active_drop_zone: function ($zones) {
var self = this;
$zones.droppable({
over: function(){
over: function () {
$(".oe_drop_zone.hide").removeClass("hide");
$(this).addClass("hide").first().after(self.$target);
self.dropped = true;
},
out: function(){
out: function () {
$(this).removeClass("hide");
self.$target.detach();
self.dropped = false;
},
});
},
_drag_and_drop_start: function (){
_drag_and_drop_start: function () {
var self = this;
self.buildingBlock.hide();
self.buildingBlock.editor_busy = true;
self.size = {
width: self.$target.width(),
@@ -952,6 +908,7 @@ var Editor = Class.extend({
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');
@@ -959,7 +916,7 @@ var Editor = Class.extend({
self._drag_and_drop_after_insert_dropzone();
self._drag_and_drop_active_drop_zone($('.oe_drop_zone'));
},
_drag_and_drop_stop: function (){
_drag_and_drop_stop: function () {
var self = this;
var $dropzone = this.$target.prev();
var prev = $dropzone.length && $dropzone[0].previousSibling;
@@ -984,7 +941,7 @@ var Editor = Class.extend({
$parent.prepend(this.$target);
}
for (var i in this.styles){
for (var i in this.styles) {
this.styles[i].on_move();
}
}
@@ -992,9 +949,9 @@ var Editor = Class.extend({
self.buildingBlock.editor_busy = false;
self.get_parent_block();
setTimeout(function () {
_.defer(function () {
self.buildingBlock.cover_target(self.$target.data('overlay'), self.$target);
},0);
});
},
load_style_options: function () {
@@ -1071,7 +1028,7 @@ var Editor = Class.extend({
this.$target.after($clone);
this.buildingBlock.call_for_all_snippets($clone, function (editor, $snippet) {
for (var i in editor.styles){
for (var i in editor.styles) {
editor.styles[i].on_clone($snippet);
}
});
@@ -1086,7 +1043,7 @@ var Editor = Class.extend({
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){
for (var i in editor.styles) {
editor.styles[i].on_remove();
}
});
@@ -1120,7 +1077,7 @@ var Editor = Class.extend({
* (after the insertion of this.$body, if this.$body exists)
*/
drop_and_build_snippet: function () {
for (var i in this.styles){
for (var i in this.styles) {
this.styles[i].drop_and_build_snippet();
}
},
@@ -1130,7 +1087,7 @@ var Editor = Class.extend({
*/
on_focus : function () {
this.$overlay.addClass('oe_active');
for (var i in this.styles){
for (var i in this.styles) {
this.styles[i].on_focus();
}
},
@@ -1139,7 +1096,7 @@ var Editor = Class.extend({
* This method is called when the user click outside the snippet in the dom, after a focus
*/
on_blur : function () {
for (var i in this.styles){
for (var i in this.styles) {
this.styles[i].on_blur();
}
this.$overlay.removeClass('oe_active');
File diff suppressed because it is too large Load Diff
@@ -977,7 +977,7 @@ $.summernote.pluginEvents.tab = function (event, editor, layoutInfo, outdent) {
$.summernote.pluginEvents.indent(event, editor, layoutInfo);
}
} else {
if (!outdent){
if (!outdent) {
if(dom.isText(r.sc)) {
var next = r.sc.splitText(r.so);
} else {
@@ -1876,11 +1876,11 @@ eventHandler.modules.toolbar.button.updateRecentColor = function (elBtn, sEvent,
font.style.color = sValue !== 'inherit' ? sValue : "";
}
} else {
font.className = font.className.replace(/(^|\s+)bg-\S+/, '');
if (sValue.indexOf('bg-') !== -1) {
font.className += ' ' + sValue;
font.style.backgroundColor = "";
} else {
font.className = font.className.replace(/(^|\s+)bg-\S+/, '');
font.style.backgroundColor = sValue !== 'inherit' ? sValue : "";
}
}
@@ -1905,7 +1905,7 @@ eventHandler.modules.editor.redo = function ($popover) {
// use image toolbar if current range is on image
var fn_editor_currentstyle = eventHandler.modules.editor.currentStyle;
eventHandler.modules.editor.currentStyle = function(target) {
eventHandler.modules.editor.currentStyle = function (target) {
var styleInfo = fn_editor_currentstyle.apply(this, arguments);
// with our changes for inline editor, the targeted element could be a button of the editor
if(!styleInfo.image || !dom.isEditable(styleInfo.image)) {
@@ -116,7 +116,6 @@ var Translate = Widget.extend({
},
start: function () {
this._super();
this.$('button[data-action=save]').prop('disabled', true);
return this.edit();
},
setTarget: function ($target) {
@@ -158,7 +157,7 @@ var Translate = Widget.extend({
},
edit: function () {
var flag = false;
window.onbeforeunload = function(event) {
window.onbeforeunload = function (event) {
if ($('.o_editable.o_dirty').length && !flag) {
flag = true;
setTimeout(function () {flag=false;},0);
@@ -179,7 +178,6 @@ var Translate = Widget.extend({
var $node = $(node);
var trans = this.getTranlationObject($node[0]);
$node.toggleClass('o_dirty', trans.value !== $node.html().replace(/[ \t\n\r]+/, ' '));
this.$('button[data-action=save]').prop('disabled', !$('.o_editable.o_dirty').length);
},
getTranlationObject: function (node) {
var $node = $(node);
+19 -19
View File
@@ -39,8 +39,8 @@ var Dialog = Widget.extend({
close: function () {
this.$el.modal('hide');
},
stop_escape: function(event) {
if($(".modal.in").length>0 && event.which == 27){
stop_escape: function (event) {
if($(".modal.in").length>0 && event.which == 27) {
event.stopPropagation();
}
}
@@ -72,7 +72,7 @@ var alt = Dialog.extend({
},
});
var click_event = function(el, type) {
var click_event = function (el, type) {
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent(type, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, el);
el.dispatchEvent(evt);
@@ -239,14 +239,14 @@ var ImageDialog = Widget.extend({
},
'click button.filepicker': function () {
var filepicker = this.$('input[type=file]');
if (!_.isEmpty(filepicker)){
if (!_.isEmpty(filepicker)) {
filepicker[0].click();
}
},
'click .js_disable_optimization': function () {
this.$('input[name="disable_optimization"]').val('1');
var filepicker = this.$('button.filepicker');
if (!_.isEmpty(filepicker)){
if (!_.isEmpty(filepicker)) {
filepicker[0].click();
}
},
@@ -256,8 +256,8 @@ var ImageDialog = Widget.extend({
'keyup input.url': "change_input",
//'change select.image-style': 'preview_image',
'click .existing-attachments [data-src]': 'select_existing',
'click .existing-attachment-remove': 'try_remove',
'keydown.dismiss.bs.modal': function(){},
'click .o_existing_attachment_remove': 'try_remove',
'keydown.dismiss.bs.modal': function () {},
}),
init: function (parent, media, options) {
this._super();
@@ -417,7 +417,7 @@ var ImageDialog = Widget.extend({
this.$('button.filepicker').removeClass('btn-danger btn-success');
this.$('form').submit();
},
file_selected: function(attachment, error) {
file_selected: function (attachment, error) {
var $button = this.$('button.filepicker');
if (!error) {
$button.addClass('btn-success');
@@ -497,14 +497,14 @@ var ImageDialog = Widget.extend({
},
selected_existing: function () {
var self = this;
this.$('.existing-attachment-cell.media_selected').removeClass("media_selected");
var $select = this.$('.existing-attachment-cell [data-src]').filter(function () {
this.$('.o_existing_attachment_cell.o_selected').removeClass("o_selected");
var $select = this.$('.o_existing_attachment_cell [data-src]').filter(function () {
var $img = $(this);
return !!_.find(self.images, function (v) {
return (v.url === $img.data("src") || ($img.data("url") && v.url === $img.data("url")) || v.id === $img.data("id"));
});
});
$select.closest('.existing-attachment-cell').addClass("media_selected");
$select.closest('.o_existing_attachment_cell').addClass("o_selected");
return $select;
},
try_remove: function (e) {
@@ -535,7 +535,7 @@ var ImageDialog = Widget.extend({
var cacheCssSelectors = {};
var getCssSelectors = function(filter) {
var getCssSelectors = function (filter) {
var css = [];
if (cacheCssSelectors[filter]) {
return cacheCssSelectors[filter];
@@ -580,7 +580,7 @@ var getCssSelectors = function(filter) {
}
return cacheCssSelectors[filter] = css;
};
var computeFonts = _.once(function() {
var computeFonts = _.once(function () {
_.each(fontIcons, function (data) {
data.cssData = getCssSelectors(data.parser);
data.alias = [];
@@ -628,14 +628,14 @@ var fontIconsDialog = Widget.extend({
e.stopPropagation();
this.$('#fa-icon').val(e.target.getAttribute('data-id'));
$(".font-icons-icon").removeClass("font-icons-selected");
$(e.target).addClass("font-icons-selected");
$(".font-icons-icon").removeClass("o_selected");
$(e.target).addClass("o_selected");
},
'keydown.dismiss.bs.modal': function(){},
'keydown.dismiss.bs.modal': function () {},
}),
// extract list of font (like awsome) from the cheatsheet.
renderElement: function() {
renderElement: function () {
this.iconsParser = fontIcons;
this.icons = _.flatten(_.map(fontIcons, function (data) {
return data.icons;
@@ -750,7 +750,7 @@ var fontIconsDialog = Widget.extend({
continue;
case '': continue;
default:
$(".font-icons-icon").removeClass("font-icons-selected").filter("[data-alias*=',"+cls+",']").addClass("font-icons-selected");
$(".font-icons-icon").removeClass("o_selected").filter("[data-alias*=',"+cls+",']").addClass("o_selected");
for (var k=0; k<this.icons.length; k++) {
if (this.icons.indexOf(cls) !== -1) {
this.$('#fa-icon').val(cls);
@@ -852,7 +852,7 @@ var VideoDialog = Widget.extend({
'keyup input#urlvideo': 'change_input',
'change input#embedvideo': 'change_input',
'keyup input#embedvideo': 'change_input',
'keydown.dismiss.bs.modal': function(){},
'keydown.dismiss.bs.modal': function () {},
}),
init: function (parent, media) {
this._super();
+146 -364
View File
@@ -1,23 +1,19 @@
<templates id="template" xml:space="preserve">
<t t-name="web_editor.editorbar">
<div class="o_css_editor navbar navbar-fixed-top hidden-xs" id="web_editor-top-edit">
<div id="web_editor-toolbars" />
<div id="web_editor-top-edit" class="o_css_editor">
<div id="web_editor-toolbars"/>
<form class="navbar-form text-muted">
<div id="web_editor-top-actions">
<a class="btn btn-link btn-xs" data-action="cancel" href="#">
<i class="material-icons">clear</i>DISCARD</a>
<button class="btn full compl btn-xs" data-action="save" type="button">
<i class="fa fa-floppy-o"></i> SAVE</button>
</div>
<button type="button" class="btn btn-sm btn-default" data-action="cancel"><i class="fa fa-times"/> Discard</button>
<button type="button" class="btn btn-sm btn-primary" data-action="save"><i class="fa fa-floppy-o"/> Save</button>
</form>
</div>
</t>
<t t-name="web_editor.dialog">
<div aria-hidden="true" class="modal web_editor-dialog" role="dialog" tabindex="-1">
<div class="modal o_website_modal web_editor-dialog" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button aria-hidden="true" class="close" data-dismiss="modal" type="button">×</button>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 class="modal-title">
<t t-esc="title"/>
</h3>
@@ -26,350 +22,129 @@
<t t-raw="0"/>
</div>
<div class="modal-footer">
<button class="btn btn-primary save" t-if="!button" type="button">Save</button>
<button class="btn btn-primary save" t-if="button" type="button">
<t t-raw="button"/>
</button>
<button class="btn btn-sm btn-primary save" t-if="!button" type="button">Save</button>
<button class="btn btn-sm btn-primary save" t-if="button" type="button"><t t-raw="button"/></button>
<button class="btn hidden wait" disabled="disabled" type="button"/>
<span>or </span>
<a aria-hidden="true" data-dismiss="modal" href="#">Discard</a>
<a class="btn btn-sm btn-default" data-dismiss="modal" href="#" aria-hidden="true">Discard</a>
</div>
</div>
</div>
</div>
</t>
<t t-name="web_editor.dialog.background_position">
<div aria-hidden="true" class="modal website_modal web_editor-background_position" role="dialog" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button aria-hidden="true" class="close" data-dismiss="modal" type="button">×</button>
<h3 class="modal-title">Background Image Options</h3>
</div>
<div class="modal-body">
<div class="panel-group" id="bg_image_opt_accordition" role="tablist" aria-multiselectable="true">
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="heading_cover">
<label role="button" class="radio inline" data-toggle="collapse" data-parent="#bg_image_opt_accordition" href="#collapse_cover">
<input id="radio1" class="opt_select" name="rdo" type="radio"/>COVER</label>
</div>
<div class="panel-collapse collapse" role="tabpanel" id="collapse_cover">
<div class="panel-body">
<div t-name="web_editor.dialog.background_position" class="o_bg_img_opt_modal">
<label class="radio-inline"><input type="radio" name="o_bg_img_opt" value="cover"/> Cover</label>
<label class="radio-inline"><input type="radio" name="o_bg_img_opt" value="contain"/> Contain</label>
<label class="radio-inline"><input type="radio" name="o_bg_img_opt" value="custom"/> Custom</label>
<a class="help-controll collapsed" role="button" data-toggle="collapse" href="#cover_help" aria-expanded="false" aria-controls="cover_help"><i class="material-icons">help</i></a>
<div class="help collapse" id="cover_help">
<div class="simulator cover_bg">
<div class="bg"></div>
<div class="el"></div>
</div>
<div class="help-text">
<p>The 'cover' method scale the background image to be as large as possible so that the background area is completely covered by the background image. Some parts of the background image may not be in view</p>
</div>
</div>
<p><strong>Assigning a focal point to ensure that the targeted area will be always visible</strong></p>
<div class="cover_editing_container">
<h6>Click on the picture</h6>
<div class="object">
<span class="grid grid-1"/>
<span class="grid grid-2"/>
<span class="grid grid-3"/>
<span class="grid grid-4"/>
<span class="focus_point"/>
<div class="ui_info">X: <span class="x"/> Y: <span class="y"/></div>
</div>
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="heading_contain">
<label role="button" class="radio inline" data-toggle="collapse" data-parent="#bg_image_opt_accordition" href="#collapse_contain">
<input id="radio2" class="opt_select" name="rdo" type="radio"/>CONTAIN</label>
</div>
<div class="panel-collapse collapse" role="tabpanel" id="collapse_contain">
<div class="panel-body">
<a class="help-controll collapsed" role="button" data-toggle="collapse" href="#contain_help" aria-expanded="false" aria-controls="contain_help"><i class="material-icons">help</i></a>
<div class="help collapse" id="contain_help">
<div class="simulator contain_bg">
<div class="bg"></div>
<div class="el"></div>
</div>
<div class="help-text">
<p>Scale the image to the largest size such that both its width and its height can fit inside the content area</p>
</div>
</div>
<form class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label" for="repeatInput">Repeat</label>
<div class="col-sm-5">
<div class="checkbox">
<label>
<input id="contain_repeat" type="checkbox"/>
</label>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="heading_custom">
<label role="button" class="radio inline" data-toggle="collapse" data-parent="#bg_image_opt_accordition" href="#collapse_custom">
<input id="radio3" class="opt_select" name="rdo" type="radio"/>CUSTOM</label>
</div>
<div class="panel-collapse collapse" role="tabpanel" id="collapse_custom">
<div class="panel-body">
<form class="form-horizontal">
<fieldset>
<legend>Background size</legend>
<p>Sets the width and height of the background image in percent of the parent element.</p>
<div class="form-group">
<label class="col-sm-3 control-label" for="custom_size_x">Background width</label>
<div class="col-sm-5">
<div class="input-group">
<input type="number" min="0" max="100" class="form-control input-sm" id="custom_size_x" placeholder="auto"/>
<div class="input-group-addon">%</div>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="custom_size_y">Background height</label>
<div class="col-sm-5">
<div class="input-group">
<input type="number" min="0" max="100" class="form-control input-sm" id="custom_size_y" placeholder="auto"/>
<div class="input-group-addon">%</div>
</div>
</div>
</div>
</fieldset>
<fieldset>
<legend>Background position</legend>
<p>Set the starting position of the background image.</p>
<div class="form-group">
<label class="col-sm-3 control-label" for="custom_pos_x">Horizontal</label>
<div class="col-sm-5">
<div class="input-group">
<input type="number" min="0" max="100" class="form-control input-sm" id="custom_pos_x" placeholder="auto"/>
<div class="input-group-addon">%</div>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="custom_pos_x">Vertical</label>
<div class="col-sm-5">
<div class="input-group">
<input type="number" min="0" max="100" class="form-control input-sm" id="custom_pos_y" placeholder="auto"/>
<div class="input-group-addon">%</div>
</div>
</div>
</div>
</fieldset>
<fieldset>
<legend>Background repeat</legend>
<p>Define if/how the background image will be repeated</p>
<select class="form-control" id="custom_repeat">
<option value="o_bg_img_no_repeat">No repeat</option>
<option value="o_bg_img_repeat">Repeat both</option>
<option value="o_bg_img_repeat_x">Repeat x</option>
<option value="o_bg_img_repeat_y">Repeat y</option>
</select>
</fieldset>
</form>
</div>
</div>
</div> <!-- / .panel -->
</div> <!-- / .panel-group -->
<input id="pos_x" type="hidden"/>
<input id="pos_y" type="hidden"/>
<input id="bg_size" type="hidden"/>
</div> <!-- /.modal-body -->
<div class="modal-footer">
<button class="btn btn-primary save" data-dismiss="modal" type="button">Save</button> or <a aria-hidden="true" data-dismiss="modal" href="#">Discard</a>
</div>
<div class="o_bg_img_opt" data-value="cover">
<a class="help-control collapsed" role="button" data-toggle="collapse" href="#cover_help" aria-expanded="false" aria-controls="cover_help"><span class="fa fa-question-circle"/></a>
<div class="help collapse" id="cover_help">
<div class="simulator cover_bg">
<div class="bg"/>
<div class="el"/>
</div>
<p class="help-text">Scale the image to be as large as it needs to fill the whole content area. Part of the image may not be visible.</p>
</div>
<p><strong>Assigning a focal point to ensure that the targeted area will be always visible</strong></p>
<div class="o_bg_img_opt_cover_edition">
<h6>Click on the picture</h6>
<div class="o_bg_img_opt_object">
<span class="grid grid-1"/>
<span class="grid grid-2"/>
<span class="grid grid-3"/>
<span class="grid grid-4"/>
<span class="o_focus_point"/>
<div class="o_bg_img_opt_ui_info">X: <span class="o_x"/> Y: <span class="o_y"/></div>
</div>
</div>
</div>
</t>
<t t-name="web_editor.dialog.background_position">
<div aria-hidden="true" class="modal website_modal web_editor-background_position" role="dialog" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button aria-hidden="true" class="close" data-dismiss="modal" type="button">×</button>
<h3 class="modal-title">Background Image Options</h3>
</div>
<div class="modal-body">
<div class="panel-group" id="bg_image_opt_accordition" role="tablist" aria-multiselectable="true">
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="heading_cover">
<label role="button" class="radio inline" data-toggle="collapse" data-parent="#bg_image_opt_accordition" href="#collapse_cover">
<input id="radio1" class="opt_select" name="rdo" type="radio"/>COVER</label>
</div>
<div class="panel-collapse collapse" role="tabpanel" id="collapse_cover">
<div class="panel-body">
<a class="help-controll collapsed" role="button" data-toggle="collapse" href="#cover_help" aria-expanded="false" aria-controls="cover_help"><i class="material-icons">help</i></a>
<div class="help collapse" id="cover_help">
<div class="simulator cover_bg">
<div class="bg"></div>
<div class="el"></div>
</div>
<div class="help-text">
<p>The 'cover' method scale the background image to be as large as possible so that the background area is completely covered by the background image. Some parts of the background image may not be in view</p>
</div>
</div>
<p><strong>Assigning a focal point to ensure that the targeted area will be always visible</strong></p>
<div class="cover_editing_container">
<h6>Click on the picture</h6>
<div class="object">
<span class="grid grid-1"/>
<span class="grid grid-2"/>
<span class="grid grid-3"/>
<span class="grid grid-4"/>
<span class="focus_point"/>
<div class="ui_info">X: <span class="x"/> Y: <span class="y"/></div>
</div>
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="heading_contain">
<label role="button" class="radio inline" data-toggle="collapse" data-parent="#bg_image_opt_accordition" href="#collapse_contain">
<input id="radio2" class="opt_select" name="rdo" type="radio"/>CONTAIN</label>
</div>
<div class="panel-collapse collapse" role="tabpanel" id="collapse_contain">
<div class="panel-body">
<a class="help-controll collapsed" role="button" data-toggle="collapse" href="#contain_help" aria-expanded="false" aria-controls="contain_help"><i class="material-icons">help</i></a>
<div class="help collapse" id="contain_help">
<div class="simulator contain_bg">
<div class="bg"></div>
<div class="el"></div>
</div>
<div class="help-text">
<p>Scale the image to the largest size such that both its width and its height can fit inside the content area</p>
</div>
</div>
<form class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label" for="repeatInput">Repeat</label>
<div class="col-sm-5">
<div class="checkbox">
<label>
<input id="contain_repeat" type="checkbox"/>
</label>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="heading_custom">
<label role="button" class="radio inline" data-toggle="collapse" data-parent="#bg_image_opt_accordition" href="#collapse_custom">
<input id="radio3" class="opt_select" name="rdo" type="radio"/>CUSTOM</label>
</div>
<div class="panel-collapse collapse" role="tabpanel" id="collapse_custom">
<div class="panel-body">
<form class="form-horizontal">
<fieldset>
<legend>Background size</legend>
<p>Sets the width and height of the background image in percent of the parent element.</p>
<div class="form-group">
<label class="col-sm-3 control-label" for="custom_size_x">Background width</label>
<div class="col-sm-5">
<div class="input-group">
<input type="number" min="0" max="100" class="form-control input-sm" id="custom_size_x" placeholder="auto"/>
<div class="input-group-addon">%</div>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="custom_size_y">Background height</label>
<div class="col-sm-5">
<div class="input-group">
<input type="number" min="0" max="100" class="form-control input-sm" id="custom_size_y" placeholder="auto"/>
<div class="input-group-addon">%</div>
</div>
</div>
</div>
</fieldset>
<fieldset>
<legend>Background position</legend>
<p>Set the starting position of the background image.</p>
<div class="form-group">
<label class="col-sm-3 control-label" for="custom_pos_x">Horizontal</label>
<div class="col-sm-5">
<div class="input-group">
<input type="number" min="0" max="100" class="form-control input-sm" id="custom_pos_x" placeholder="auto"/>
<div class="input-group-addon">%</div>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="custom_pos_x">Vertical</label>
<div class="col-sm-5">
<div class="input-group">
<input type="number" min="0" max="100" class="form-control input-sm" id="custom_pos_y" placeholder="auto"/>
<div class="input-group-addon">%</div>
</div>
</div>
</div>
</fieldset>
<fieldset>
<legend>Background repeat</legend>
<p>Define if/how the background image will be repeated</p>
<select class="form-control" id="custom_repeat">
<option value="o_bg_img_no_repeat">No repeat</option>
<option value="o_bg_img_repeat">Repeat both</option>
<option value="o_bg_img_repeat_x">Repeat x</option>
<option value="o_bg_img_repeat_y">Repeat y</option>
</select>
</fieldset>
</form>
</div>
</div>
</div> <!-- / .panel -->
</div> <!-- / .panel-group -->
<input id="pos_x" type="hidden"/>
<input id="pos_y" type="hidden"/>
<input id="bg_size" type="hidden"/>
</div> <!-- /.modal-body -->
<div class="modal-footer">
<button class="btn btn-primary save" data-dismiss="modal" type="button">Save</button> or <a aria-hidden="true" data-dismiss="modal" href="#">Discard</a>
</div>
<div class="o_bg_img_opt" data-value="contain">
<a class="help-control collapsed" role="button" data-toggle="collapse" href="#contain_help" aria-expanded="false" aria-controls="contain_help"><span class="fa fa-question-circle"/></a>
<div class="help collapse" id="contain_help">
<div class="simulator contain_bg">
<div class="bg"/>
<div class="el"/>
</div>
<p class="help-text">Scale the image to the largest size such that both its width and height can fit inside the content area</p>
</div>
<form class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label" for="repeatInput">Repeat</label>
<div class="col-sm-5">
<div class="checkbox">
<label>
<input type="checkbox" id="o_bg_img_opt_contain_repeat"/>
</label>
</div>
</div>
</div>
</form>
</div>
</t>
<form class="o_bg_img_opt form-horizontal" data-value="custom">
<fieldset>
<legend>Background size</legend>
<p>Sets the width and height of the background image in percent of the parent element.</p>
<div class="form-group">
<label class="col-sm-3 control-label" for="o_bg_img_opt_custom_size_x">Background width</label>
<div class="col-sm-5">
<div class="input-group">
<input type="number" min="0" max="100" class="form-control input-sm" id="o_bg_img_opt_custom_size_x" placeholder="auto"/>
<div class="input-group-addon">%</div>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="o_bg_img_opt_custom_size_y">Background height</label>
<div class="col-sm-5">
<div class="input-group">
<input type="number" min="0" max="100" class="form-control input-sm" id="o_bg_img_opt_custom_size_y" placeholder="auto"/>
<div class="input-group-addon">%</div>
</div>
</div>
</div>
</fieldset>
<fieldset>
<legend>Background position</legend>
<p>Set the starting position of the background image.</p>
<div class="form-group">
<label class="col-sm-3 control-label" for="o_bg_img_opt_custom_pos_x">Horizontal</label>
<div class="col-sm-5">
<div class="input-group">
<input type="number" min="0" max="100" class="form-control input-sm" id="o_bg_img_opt_custom_pos_x" placeholder="auto"/>
<div class="input-group-addon">%</div>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="o_bg_img_opt_custom_pos_y">Vertical</label>
<div class="col-sm-5">
<div class="input-group">
<input type="number" min="0" max="100" class="form-control input-sm" id="o_bg_img_opt_custom_pos_y" placeholder="auto"/>
<div class="input-group-addon">%</div>
</div>
</div>
</div>
</fieldset>
<fieldset>
<legend>Background repeat</legend>
<p>Define if/how the background image will be repeated</p>
<select class="form-control" id="o_bg_img_opt_custom_repeat">
<option value="">No repeat</option>
<option value="o_bg_img_opt_repeat">Repeat both</option>
<option value="o_bg_img_opt_repeat_x">Repeat x</option>
<option value="o_bg_img_opt_repeat_y">Repeat y</option>
</select>
</fieldset>
</form>
</div>
<t t-name="web_editor.dialog.media">
<div aria-hidden="true" class="modal note-image-dialog" role="dialog" tabindex="-1">
<div class="modal-dialog select-media">
<div class="modal note-image-dialog o_website_modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg o_select_media_dialog">
<div class="modal-content">
<div class="modal-header">
<button aria-hidden="true" class="close" data-dismiss="modal" type="button">×</button>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 class="modal-title">Select a Media</h3>
</div>
<div class="modal-body">
@@ -378,7 +153,7 @@
<li><a href="#editor-media-document" data-toggle="tab">Document</a></li>
<li><a href="#editor-media-icon" data-toggle="tab">Pictogram</a></li>
<li><a href="#editor-media-video" data-toggle="tab">Video</a></li>
<li class="search" style="float: right;">
<li class="search">
<ul class="pager mb0 mt0">
<li class="previous disabled">
<a href="#">← Previous</a>
@@ -388,10 +163,11 @@
</li>
</ul>
</li>
<li class="search" style="float: right;">
<li class="search">
<form action="#">
<div class="form-group font-icons fa fa-search mb0">
<div class="form-group">
<input class="form-control" id="icon-search" type="search"/>
<span class="fa fa-search"/>
</div>
</form>
</li>
@@ -399,15 +175,16 @@
<!-- Tab panes -->
<div class="tab-content">
<div class="tab-pane fade in active" id="editor-media-image"/>
<div class="tab-pane fade" id="editor-media-document"/>
<div class="tab-pane fade" id="editor-media-icon"/>
<div class="tab-pane fade" id="editor-media-video"/>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary save" type="button">Save</button>
<button class="btn hidden wait" disabled="disabled" type="button"/>or
<a aria-hidden="true" data-dismiss="modal" href="#">Discard</a></div>
<button class="btn btn-sm btn-primary save" type="button">Save</button>
<button class="btn btn-sm hidden wait" disabled="disabled" type="button"/>
<a class="btn btn-sm btn-default" data-dismiss="modal" href="#" aria-hidden="true">Discard</a>
</div>
</div>
</div>
</div>
@@ -425,7 +202,7 @@
<input type="file" name="upload" t-att-accept="widget.accept" multiple="multiple" style="position: absolute; opacity: 0; width: 1px; height: 1px;"/>
<input type="hidden" name="disable_optimization" value=""/>
<div class="btn-group">
<button class="btn btn-primary filepicker" type="button">Upload an image from your computer</button>
<button class="btn btn-primary filepicker" type="button">Upload an image</button>
<button class="btn btn-primary dropdown-toggle" data-toggle="dropdown" type="button">
<span class="caret"/>
<span class="sr-only">Alternate Upload</span>
@@ -447,7 +224,7 @@
</div>
</div>
</div>
<input name="func" type="hidden"/>
<input type="hidden" name="func"/>
<div class="help-block"/>
<div class="existing-attachments">
<t t-call="web_editor.dialog.image.existing"/>
@@ -457,11 +234,11 @@
<iframe class="hidden" name="fileframe" src="about:blank"/>
</t>
<t t-name="web_editor.dialog.image.existing">
<div aria-hidden="true" class="modal" role="dialog" tabindex="-1">
<div class="modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog select-image">
<div class="modal-content">
<div class="modal-header">
<button aria-hidden="true" class="close" data-dismiss="modal" type="button">×</button>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 class="modal-title">Select a Picture</h3>
</div>
<div class="modal-body has-error">
@@ -469,7 +246,7 @@
<div class="help-block"/>
</div>
<div class="modal-footer">
<a aria-hidden="true" data-dismiss="modal" href="#">Discard</a>
<a data-dismiss="modal" href="#" aria-hidden="true">Discard</a>
</div>
</div>
</div>
@@ -478,8 +255,8 @@
<t t-name="web_editor.dialog.image.existing.content">
<div class="existing-attachments">
<div class="row mt16" t-as="row" t-foreach="rows">
<div class="col-sm-2 existing-attachment-cell" t-as="attachment" t-foreach="row">
<i class="fa fa-times existing-attachment-remove" t-att-data-id="attachment.id"/>
<div class="col-sm-2 o_existing_attachment_cell" t-as="attachment" t-foreach="row">
<i class="fa fa-times o_existing_attachment_remove" t-att-data-id="attachment.id"/>
<div class="o_attachment_border"><div t-att-data-src="attachment.src" t-att-data-url="attachment.url" t-att-alt="attachment.name" t-att-title="attachment.name" t-att-data-id="attachment.id" t-att-data-mimetype="attachment.mimetype" class="o_image"/></div>
</div>
</div>
@@ -499,39 +276,37 @@
</div>
</t>
<t t-name="web_editor.discard">
<div aria-hidden="true" class="modal" role="dialog" tabindex="-1">
<div class="modal o_website_modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button aria-hidden="true" class="close" data-dismiss="modal" type="button">×</button>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 class="modal-title">Discard edition</h3>
</div>
<div class="modal-body">
<p>If you discard the current edition,
<em>all</em>
unsaved changes will be lost.</p>
<p>If you discard the current edition, <em>all</em> unsaved changes will be lost.</p>
<p>You can cancel to return to the edition mode.</p>
</div>
<div class="modal-footer">
<button class="btn btn-danger" type="button">Discard</button>or
<a aria-hidden="true" data-dismiss="modal" href="#">Cancel</a></div>
<button class="btn btn-sm btn-danger" type="button">Discard</button>
<a class="btn btn-sm btn-default" data-dismiss="modal" href="#" aria-hidden="true">Cancel</a>
</div>
</div>
</div>
</div>
</t>
<t t-name="web_editor.dialog.alt">
<t t-call="web_editor.dialog">
<t t-set="title">Change media Alt and Title</t>
<t t-set="title">Change media description and tooltip</t>
<form action="#" class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label" for="alt">Alt:</label>
<label class="col-sm-2 control-label" for="alt">Description</label>
<div class="col-sm-9">
<input class="form-control" id="alt" required="required" t-att-value="widget.alt" type="text"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label" for="title">Title:</label>
<label class="col-sm-2 control-label" for="title">Tooltip</label>
<div class="col-sm-9">
<input class="form-control" id="title" required="required" t-att-value="widget.title" type="text"/>
</div>
@@ -541,8 +316,8 @@
</t>
<t t-name="web_editor.dialog.font-icons">
<form action="#">
<input id="fa-icon" type="hidden"/>
<input id="fa-size" type="hidden" value="fa-1x"/>
<input type="hidden" id="fa-icon"/>
<input type="hidden" id="fa-size" value="fa-1x"/>
<div class="font-icons-icons">
<t t-call="web_editor.dialog.font-icons.icons">
<t t-set="iconsParser" t-value="widget.iconsParser"/>
@@ -691,4 +466,11 @@
</form>
</t>
</t>
<t t-name="web_editor.components.switch">
<label class="o_switch" t-att-for="id">
<input type="checkbox" t-att-id="id"/>
<span/>
<t t-if="label"><t t-esc="label"/></t>
</label>
</t>
</templates>
+27 -20
View File
@@ -13,36 +13,30 @@
</li>
</t>
<t t-name="web_editor.snippets">
<div id='web_editor_snippets' class="hidden-xs o_open">
<div id="o_left_bar"></div>
</div>
</t>
<t t-name="web_editor.snippet_overlay">
<div class="oe_overlay">
<div class="oe_handles">
<div class="oe_handle n readonly"/>
<div class="oe_handle e readonly"/>
<div class="oe_handle w readonly"/>
<div class="oe_handle s readonly"/>
<div class="oe_handle size readonly">
<div class="oe_handle_button auto_size">Auto Resize</div>
<div class="oe_handle_button size">Resize</div>
</div>
</div>
<div class="oe_overlay_options" contentEditable="false">
<div class="btn-group">
<a href="#" class="btn btn-default btn-sm oe_snippet_parent" title="Select Container Block"><i class="fa fa-upload"></i></a>
<a href="#" class="btn btn-default btn-sm oe_snippet_parent" title="Select Container Block"><i class="fa fa-upload"/></a>
<div class="dropdown oe_options hidden btn-group">
<a href="#" data-toggle="dropdown" class="btn btn-primary btn-sm" title="Customize">Customize </a>
<ul class="dropdown-menu" role="menu"></ul>
<a href="#" data-toggle="dropdown" class="btn btn-primary btn-sm" title="Customize">Customize</a>
<ul class="dropdown-menu" role="menu"/>
</div>
<a href="#" class="btn btn-default btn-sm oe_snippet_move" title="Drag to Move"><i class="fa fa-arrows ml4 mr4"></i></a>
<a href="#" class="btn btn-default btn-sm oe_snippet_clone" title="Duplicate Container"><i class="fa fa-files-o ml4 mr4"></i></a>
<a href="#" class="btn btn-default btn-sm oe_snippet_remove" title="Remove Block"><i class="fa fa-trash-o ml4 mr4"></i></a>
</div>
</div>
<div class='oe_handles'>
<div class='oe_handle n readonly'><div></div></div>
<div class='oe_handle e readonly'><div></div></div>
<div class='oe_handle w readonly'><div></div></div>
<div class='oe_handle size readonly'>
<div class="oe_handle_button auto_size">Auto Resize</div>
<div class="oe_handle_button size">Resize</div>
</div>
<div class='oe_handle s readonly'><div></div></div>
</div>
</div>
</t>
@@ -50,8 +44,21 @@
<div class='oe_snippet_manipulator'></div>
</t>
<!-- t-field options -->
<!-- options -->
<div t-name="web_editor.snippet.option.colorpicker" class="colorpicker">
<div class="note-palette-title">Background Color</div>
<div class="btn-group palette-reset">
<div class="note-color-reset" data-event="foreColor" data-value="inherit" title="None">
<i class="fa fa-ban"/>
</div>
</div>
<div class="o_colorpicker_sections">
<ul class="nav nav-pills o_colorpicker_section_menu"/>
<div class="tab-content o_colorpicker_section_tabs"/>
</div>
</div>
<!-- t-field options -->
<t t-name="web_editor.many2one.button">
<div class="dropdown">
<a href="#" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" data-hover="dropdown" title="Search Contact"><i class="fa fa-search"></i></a>
@@ -1,14 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<templates id="template" xml:space="preserve">
<t t-name="web_editor.translator">
<div id="web_editor-top-edit" class="o_css_editor o_translate navbar navbar-inverse navbar-fixed-top hidden-xs">
<form class="navbar-form text-muted">
<button type="button" data-action="save" class="btn btn-primary btn-xs">Save</button>
<span>or</span>
<a href="#" data-action="cancel" class="btn btn-link btn-xs">Discard</a>
</form>
</div>
<t t-name="web_editor.translator" t-extend="web_editor.editorbar">
<t t-jquery="#web_editor-top-edit">
$(this).addClass('o_translate');
</t>
<t t-jquery="#web_editor-toolbars" t-operation="replace"/>
</t>
<t t-name="web_editor.translator.attributes">
+34 -24
View File
@@ -110,34 +110,44 @@
</xpath>
</template>
<!-- color-picker -->
<!-- HTML class to hide option for one mode : only-text, only-bg -->
<!--
The web_editor.colorpicker template regroups section of colorpicker menu for website customization
(text foreground/background but also snippet background color option).
As it is presentend below, the colorpicker tag regroups a set of .o_colorpicker_section with name,
icon-class and icon-content as data. These will be used to build the colorpicker dropdowns.
Redefinition can edit section content, add sections or even remove them. If no section is found when
building a colorpicker dropdown, the template content will be used without changes as the colorpicker
dropdown content.
Sections should contain a set of button with a data-color attribute. When selecting such a button to
edit style, the "bg-x" class or the "text-x" will be automatically added.
-->
<template id="web_editor.colorpicker" name="Color-Picker">
<div class="colorpicker">
<div class="theme">
<button class="bg-accent">Accent <span></span></button>
<button class="bg-compl">Complementary<span></span></button>
<button class="bg-alpha">Alpha <span></span></button>
<button class="bg-beta">Beta <span></span></button>
<button class="bg-gamma">Gamma <span></span></button>
<colorpicker>
<div class="o_colorpicker_section" data-name="theme" data-icon-class="fa fa-flask">
<button data-color="alpha">Alpha</button>
<button data-color="beta">Beta</button>
<button data-color="gamma">Gamma</button>
<button data-color="delta">Delta</button>
<button data-color="epsilon">Epsilon</button>
</div>
<div class="grayscale">
<button class="bg-white">White <span></span></button>
<button class="bg-gray_lighter">Gray Lighter <span></span></button>
<button class="bg-gray_light">Gray Light <span></span></button>
<button class="bg-gray">Gray <span></span></button>
<button class="bg-gray_dark">Gray Dark <span></span></button>
<button class="bg-gray_darker">Gray Darker <span></span></button>
<button class="bg-black">Black <span></span></button>
<div class="o_colorpicker_section" data-name="grayscale" data-icon-class="fa fa-database">
<button data-color="white">White</button>
<button data-color="gray-lighter">Gray Lighter</button>
<button data-color="gray-light">Gray Light</button>
<button data-color="gray">Gray</button>
<button data-color="gray-dark">Gray Dark</button>
<button data-color="gray-darker">Gray Darker</button>
<button data-color="black">Black</button>
</div>
<div class="ui">
<button class="bg-primary">Primary Color <span></span></button>
<button class="bg-success">Success Color <span></span></button>
<button class="bg-info">Info Color <span></span></button>
<button class="bg-warning">Warning Color <span></span></button>
<button class="bg-danger">Danger Color <span></span></button>
<div class="o_colorpicker_section" data-name="ui" data-icon-class="fa fa-paint-brush">
<button data-color="primary">Primary</button>
<button data-color="success">Success</button>
<button data-color="info">Info</button>
<button data-color="warning">Warning</button>
<button data-color="danger">Danger</button>
</div>
</div>
</colorpicker>
</template>
</odoo>
@@ -10,13 +10,13 @@ require('web_editor.base'); // wait for implicit dependencies to load
var qweb = core.qweb;
if(!$('#oe_systray').length) {
return $.Deferred().reject("DOM doesn't contain '#oe_systray'");
if(!$('#oe_main_menu_navbar').length) {
return $.Deferred().reject("DOM doesn't contain #oe_main_menu_navbar");
}
var WebsitePlannerLauncher = Widget.extend({
template: "PlannerLauncher",
start: function() {
start: function () {
var self = this;
var res = this._super.apply(this, arguments);
this.$('.progress').show();
@@ -29,22 +29,22 @@ var WebsitePlannerLauncher = Widget.extend({
}
});
},
get_website_planner: function() {
get_website_planner: function () {
return (new Model('web.planner')).call('search_read', [[['planner_application', '=', 'planner_website']]]);
},
setup: function() {
setup: function () {
var self = this;
this.dialog = new planner.PlannerDialog(this, this.planner);
this.dialog.appendTo($('<div>'));
this.$(".progress").tooltip({html: true, title: this.planner.tooltip_planner, placement: 'bottom', container: 'body', delay: {'show': 700}});
this.dialog.on("planner_progress_changed", this, function(percent) {
this.dialog.on("planner_progress_changed", this, function (percent) {
self.update_parent_progress_bar(percent);
});
},
update_parent_progress_bar: function(percent) {
update_parent_progress_bar: function (percent) {
this.$(".progress-bar").css('width', percent+"%");
},
show_dialog: function() {
show_dialog: function () {
this.dialog.$el.appendTo(document.body);
this.dialog.$el.modal('show');
},
@@ -52,7 +52,7 @@ var WebsitePlannerLauncher = Widget.extend({
return ajax.loadXML('/web_planner/static/src/xml/web_planner.xml', qweb).then(function() {
var websitePlannerLauncher = new WebsitePlannerLauncher();
websitePlannerLauncher.prependTo($('#oe_systray'));
websitePlannerLauncher.prependTo($('#oe_main_menu_navbar .o_menu_systray'));
});
});
+8 -19
View File
@@ -105,10 +105,6 @@ var ViewEditor = Widget.extend({
self.aceEditor.resize();
self.$el.width(width);
}
function resizeEditorHeight(height) {
self.$el.css('top', height);
self.$('.ace_editor').css('bottom', height);
}
function storeEditorWidth() {
window.localStorage.setItem('ace_editor_width', self.$el.width());
}
@@ -136,13 +132,9 @@ var ViewEditor = Widget.extend({
self.$('.ace_gutter').mouseup(stopResizing).mousedown(startResizing).click(stopResizing);
$(document).mousemove(updateWidth);
$('button[data-action=edit]').click(function () {
self.close();
});
this.getParent().on('change:height', this, function () {
resizeEditorHeight(this.getParent().$el.outerHeight()+2);
self.close();
});
resizeEditor(readEditorWidth());
resizeEditorHeight(this.getParent().$el.outerHeight()+2);
},
loadTemplates: function () {
var self = this;
@@ -220,7 +212,7 @@ var ViewEditor = Widget.extend({
model: 'ir.ui.view',
method: 'read',
args: [[viewId], ['arch'], _.extend(base.get_context(), {'lang': null})],
}).then(function(result) {
}).then(function (result) {
var editingSession = self.buffers[viewId] = new ace.EditSession(result[0].arch);
editingSession.setMode("ace/mode/xml");
editingSession.setUndoManager(new ace.UndoManager());
@@ -359,12 +351,7 @@ var ViewEditor = Widget.extend({
this.$("#ace-view-list").val(session.id).change();
}
var $dialog = $(qweb.render('website.error_dialog', {
title: session.text.match(/\s+name=['"]([^'"]+)['"]/i)[1],
message:"<b>Malformed XML document</b>:<br/>" + message
}));
$dialog.appendTo("body");
$dialog.modal('show');
website.error(session.text.match(/\s+name=['"]([^'"]+)['"]/i)[1], "<b>Malformed XML document</b>:<br/>" + message);
},
open: function () {
this.$el.removeClass('oe_ace_closed').addClass('oe_ace_open');
@@ -378,9 +365,11 @@ var ViewEditor = Widget.extend({
website.TopBar.include({
start: function () {
this.ace = new Ace();
var def = this.ace.attachTo($('#html_editor'));
return $.when(this._super(), def);
}
return $.when(
this._super.apply(this, arguments),
this.ace.attachTo($('#html_editor'))
);
},
});
});
@@ -9,7 +9,7 @@ var _t = core._t;
var WidgetWebsiteButton = form_common.AbstractField.extend({
template: 'WidgetWebsiteButton',
render_value: function() {
render_value: function () {
this._super.apply(this, arguments);
var $value = this.$('.o_value');
@@ -28,7 +28,7 @@ var WidgetWebsiteButton = form_common.AbstractField.extend({
this.$el.addClass(this.node.attrs.class);
}
},
is_false: function() {
is_false: function () {
return false;
},
});
@@ -15,34 +15,18 @@ var qweb = core.qweb;
ajax.loadXML('/website/static/src/xml/website.contentMenu.xml', qweb);
var TopBarContent = Widget.extend({
start: function() {
start: function () {
var self = this;
self.$el.on('click', 'a[data-action]', function(ev) {
ev.preventDefault();
var $content_item = $(this);
self[$content_item.data('action')]();
// Add page modal + menu content event
this.$el.add($('#o_website_add_page_modal')).on('click', 'a[data-action]', function (e) {
e.preventDefault();
self[$(this).data('action')]();
});
// Build 'ADD PAGE' modal
var $cont = $('#website_addPage_modal .website_addPage_ul');
var $defIcon = $('<i class="fa fa-cube"></i>')
$("#website_addPage_list").nextAll().each(function(){
var $clone = $(this).clone().appendTo($cont).attr("data-dismiss","modal").addClass('animated')
var $a = $clone.find('a')
var text = $a.text()
if($clone.find('i').length < 1){ $defIcon.clone().prependTo($a)}
if($clone.find('p').length < 1){ $a.html($a.html().replace($a.text(),'')).append('<p>' + text + '</p>')}
$a.on('click', function(){
var $content_item = $(this);
self[$content_item.data('action')]();
})
})
return this._super();
},
edit_menu: function() {
edit_menu: function () {
var self = this;
var context = base.get_context();
var def = $.Deferred();
@@ -70,7 +54,7 @@ var TopBarContent = Widget.extend({
});
});
},
new_page: function() {
new_page: function () {
website.prompt({
id: "editor_new_page",
window_title: _t("New Page"),
@@ -79,18 +63,11 @@ var TopBarContent = Widget.extend({
var $group = this.$dialog.find("div.form-group");
$group.removeClass("mb0");
var $add = $(
'<div class="form-group mb0">'+
'<span class="col-sm-offset-3 col-sm-9 text-left">'+
'<label class="switch checked" for="switch_addTo_menu">' +
'<input type="checkbox" id="switch_addTo_menu" class="switch_input" checked="checked" />' +
'<span class="switch_track"></span>' +
'</label>' +
'</span>'+
'</div>');
$add.find('label').after(_t("Add page in menu"));
var $add = $('<div/>', {'class': 'form-group mb0'})
.append($('<span/>', {'class': 'col-sm-offset-3 col-sm-9 text-left'})
.append(qweb.render('web_editor.components.switch', {id: 'switch_addTo_menu', label: _t("Add page in menu")})));
$add.find('input').prop('checked', true);
$group.after($add);
console.log(website)
}
}).then(function (val, field, $dialog) {
if (val) {
@@ -100,7 +77,7 @@ var TopBarContent = Widget.extend({
}
});
},
rename_page: function() {
rename_page: function () {
var self = this;
var context = base.get_context();
self.mo_id = self.getMainObject().id;
@@ -134,7 +111,7 @@ var TopBarContent = Widget.extend({
});
});
},
delete_page: function() {
delete_page: function () {
var self = this;
var context = base.get_context();
self.mo_id = self.getMainObject().id;
@@ -144,17 +121,17 @@ var TopBarContent = Widget.extend({
method: 'page_search_dependencies',
args: [self.mo_id],
kwargs: {
context: context
context: context,
},
}).then(function (deps) {
website.prompt({
id: "editor_delete_page",
window_title: _t("Delete Page"),
dependencies: deps,
init: function() { $('.btn-continue').prop("disabled", true)},
init: function () { $('.btn-continue').prop("disabled", true)},
}, 'website.delete_page').then(function (val, field, $dialog) {
if ($dialog.find('input[type="checkbox"]').is(':checked')){
if ($dialog.find('input[type="checkbox"]').is(':checked')) {
ajax.jsonRpc('/web/dataset/call_kw', 'call', {
model: 'website',
method: 'delete_page',
+25 -88
View File
@@ -23,47 +23,16 @@ website.TopBar.include({
},
start: function () {
var self = this;
$("#wrapwrap").on('click', '.o_editable, [data-oe-model]', function (event) {
var $this = $(event.srcElement);
var tag = $this[0] && $this[0].tagName.toLowerCase();
if (!(tag === 'a' || tag === "button") && !$this.parents("a, button").length) {
self.$('[data-action="edit"]').parent().effect('bounce', {distance: 18, times: 5}, 250);
}
});
$("#wrapwrap").find("[data-oe-model] .oe_structure.oe_empty, [data-oe-model].oe_structure.oe_empty, [data-oe-type=html]:empty")
.filter(".oe_not_editable")
.filter(".oe_no_empty")
.addClass("oe_empty")
.attr("data-oe-placeholder", _t("Press The Top-Left Edit Button"));
.addClass("oe_empty");
if (location.search.indexOf("enable_editor") >= 0 && $('html').attr('lang') === "en_US") {
this.$el.addClass('editing_mode');
}
self.init_components()
self.resize()
$(window).on("resize", function(){
self.resize()
})
return this._super();
},
init_components: function(){
$(".switch").each(function(){
var $el = $(this)
$el.on('click', function(){
var $i = $el.find('.switch_input')
$el.toggleClass('checked')
if($i.prop("checked")){
$i.prop("checked", false);
} else {
$i.prop("checked", true);
}
return false;
})
});
return this._super.apply(this, arguments);
},
edit: function () {
this.$('button[data-action=edit]').prop('disabled', true);
@@ -71,31 +40,6 @@ website.TopBar.include({
editor.editor_bar = new editor.Class(this);
editor.editor_bar.prependTo(document.body);
},
resize: function() {
var wW = $(window).width(),
$sys = $('#oe_systray'),
$nav = $('#website_main_menu_navbar');
// Adapt dropdown-menu orientation to fit screen size
$sys.find('> li.wb_dropdown, >li.dropdown').each(function(){
var $el = $(this),
offset = $el.offset(),
width = $el.width();
var centerX = offset.left + width / 2;
if(centerX > wW/2){
$el.addClass('right')
} else {
$el.removeClass('right')
}
})
// Resize oe_systray
var totalWidth = null;
$nav.find('>*').not($sys).each(function(index) {
totalWidth += parseInt($(this).outerWidth() , 10);
});
$sys.width((wW - totalWidth)-50).addClass('ready')
}
});
/* ----- Customize Template ---- */
@@ -105,7 +49,7 @@ website.TopBarCustomize = Widget.extend({
'mousedown a.dropdown-toggle': 'load_menu',
'click ul a[data-view-id]': 'do_customize',
},
start: function() {
start: function () {
var self = this;
this.$menu = self.$el.find('ul');
this.view_name = $(document.documentElement).data('view-xmlid');
@@ -119,43 +63,36 @@ website.TopBarCustomize = Widget.extend({
if(this.loaded) {
return;
}
ajax.jsonRpc('/website/customize_template_get', 'call', { 'key': this.view_name }).then(
function(result) {
_.each(result, function (item) {
if (item.key === "website.debugger" && !window.location.search.match(/[&?]debug(&|$)/)) return;
if (item.header) {
self.$menu.append('<li class="dropdown-header">' + item.name + '</li>');
} else {
self.$menu.append(_.str.sprintf(
'<li role="presentation">'+
'<a href="#" data-view-id="%s" role="menuitem">' +
'<span class="toggle_container">' +
'<label class="switch %s" for="switch-%s">' +
'<input type="checkbox" id="switch-%s" class="switch_input" checked="%s">' +
'<span class="switch_track"></span>' +
'</label>' +
'</span> %s'+
'</a>' +
'</li>',
item.id, item.active ? 'checked' : '', item.id, item.id, item.active ? 'true' : 'false', item.name));
}
});
self.loaded = true;
}
);
ajax.jsonRpc('/website/customize_template_get', 'call', {
key: this.view_name,
}).then(function (result) {
_.each(result, function (item) {
if (item.key === "website.debugger" && !window.location.search.match(/[&?]debug(&|$)/)) return;
if (item.header) {
self.$menu.append('<li class="dropdown-header">' + item.name + '</li>');
} else {
var $li = $('<li/>', {role: 'presentation'})
.append($('<a/>', {href: '#', 'data-view-id': item.id, role: 'menuitem'})
.append(qweb.render('web_editor.components.switch', {id: 'switch-' + item.id, label: item.name})));
$li.find('input').prop('checked', !!item.active);
self.$menu.append($li);
}
});
self.loaded = true;
});
},
do_customize: function (event) {
var view_id = $(event.currentTarget).data('view-id');
$('#website_loading').addClass('active')
do_customize: function (e) {
e.preventDefault();
var view_id = $(e.currentTarget).data('view-id');
return ajax.jsonRpc('/web/dataset/call_kw', 'call', {
model: 'ir.ui.view',
method: 'toggle',
args: [],
kwargs: {
ids: [parseInt(view_id, 10)],
context: base.get_context()
context: base.get_context(),
}
}).then( function() {
}).then(function () {
window.location.reload();
});
},
+216 -216
View File
@@ -1,189 +1,178 @@
odoo.define('website.website', function (require) {
"use strict";
"use strict";
var ajax = require('web.ajax');
var core = require('web.core');
var Widget = require('web.Widget');
var session = require('web.session');
var base = require('web_editor.base');
var Tour = require('web.Tour');
var ajax = require('web.ajax');
var core = require('web.core');
var Widget = require('web.Widget');
var session = require('web.session');
var base = require('web_editor.base');
var Tour = require('web.Tour');
var qweb = core.qweb;
var _t = core._t;
base.url_translations = '/website/translations';
var qweb = core.qweb;
var _t = core._t;
base.url_translations = '/website/translations';
/* --- Set the browser into the dom for css selectors --- */
var browser;
if ($.browser.webkit) browser = "webkit";
else if ($.browser.safari) browser = "safari";
else if ($.browser.opera) browser = "opera";
else if ($.browser.msie || ($.browser.mozilla && +$.browser.version.replace(/^([0-9]+\.[0-9]+).*/, '\$1') < 20)) browser = "msie";
else if ($.browser.mozilla) browser = "mozilla";
browser += ","+$.browser.version;
if (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase())) browser += ",mobile";
document.documentElement.setAttribute('data-browser', browser);
/* --- Set the browser into the dom for css selectors --- */
var browser;
if ($.browser.webkit) browser = "webkit";
else if ($.browser.safari) browser = "safari";
else if ($.browser.opera) browser = "opera";
else if ($.browser.msie || ($.browser.mozilla && +$.browser.version.replace(/^([0-9]+\.[0-9]+).*/, '\$1') < 20)) browser = "msie";
else if ($.browser.mozilla) browser = "mozilla";
browser += ","+$.browser.version;
if (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase())) browser += ",mobile";
document.documentElement.setAttribute('data-browser', browser);
/* ----------------------------------------------------
Helpers
---------------------------------------------------- */
var get_context = base.get_context;
base.get_context = base.get_context = function (dict) {
var html = document.documentElement;
return _.extend({
'website_id': html.getAttribute('data-website-id')|0
}, get_context(dict), dict);
};
/* ----------------------------------------------------
Widgets
---------------------------------------------------- */
var prompt = function (options, _qweb) {
/**
* A bootstrapped version of prompt() albeit asynchronous
* This was built to quickly prompt the user with a single field.
* For anything more complex, please use editor.Dialog class
*
* Usage Ex:
*
* website.prompt("What... is your quest ?").then(function (answer) {
* arthur.reply(answer || "To seek the Holy Grail.");
* });
*
* website.prompt({
* select: "Please choose your destiny",
* init: function() {
* return [ [0, "Sub-Zero"], [1, "Robo-Ky"] ];
* }
* }).then(function (answer) {
* mame_station.loadCharacter(answer);
* });
*
* @param {Object|String} options A set of options used to configure the prompt or the text field name if string
* @param {String} [options.window_title=''] title of the prompt modal
* @param {String} [options.input] tell the modal to use an input text field, the given value will be the field title
* @param {String} [options.textarea] tell the modal to use a textarea field, the given value will be the field title
* @param {String} [options.select] tell the modal to use a select box, the given value will be the field title
* @param {Object} [options.default=''] default value of the field
* @param {Function} [options.init] optional function that takes the `field` (enhanced with a fillWith() method) and the `dialog` as parameters [can return a deferred]
*/
if (typeof options === 'string') {
options = {
text: options
};
}
if (_.isUndefined(_qweb)) {
_qweb = 'website.prompt';
}
options = _.extend({
window_title: '',
field_name: '',
'default': '', // dict notation for IE<9
init: function() {},
}, options || {});
var type = _.intersection(Object.keys(options), ['input', 'textarea', 'select']);
type = type.length ? type[0] : 'input';
options.field_type = type;
options.field_name = options.field_name || options[type];
var def = $.Deferred();
var dialog = $(qweb.render(_qweb, options)).appendTo("body");
options.$dialog = dialog;
var field = dialog.find(options.field_type).first();
field.val(options['default']); // dict notation for IE<9
field.fillWith = function (data) {
if (field.is('select')) {
var select = field[0];
data.forEach(function (item) {
select.options[select.options.length] = new Option(item[1], item[0]);
});
} else {
field.val(data);
}
/* ----------------------------------------------------
Helpers
---------------------------------------------------- */
var get_context = base.get_context;
base.get_context = base.get_context = function (dict) {
var html = document.documentElement;
return _.extend({
'website_id': html.getAttribute('data-website-id')|0
}, get_context(dict), dict);
};
var init = options.init(field, dialog);
$.when(init).then(function (fill) {
if (fill) {
field.fillWith(fill);
/* ----------------------------------------------------
Widgets
---------------------------------------------------- */
var prompt = function (options, _qweb) {
/**
* A bootstrapped version of prompt() albeit asynchronous
* This was built to quickly prompt the user with a single field.
* For anything more complex, please use editor.Dialog class
*
* Usage Ex:
*
* website.prompt("What... is your quest ?").then(function (answer) {
* arthur.reply(answer || "To seek the Holy Grail.");
* });
*
* website.prompt({
* select: "Please choose your destiny",
* init: function () {
* return [ [0, "Sub-Zero"], [1, "Robo-Ky"] ];
* }
* }).then(function (answer) {
* mame_station.loadCharacter(answer);
* });
*
* @param {Object|String} options A set of options used to configure the prompt or the text field name if string
* @param {String} [options.window_title=''] title of the prompt modal
* @param {String} [options.input] tell the modal to use an input text field, the given value will be the field title
* @param {String} [options.textarea] tell the modal to use a textarea field, the given value will be the field title
* @param {String} [options.select] tell the modal to use a select box, the given value will be the field title
* @param {Object} [options.default=''] default value of the field
* @param {Function} [options.init] optional function that takes the `field` (enhanced with a fillWith() method) and the `dialog` as parameters [can return a deferred]
*/
if (typeof options === 'string') {
options = {
text: options
};
}
dialog.modal('show');
field.focus();
dialog.on('click', '.btn-primary', function () {
if (_.isUndefined(_qweb)) {
_qweb = 'website.prompt';
}
options = _.extend({
window_title: '',
field_name: '',
'default': '', // dict notation for IE<9
init: function () {},
}, options || {});
var type = _.intersection(Object.keys(options), ['input', 'textarea', 'select']);
type = type.length ? type[0] : 'input';
options.field_type = type;
options.field_name = options.field_name || options[type];
var def = $.Deferred();
var dialog = $(qweb.render(_qweb, options)).appendTo("body");
options.$dialog = dialog;
var field = dialog.find(options.field_type).first();
field.val(options['default']); // dict notation for IE<9
field.fillWith = function (data) {
if (field.is('select')) {
var select = field[0];
data.forEach(function (item) {
select.options[select.options.length] = new Option(item[1], item[0]);
});
} else {
field.val(data);
}
};
var init = options.init(field, dialog);
$.when(init).then(function (fill) {
if (fill) {
field.fillWith(fill);
}
dialog.modal('show');
field.focus();
dialog.on('click', '.btn-primary', function () {
var backdrop = $('.modal-backdrop');
def.resolve(field.val(), field, dialog);
dialog.modal('hide').remove();
backdrop.remove();
});
});
dialog.on('hidden.bs.modal', function () {
var backdrop = $('.modal-backdrop');
def.resolve(field.val(), field, dialog);
dialog.modal('hide').remove();
def.reject();
dialog.remove();
backdrop.remove();
});
});
dialog.on('hidden.bs.modal', function () {
var backdrop = $('.modal-backdrop');
def.reject();
dialog.remove();
backdrop.remove();
});
if (field.is('input[type="text"], select')) {
field.keypress(function (e) {
if (e.which == 13) {
e.preventDefault();
dialog.find('.btn-primary').trigger('click');
}
if (field.is('input[type="text"], select')) {
field.keypress(function (e) {
if (e.which == 13) {
e.preventDefault();
dialog.find('.btn-primary').trigger('click');
}
});
}
return def;
};
var error = function (title, message, url) {
return new Dialog(null, {
title: data.data ? data.data.arguments[0] : "",
$content: $(qweb.render('website.error_dialog', {
message: data.data ? data.data.arguments[1] : data.statusText,
backend_url: url,
})),
}).open();
};
function _add_input(form, name, value) {
var param = document.createElement('input');
param.setAttribute('type', 'hidden');
param.setAttribute('name', name);
param.setAttribute('value', value);
form.appendChild(param);
}
var form = function (url, method, params) {
var form = document.createElement('form');
form.setAttribute('action', url);
form.setAttribute('method', method);
if (core.csrf_token) {
_add_input(form, 'csrf_token', core.csrf_token);
}
_.each(params, function (v, k) {
_add_input(form, k, v);
});
}
return def;
};
document.body.appendChild(form);
form.submit();
};
var error = function(data, url) {
var $error = $(qweb.render('website.error_dialog', {
'title': data.data ? data.data.arguments[0] : "",
'message': data.data ? data.data.arguments[1] : data.statusText,
'backend_url': url
}));
$error.appendTo("body");
$error.modal('show');
};
function _add_input(form, name, value) {
var param = document.createElement('input');
param.setAttribute('type', 'hidden');
param.setAttribute('name', name);
param.setAttribute('value', value);
form.appendChild(param);
}
var form = function (url, method, params) {
var form = document.createElement('form');
form.setAttribute('action', url);
form.setAttribute('method', method);
if (core.csrf_token) {
_add_input(form, 'csrf_token', core.csrf_token);
}
_.each(params, function (v, k) {
_add_input(form, k, v);
ajax.loadXML('/website/static/src/xml/website.xml', qweb);
ajax.loadXML('/web/static/src/xml/base_common.xml', qweb);
base.ready().then(function () {
data.topBar = new TopBar();
return data.topBar.attachTo($("#oe_main_menu_navbar"));
});
document.body.appendChild(form);
form.submit();
};
ajax.loadXML('/website/static/src/xml/website.xml', qweb);
ajax.loadXML('/web/static/src/xml/base_common.xml', qweb);
/**
* Cancel the auto run of Tour (test) and launch the tour after tob bar all bind events
*/
base.ready().then(function () {
data.topBar = new TopBar();
data.topBar.attachTo($("#website_main_menu_navbar"));
});
/**
* Returns a deferred resolved when the templates are loaded
* and the Widgets can be instanciated.
*/
/* ----- PUBLISHING STUFF ---- */
$(document).on('click', '.js_publish_management .js_publish_btn', function () {
@@ -194,22 +183,22 @@ base.ready().then(function () {
$data.toggleClass("css_unpublished css_published");
$data.parents("[data-publish]").attr("data-publish", +result ? 'on' : 'off');
}).fail(function (err, data) {
error(data, '/web#return_label=Website&model='+$data.data('object')+'&id='+$data.data('id'));
error(data.data ? data.data.arguments[0] : "", data.data ? data.data.arguments[1] : data.statusText, '/web#return_label=Website&model='+$data.data('object')+'&id='+$data.data('id'));
});
});
if (!$('.js_change_lang').length) {
// in case template is not up to date...
var links = $('ul.js_language_selector li a:not([data-oe-id])');
var m = $(_.min(links, function(l) { return $(l).attr('href').length; })).attr('href');
links.each(function() {
var m = $(_.min(links, function (l) { return $(l).attr('href').length; })).attr('href');
links.each(function () {
var t = $(this).attr('href');
var l = (t === m) ? "default" : t.split('/')[1];
$(this).data('lang', l).addClass('js_change_lang');
});
}
$(document).on('click', '.js_change_lang', function(e) {
$(document).on('click', '.js_change_lang', function (e) {
e.preventDefault();
var self = $(this);
@@ -227,54 +216,65 @@ base.ready().then(function () {
init_kanban(this);
});
$('.js_website_submit_form').on('submit', function() {
$('.js_website_submit_form').on('submit', function () {
var $buttons = $(this).find('button[type="submit"], a.a-submit');
_.each($buttons, function(btn) {
_.each($buttons, function (btn) {
$(btn).attr('data-loading-text', '<i class="fa fa-spinner fa-spin"></i> ' + $(btn).text()).button('loading');
});
});
setTimeout(function () {
_.defer(function () {
if (window.location.hash.indexOf("scrollTop=") > -1) {
window.document.body.scrollTop = +location.hash.match(/scrollTop=([0-9]+)/)[1];
}
},0);
// display image thumbnail
$(".o_image[data-mimetype^='image']").each(function () {
var $img = $(this);
if (/gif|jpe|jpg|png/.test($img.data('mimetype')) && $img.data('src')) {
$img.css('background-image', "url('" + $img.data('src') + "')");
}
});
/**
* Object who contains all method and bind for the top bar, the template is create server side.
*/
var TopBar = Widget.extend({
start: function () {
var $collapse = this.$('#oe_applications ul.dropdown-menu').clone()
.attr("id", "oe_applications_collapse")
.attr("class", "nav navbar-nav navbar-left navbar-collapse collapse");
this.$('#oe_applications').before($collapse);
$collapse.wrap('<div class="visible-xs"/>');
this.$('[data-target="#oe_applications"]').attr("data-target", "#oe_applications_collapse");
return this._super();
}
});
var data = {
prompt: prompt,
form: form,
TopBar: TopBar,
ready: function () {
console.warn("website.ready is deprecated: Please use require('web_editor.base').ready()");
return base.ready();
}
};
return data;
});
// display image thumbnail
$(".o_image[data-mimetype^='image']").each(function () {
var $img = $(this);
if (/gif|jpe|jpg|png/.test($img.data('mimetype')) && $img.data('src')) {
$img.css('background-image', "url('" + $img.data('src') + "')");
}
});
/**
* Object who contains all method and bind for the top bar, the template is create server side.
*/
var TopBar = Widget.extend({
start: function () {
var $collapse = this.$('#oe_applications ul.dropdown-menu').clone()
.attr("id", "oe_applications_collapse")
.attr("class", "nav navbar-nav navbar-left navbar-collapse collapse");
this.$('#oe_applications').before($collapse);
$collapse.wrap('<div class="visible-xs"/>');
this.$('[data-target="#oe_applications"]').attr("data-target", "#oe_applications_collapse");
var self = this;
this.$el.on('mouseover', '> ul > li.dropdown:not(.open)', function (e) {
var $opened = self.$('> ul > li.dropdown.open');
if($opened.length) {
$opened.removeClass('open');
$(e.currentTarget).find('.dropdown-toggle').mousedown().focus().mouseup().click();
}
});
this.$el.on('click', '.o_mobile_menu_toggle', function (ev) {
self.$el.parent().toggleClass('o_mobile_menu_opened');
});
return this._super.apply(this, arguments);
}
});
var data = {
prompt: prompt,
error: error,
form: form,
TopBar: TopBar,
ready: function () {
console.warn("website.ready is deprecated: Please use require('web_editor.base').ready()");
return base.ready();
},
};
return data;
});
+28 -18
View File
@@ -1,39 +1,49 @@
odoo.define('website.mobile', function (require) {
'use strict';
var core = require('web.core');
var ajax = require('web.ajax');
var core = require('web.core');
var Dialog = require('web.Dialog');
var Widget = require('web.Widget');
var base = require('web_editor.base');
var website = require('website.website');
var qweb = core.qweb;
var _t = core._t;
var MobilePreview = Widget.extend({
var MobilePreviewDialog = Dialog.extend({
template: 'website.mobile_preview',
events: {
'hidden.bs.modal': 'destroy'
init: function () {
this._super.apply(this, arguments);
this.mobile_src = $.param.querystring(window.location.href, 'mobilepreview');
},
start: function() {
if (!window.location.origin) { // fix for ie9
window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
}
document.getElementById("mobile-viewport").src = window.location.origin + window.location.pathname + window.location.search + "#mobile-preview";
this.$el.modal();
},
destroy: function() {
$('.modal-backdrop').remove();
this._super();
start: function () {
var self = this;
this.$modal.addClass('oe_mobile_preview');
this.$modal.on('click', '.modal-header', function () {
self.$el.toggleClass('o_invert_orientation');
});
this.$iframe = this.$('iframe');
this.$iframe.on('load', function (e) {
self.$iframe.contents().find('body').removeAttr('user');
self.$iframe.contents().find('#oe_main_menu_navbar, #o_website_add_page_modal').remove();
});
return this._super.apply(this, arguments);
},
});
website.TopBar.include({
start: function () {
this.$el.on('click', 'a[data-action=show-mobile-preview]', function() {
new MobilePreview().appendTo($(document.body));
var self = this;
this.$el.on('click', 'a[data-action=show-mobile-preview]', function () {
new MobilePreviewDialog(self, {
title: _t('Mobile preview') + " <span class='fa fa-repeat'/>",
}).open();
});
return this._super();
}
},
});
});
+67 -76
View File
@@ -4,6 +4,7 @@ odoo.define('website.seo', function (require) {
var core = require('web.core');
var ajax = require('web.ajax');
var Class = require('web.Class');
var Dialog = require('web.Dialog');
var mixins = require('web.mixins');
var Model = require('web.Model');
var Widget = require('web.Widget');
@@ -84,11 +85,11 @@ var SuggestionList = Widget.extend({
ajax.jsonRpc('/website/seo_suggest', 'call', {
'keywords': self.root,
'lang': language,
}).then(function(keyword_list){
}).then(function (keyword_list) {
self.addSuggestions(JSON.parse(keyword_list));
});
},
addSuggestions: function(keywords) {
addSuggestions: function (keywords) {
var self = this;
self.$el.empty();
// TODO Improve algorithm + Ajust based on custom user keywords
@@ -222,7 +223,6 @@ var Image = Widget.extend({
},
});
var ImageList = Widget.extend({
init: function (parent, options) {
this.htmlPage = options.page;
@@ -339,15 +339,13 @@ var Tip = Widget.extend({
},
});
var Configurator = Widget.extend({
var Configurator = Dialog.extend({
template: 'website.seo_configuration',
events: {
'keyup input[name=seo_page_keywords]': 'confirmKeyword',
'keyup input[name=seo_page_title]': 'titleChanged',
'keyup textarea[name=seo_page_description]': 'descriptionChanged',
'click button[data-action=add]': 'addKeyword',
'click button[data-action=update]': 'update',
'hidden.bs.modal': 'destroy',
},
canEditTitle: false,
canEditDescription: false,
@@ -355,44 +353,51 @@ var Configurator = Widget.extend({
canEditLanguage: false,
maxTitleSize: 65,
maxDescriptionSize: 150,
init: function (parent, options) {
options = options || {};
_.defaults(options, {
title: _t('Promote This Page'),
subtitle: _t('Get this page efficiently referenced in Google to attract more visitors.'),
buttons: [
{text: _t('Save'), classes: 'btn-primary', click: this.update},
{text: _t('Discard'), close: true},
],
});
this._super(parent, options);
},
start: function () {
var self = this;
var $modal = self.$el;
var htmlPage = this.htmlPage = new HtmlPage();
$modal.find('.js_seo_page_url').text(htmlPage.url());
$modal.find('input[name=seo_page_title]').val(htmlPage.title());
$modal.find('textarea[name=seo_page_description]').val(htmlPage.description());
// self.suggestImprovements();
// self.imageList = new ImageList(self, { page: htmlPage });
// if (htmlPage.images().length === 0) {
// $modal.find('.js_image_section').remove();
// } else {
// self.imageList.appendTo($modal.find('.js_seo_image_list'));
// }
self.keywordList = new KeywordList(self, { page: htmlPage });
self.keywordList.on('list-full', self, function () {
$modal.find('input[name=seo_page_keywords]')
.attr('readonly', "readonly")
.attr('placeholder', "Remove a keyword first");
$modal.find('button[data-action=add]')
.prop('disabled', true).addClass('disabled');
this.$modal.addClass('oe_seo_configuration js_seo_configuration');
this.htmlPage = new HtmlPage();
this.$('.js_seo_page_url').text(this.htmlPage.url());
this.$('input[name=seo_page_title]').val(this.htmlPage.title());
this.$('textarea[name=seo_page_description]').val(this.htmlPage.description());
this.keywordList = new KeywordList(self, { page: this.htmlPage });
this.keywordList.on('list-full', self, function () {
self.$('input[name=seo_page_keywords]').attr({
readonly: "readonly",
placeholder: "Remove a keyword first"
});
self.$('button[data-action=add]').prop('disabled', true).addClass('disabled');
});
self.keywordList.on('list-not-full', self, function () {
$modal.find('input[name=seo_page_keywords]')
.removeAttr('readonly').attr('placeholder', "");
$modal.find('button[data-action=add]')
.prop('disabled', false).removeClass('disabled');
this.keywordList.on('list-not-full', self, function () {
self.$('input[name=seo_page_keywords]').removeAttr('readonly').attr('placeholder', "");
self.$('button[data-action=add]').prop('disabled', false).removeClass('disabled');
});
self.keywordList.on('selected', self, function (word, language) {
this.keywordList.on('selected', self, function (word, language) {
self.keywordList.add(word, language);
});
self.keywordList.appendTo($modal.find('.js_seo_keywords_list'));
self.disableUnsavableFields();
self.renderPreview();
$modal.modal();
self.getLanguages();
this.keywordList.appendTo(this.$('.js_seo_keywords_list'));
this.disableUnsavableFields();
this.renderPreview();
this.getLanguages();
},
getLanguages: function(){
getLanguages: function () {
var self = this;
ajax.jsonRpc('/web/dataset/call_kw', 'call', {
model: 'website',
@@ -402,7 +407,7 @@ var Configurator = Widget.extend({
ids: [base.get_context().website_id],
context: base.get_context()
}
}).then( function(data) {
}).then( function (data) {
self.$('#language-box').html(core.qweb.render('Configurator.language_promote', {
'language': data,
'def_lang': base.get_context().lang
@@ -411,47 +416,34 @@ var Configurator = Widget.extend({
},
disableUnsavableFields: function () {
var self = this;
var $modal = self.$el;
self.loadMetaData().then(function (data) {
this.loadMetaData().then(function (data) {
self.canEditTitle = data && ('website_meta_title' in data);
self.canEditDescription = data && ('website_meta_description' in data);
self.canEditKeywords = data && ('website_meta_keywords' in data);
if (!self.canEditTitle) {
$modal.find('input[name=seo_page_title]').attr('disabled', true);
self.$('input[name=seo_page_title]').attr('disabled', true);
}
if (!self.canEditDescription) {
$modal.find('textarea[name=seo_page_description]').attr('disabled', true);
self.$('textarea[name=seo_page_description]').attr('disabled', true);
}
if (!self.canEditTitle && !self.canEditDescription && !self.canEditKeywords) {
$modal.find('button[data-action=update]').attr('disabled', true);
self.$footer.find('button[data-action=update]').attr('disabled', true);
}
});
},
suggestImprovements: function () {
var tips = [];
var self = this;
var tips = [];
_.each(tips, function (tip) {
displayTip(tip.message, tip.type);
});
function displayTip(message, type) {
new Tip(self, {
message: message,
type: type,
}).appendTo(self.$('.js_seo_tips'));
}
var htmlPage = this.htmlPage;
// Add message suggestions at the top of the dialog
// if necessary....
// if (htmlPage.headers('h1').length === 0) {
// tips.push({
// type: 'warning',
// message: "This page seems to be missing a title.",
// });
// }
if (tips.length > 0) {
_.each(tips, function (tip) {
displayTip(tip.message, tip.type);
});
}
},
confirmKeyword: function (e) {
if (e.keyCode == 13) {
@@ -469,17 +461,17 @@ var Configurator = Widget.extend({
update: function () {
var self = this;
var data = {};
if (self.canEditTitle) {
data.website_meta_title = self.htmlPage.title();
if (this.canEditTitle) {
data.website_meta_title = this.htmlPage.title();
}
if (self.canEditDescription) {
data.website_meta_description = self.htmlPage.description();
if (this.canEditDescription) {
data.website_meta_description = this.htmlPage.description();
}
if (self.canEditKeywords) {
data.website_meta_keywords = self.keywordList.keywords().join(", ");
if (this.canEditKeywords) {
data.website_meta_keywords = this.keywordList.keywords().join(", ");
}
self.saveMetaData(data).then(function () {
self.$el.modal('hide');
this.saveMetaData(data).then(function () {
self.close();
});
},
getMainObject: function () {
@@ -495,7 +487,6 @@ var Configurator = Widget.extend({
}
},
loadMetaData: function () {
var self = this;
var obj = this.getMainObject();
var def = $.Deferred();
if (!obj) {
@@ -527,19 +518,19 @@ var Configurator = Widget.extend({
},
titleChanged: function () {
var self = this;
setTimeout(function () {
_.defer(function () {
var title = self.$('input[name=seo_page_title]').val();
self.htmlPage.changeTitle(title);
self.renderPreview();
}, 0);
});
},
descriptionChanged: function () {
var self = this;
setTimeout(function () {
_.defer(function () {
var description = self.$('textarea[name=seo_page_description]').val();
self.htmlPage.changeDescription(description);
self.renderPreview();
}, 0);
});
},
renderPreview: function () {
var preview = new Preview(this, {
@@ -553,14 +544,14 @@ var Configurator = Widget.extend({
},
destroy: function () {
this.htmlPage.changeKeywords(this.keywordList.keywords());
this._super();
this._super.apply(this, arguments);
},
});
website.TopBar.include({
start: function () {
this.$el.on('click', 'a[data-action=promote-current-page]', function() {
new Configurator(this).appendTo($(document.body));
this.$el.on('click', 'a[data-action=promote-current-page]', function () {
new Configurator(this).open();
});
return this._super();
}
@@ -59,7 +59,7 @@ var SocialShare = Widget.extend({
}, 200);
});
},
renderSocial: function(social) {
renderSocial: function (social) {
var url = document.URL.split(/[?#]/)[0]; // get current url without query string
var title = document.title.split(" | ")[0]; // get the page title without the company name
var hashtags = ' #'+ document.title.split(" | ")[1].replace(' ','') + ' ' + this.hashtags; // company name without spaces (for hashtag)
@@ -76,8 +76,8 @@ var SocialShare = Widget.extend({
});
// Initialize all social_share links when ready
base.ready().done(function() {
$('.oe_social_share').mouseenter(function() {
base.ready().done(function () {
$('.oe_social_share').mouseenter(function () {
new SocialShare($(this));
});
});
@@ -8,8 +8,6 @@ var animation = require('web_editor.snippets.animation');
var qweb = core.qweb;
/*-------------------------------------------------------------------------*/
function load_called_template () {
var ids_or_xml_ids = _.uniq($("[data-oe-call]").map(function () {return $(this).data('oe-call');}).get());
if (ids_or_xml_ids.length) {
@@ -26,50 +24,6 @@ function load_called_template () {
}
}
// Ripple animation
animation.registry.ripple = animation.Class.extend({
selector: ".wb_dropdown-toggle, #oe_systray .dropdown-toggle",
start: function(){
var timeout,
btn = this.$target;
btn
.css({ position: 'relative', overflow: 'hidden'})
.bind('mousedown', function(e) {
var ripple;
if (btn.find('.ripple').length === 0) {
ripple = $('<span class="ripple"/>');
btn.prepend(ripple);
} else {
ripple = btn.find('.ripple');
}
ripple.removeClass('animate');
if (!ripple.height() && !ripple.width()) {
var diameter = Math.max(btn.outerWidth(), btn.outerHeight());
ripple.css({ height: diameter, width: diameter });
}
var x = e.pageX - btn.offset().left - ripple.width() / 2;
var y = e.pageY - btn.offset().top - ripple.height() / 2;
ripple
.css({ top: y + 'px',left: x + 'px'})
.addClass('animate');
setTimeout(function() {
//ripple.removeClass('animate');
}, 700);
});
},
}),
/*-------------------------------------------------------------------------*/
base.ready().then(function () {
load_called_template();
if ($(".o_gallery:not(.oe_slideshow)").size()) {
@@ -78,8 +32,6 @@ base.ready().then(function () {
}
});
/*-------------------------------------------------------------------------*/
animation.registry.slider = animation.Class.extend({
selector: ".carousel",
start: function () {
@@ -199,11 +151,11 @@ inside a gallery
-------------------------------------------------------------------------*/
animation.registry.gallery = animation.Class.extend({
selector: ".o_gallery:not(.o_slideshow)",
start: function() {
start: function () {
var self = this;
this.$el.on("click", "img", this.click_handler);
},
click_handler : function(event) {
click_handler : function (event) {
var self = this;
var $cur = $(event.currentTarget);
var edition_mode = ($cur.closest("[contenteditable='true']").size() !== 0);
@@ -225,7 +177,7 @@ animation.registry.gallery = animation.Class.extend({
height : Math.round( window.innerHeight * size)
};
$images.each(function() {
$images.each(function () {
urls.push($(this).attr("src"));
});
var $img = ($cur.is("img") === true) ? $cur : $cur.closest("img");
@@ -244,7 +196,7 @@ animation.registry.gallery = animation.Class.extend({
keyboard : true,
backdrop : true
});
$modal.on('hidden.bs.modal', function() {
$modal.on('hidden.bs.modal', function () {
$(this).hide();
$(this).siblings().filter(".modal-backdrop").remove(); // bootstrap leaves a modal-backdrop
$(this).remove();
@@ -257,9 +209,10 @@ animation.registry.gallery = animation.Class.extend({
}
} // click_handler
});
animation.registry.gallery_slider = animation.Class.extend({
selector: ".o_slideshow",
start: function() {
start: function () {
var $carousel = this.$target.is(".carousel") ? this.$target : this.$target.find(".carousel");
var self = this;
var $indicator = $carousel.find('.carousel-indicators');
@@ -271,7 +224,7 @@ animation.registry.gallery_slider = animation.Class.extend({
var nb = Math.ceil($lis.length / 10);
// fix bootstrap use index insead of data-slide-to
$carousel.on('slide.bs.carousel', function() {
$carousel.on('slide.bs.carousel', function () {
setTimeout(function () {
var $item = $carousel.find('.carousel-inner .prev, .carousel-inner .next');
var index = $item.index();
@@ -298,7 +251,7 @@ animation.registry.gallery_slider = animation.Class.extend({
});
hide();
$carousel.on('slid.bs.carousel', function() {
$carousel.on('slid.bs.carousel', function () {
var index = ($lis.filter('.active').index() || 1) -1;
page = Math.floor(index / 10);
hide();
@@ -6,16 +6,14 @@ var animation = require('web_editor.snippets.animation');
var options = require('web_editor.snippets.options');
var snippet_editor = require('web_editor.snippet.editor');
snippet_editor.Class.include({
_get_snippet_url: function () {
return '/website/snippets';
}
});
var preventParentEmpty = {
hide_remove_button: function() {
hide_remove_button: function () {
this.$overlay.find('.oe_snippet_remove, .oe_snippet_move').toggleClass("hidden", !this.$target.siblings().length);
},
on_focus : function () {
@@ -32,9 +30,8 @@ var preventParentEmpty = {
},
};
options.registry.slider = options.Class.extend({
drop_and_build_snippet: function() {
drop_and_build_snippet: function () {
this.id = "myCarousel" + new Date().getTime();
this.$target.attr("id", this.id);
this.$target.find("[data-slide]").attr("data-cke-saved-href", "#" + this.id);
@@ -96,14 +93,14 @@ options.registry.slider = options.Class.extend({
});
}
else {
var s_class = selection.attr('class').split(' ').filter(function(o) { return _.str.startsWith(o, "s_") })[0]
var s_class = selection.attr('class').split(' ').filter(function (o) { return _.str.startsWith(o, "s_") })[0]
selection = $snippets.find("." + s_class);
}
var $clone = $(selection).find('.item:first').clone();
// insert
$clone.removeClass('active').insertAfter($active);
setTimeout(function() {
setTimeout(function () {
self.$target.carousel().carousel(++index);
self.rebind_event();
},0);
@@ -140,7 +137,7 @@ options.registry.slider = options.Class.extend({
this.$target.find('.carousel-control, .carousel-indicators').addClass("hidden");
}
},
interval : function(type, value) {
interval : function (type, value) {
this.$target.attr("data-interval", value);
},
set_active: function () {
@@ -168,7 +165,7 @@ options.registry.carousel = options.registry.slider.extend({
this._super();
// set background and prepare to clean for save
var add_class = function (c){
var add_class = function (c) {
if (c) self._class = (self._class || "").replace(new RegExp("[ ]+" + c.replace(" ", "|[ ]+")), '') + ' ' + c;
return self._class || "";
};
@@ -223,7 +220,7 @@ options.registry.marginAndResize = options.Class.extend({
if (resize_values.w) this.$overlay.find(".oe_handle.w").removeClass("readonly");
if (resize_values.size) this.$overlay.find(".oe_handle.size").removeClass("readonly");
this.$overlay.find(".oe_handle:not(.size), .oe_handle.size .size").on('mousedown', function (event){
this.$overlay.find(".oe_handle:not(.size), .oe_handle.size .size").on('mousedown', function (event) {
event.preventDefault();
var $handle = $(this);
@@ -284,7 +281,7 @@ options.registry.marginAndResize = options.Class.extend({
var $body = $(document.body);
$body.addClass(cursor);
var body_mousemove = function (event){
var body_mousemove = function (event) {
event.preventDefault();
if (compass === 'size') {
var dy = event.pageY-offset;
@@ -320,7 +317,7 @@ options.registry.marginAndResize = options.Class.extend({
}
};
var body_mouseup = function(){
var body_mouseup = function () {
$body.unbind('mousemove', body_mousemove);
$body.unbind('mouseup', body_mouseup);
$body.removeClass(cursor);
@@ -335,7 +332,7 @@ options.registry.marginAndResize = options.Class.extend({
$body.mousemove(body_mousemove);
$body.mouseup(body_mouseup);
});
this.$overlay.find(".oe_handle.size .auto_size").on('click', function (event){
this.$overlay.find(".oe_handle.size .auto_size").on('click', function (event) {
self.$target.css("height", "");
self.$target.css("overflow", "");
self.buildingBlock.parent.rte.historyRecordUndo(self.$target, 'resize_Y');
@@ -419,7 +416,7 @@ options.registry["margin-x"] = options.registry.marginAndResize.extend(preventPa
return this.grid;
},
_drag_and_drop_after_insert_dropzone: function(){
_drag_and_drop_after_insert_dropzone: function () {
var self = this;
$(".row:has(> .oe_drop_zone)").each(function () {
var $row = $(this);
@@ -729,7 +726,9 @@ options.registry.collapse = options.Class.extend(preventParentEmpty).extend({
this.create_ids(this.$target);
},
on_clone: function ($clone) {
this._super();
this._super.apply(this, arguments);
$clone.find('[data-toggle="collapse"]').removeAttr('data-target').removeData('target');
$clone.find('.panel-collapse').removeAttr('id');
this.create_ids($clone);
},
on_move: function () {
@@ -24,7 +24,7 @@ ajax.loadXML('/website/static/src/xml/website.gallery.xml', qweb);
Look at /website/views/snippets.xml for the available options
------------------------------------------------------------------------*/
options.registry.gallery = options.Class.extend({
start : function() {
start : function () {
this._super();
this.bind_change();
var index = Math.max(_.map(this.$target.find("img").get(), function (img) { return img.dataset.index | 0; }));
@@ -37,27 +37,27 @@ options.registry.gallery = options.Class.extend({
this._temp_mode = this.$el.find("data-mode").data("mode");
this._temp_col = this.$el.find("data-columns").data("columns");
},
drop_and_build_snippet: function() {
drop_and_build_snippet: function () {
var uuid = new Date().getTime();
this.$target.find('.carousel').attr('id', 'slideshow_' + uuid);
this.$target.find('[data-target]').attr('data-target', '#slideshow_' + uuid);
},
styling : function(type, value) {
styling : function (type, value) {
var classes = this.$el.find('li[data-styling]').map(function () {
return $(this).data('styling');
}).get().join(' ');
this.$target.find("img").removeClass(classes).addClass(value);
},
interval : function(type, value) {
interval : function (type, value) {
this.$target.find('.carousel:first').attr("data-interval", value);
},
reapply : function() {
reapply : function () {
var self = this,
modes = [ 'o_nomode', 'o_grid', 'o_masonry', 'o_slideshow' ],
classes = this.$target.attr("class").split(/\s+/);
this.cancel_masonry();
modes.forEach(function(mode) {
modes.forEach(function (mode) {
if (classes.indexOf(mode) != -1) {
self.mode("reapply", mode.slice(2, Infinity));
return;
@@ -98,7 +98,7 @@ options.registry.gallery = options.Class.extend({
$container.empty().append($content);
return $container;
},
nomode : function(type) {
nomode : function (type) {
if (type !== "reapply" && !this.$target.attr('class').match(/o_grid|o_masonry|o_slideshow/)) return;
var self = this,
@@ -126,7 +126,7 @@ options.registry.gallery = options.Class.extend({
$(this.masonry_imgs).appendTo(this.$target);
this.masonry_imgs = [];
},
masonry : function(type) {
masonry : function (type) {
var self = this,
imgs = this.get_imgs(),
columns = this.get_columns(),
@@ -160,7 +160,7 @@ options.registry.gallery = options.Class.extend({
if (imgs.length) add();
this.$target.css("height", "");
},
grid : function(type) {
grid : function (type) {
if (type !== "reapply" && this.$target.hasClass('o_grid')) return;
var self = this,
@@ -171,7 +171,7 @@ options.registry.gallery = options.Class.extend({
colClass = "col-md-"+(12/columns),
$container = this.replace($row);
$imgs.each(function(index) { // 0 based index
$imgs.each(function (index) { // 0 based index
$img = $(this);
$col = $img.wrap('<div>').parent();
self.img_preserve_styles($img);
@@ -190,7 +190,7 @@ options.registry.gallery = options.Class.extend({
var self = this,
$imgs = $(this.get_imgs()),
urls = $imgs.map(function() { return $(this).attr("src"); } ).get();
urls = $imgs.map(function () { return $(this).attr("src"); } ).get();
var params = {
srcs : urls,
index: 0,
@@ -215,14 +215,14 @@ options.registry.gallery = options.Class.extend({
this.$target.data("snippet-view").start(true);
}
},
columns : function(type, value) {
columns : function (type, value) {
this.$target.attr("data-columns", value);
if (this._temp_col !== value) {
this._temp_col = value;
this.reapply();
}
},
images_add : function(type) {
images_add : function (type) {
if(type !== "click") return;
var self = this;
var $container = this.$target.find(".container:first");
@@ -243,16 +243,16 @@ options.registry.gallery = options.Class.extend({
},0);
});
},
images_rm : function(type) {
images_rm : function (type) {
if(type !== "click") return;
this.replace($('<div class="alert alert-info css_editable_mode_display"/>').text(_t("Add Images from the 'Customize' menu")));
},
sizing : function() { // done via css, keep it to avoid undefined error
sizing : function () { // done via css, keep it to avoid undefined error
},
/*
* helpers
*/
styles_to_preserve : function($img) {
styles_to_preserve : function ($img) {
var styles = [ 'img-rounded', 'img-thumbnail', 'img-circle', 'shadow', 'fa-spin' ];
var preserved = [];
@@ -263,17 +263,17 @@ options.registry.gallery = options.Class.extend({
}
return preserved.join(' ');
},
img_preserve_styles : function($img) {
img_preserve_styles : function ($img) {
var classes = this.styles_to_preserve($img);
$img.removeAttr("class");
$img.addClass(classes);
return $img;
},
img_responsive : function(img) {
img_responsive : function (img) {
img.addClass("img img-responsive");
return img;
},
lowest : function($cols) {
lowest : function ($cols) {
var height = 0, min = -1, col=0, lowest = undefined;
$cols.each(function () {
var $col = $(this);
@@ -285,11 +285,11 @@ options.registry.gallery = options.Class.extend({
});
return lowest;
},
get_columns : function() {
get_columns : function () {
return parseInt(this.$target.attr("data-columns") || 3);
},
clean_for_save: function() {
clean_for_save: function () {
var self = this;
if (this.$target.hasClass("slideshow")) {
this.$target.removeAttr("style");
+14 -22
View File
@@ -45,7 +45,6 @@ var Theme = Widget.extend({
this.timer = null;
this.reload = false;
this.flag = false;
this.$el.addClass("theme_customize_modal");
this.active_select_tags();
this.$inputs = this.$("input[data-xmlid],input[data-enable],input[data-disable]");
setTimeout(function () {self.$el.addClass('in');}, 0);
@@ -95,20 +94,20 @@ var Theme = Widget.extend({
var self = this;
$('#theme_error').remove();
return ajax.jsonRpc('/website/theme_customize_get', 'call', {
'xml_ids': this.get_xml_ids(this.$inputs)
}).done(function (data) {
self.$inputs.filter('[data-xmlid=""]').prop("checked", true).change();
self.$inputs.filter('[data-xmlid]:not([data-xmlid=""])').each(function () {
if (!_.difference(self.get_xml_ids($(this)), data[1]).length) {
$(this).prop("checked", false).trigger("change", true);
}
if (!_.difference(self.get_xml_ids($(this)), data[0]).length) {
$(this).prop("checked", true).trigger("change", true);
}
});
}).fail(function (d, error) {
$('body').prepend($('<div id="theme_error"/>').text(error.data.message));
'xml_ids': this.get_xml_ids(this.$inputs)
}).done(function (data) {
self.$inputs.filter('[data-xmlid=""]').prop("checked", true).change();
self.$inputs.filter('[data-xmlid]:not([data-xmlid=""])').each(function () {
if (!_.difference(self.get_xml_ids($(this)), data[1]).length) {
$(this).prop("checked", false).trigger("change", true);
}
if (!_.difference(self.get_xml_ids($(this)), data[0]).length) {
$(this).prop("checked", true).trigger("change", true);
}
});
}).fail(function (d, error) {
$('body').prepend($('<div id="theme_error"/>').text(error.data.message));
});
},
get_inputs: function (string) {
return this.$inputs.filter('#'+string.split(/\s*,\s*/).join(", #"));
@@ -278,14 +277,7 @@ function themeError(message) {
message = '<span class="text-muted">' + message + "</span><br/><br/>" + _t("Please install or update node-less");
}
var $error = $( QWeb.render('website.error_dialog', {
title: _t("Theme Error"),
message: message
}));
$error.appendTo("body").modal();
$error.on('hidden.bs.modal', function () {
$(this).remove();
});
website.error(_t("Theme Error"), message);
}
function theme_customize() {
@@ -55,13 +55,13 @@ var nodialog = 'website_translator_nodialog';
var Translate = translate.Class.include({
onTranslateReady: function () {
if(this.gengo_translate){
if(this.gengo_translate) {
this.translation_gengo_display();
}
this._super();
},
edit: function () {
$("#website_main_menu_navbar").hide();
$("#oe_main_menu_navbar").hide();
if (!localStorage[nodialog]) {
var dialog = new TranslatorDialog();
dialog.appendTo($(document.body));
@@ -77,7 +77,7 @@ var Translate = translate.Class.include({
return this._super();
},
cancel: function () {
$("#website_main_menu_navbar").show();
$("#oe_main_menu_navbar").show();
return this._super();
}
});
@@ -10,7 +10,7 @@
-->
<t t-name="website.gallery.dialog.upload">
<div class="modal website_modal fade" >
<div class="modal o_website_modal fade" >
<div class="modal-dialog" style="max-width: 50%;">
<div class="modal-content">
<div class="modal-header">
@@ -69,9 +69,9 @@
<a class="carousel-control right" t-attf-href="##{id}" data-slide="next"><span class="fa fa-chevron-right" /></a>
</div> <!-- carousel-id -->
<script type="text/javascript">
(function() {
(function () {
$(".slideshow").css("height", Math.round(window.innerHeight*0.7));
$(window).on("resize", function() { $(".slideshow").css("height", Math.round(window.innerHeight*0.7)); });
$(window).on("resize", function () { $(".slideshow").css("height", Math.round(window.innerHeight*0.7)); });
})();
</script>
</t>
@@ -88,7 +88,7 @@
-->
<t t-name="website.gallery.slideshow.lightbox">
<div class="modal website_modal fade" aria-labbelledby="Image Gallery Dialog" aria-hidden="true">
<div class="modal o_website_modal fade" aria-labbelledby="Image Gallery Dialog" aria-hidden="true">
<div class="modal-dialog modal-lg" role="Picture Gallery"
t-attf-style="min-width: #{dim.min_width}px ; min-height: #{dim.min_height}px ; max-width: #{dim.max_width}px ; max-height: #{dim.max_height}px ; height: #{dim.height}px ;">
+46 -73
View File
@@ -11,85 +11,58 @@
</t>
</t>
<t t-name="website.seo_configuration">
<div class="modal website_modal fade oe_seo_configuration js_seo_configuration" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button title="Close" type="button" class="close" data-dismiss="modal">×</button>
<div class="h2">Promote This Page</div>
<div class="text-muted">
Get this page efficiently referenced in Google to attract more visitors.
<div t-name="website.seo_configuration">
<div class="js_seo_tips" />
<section class="js_seo_keywords_list">
<h3 class="page-header mt16">1. Define Keywords <small>describing your page content</small></h3>
<div class="form-horizontal" role="form">
<div class="form-group">
<label for="seo_page_keywords" class="col-sm-3 control-label">Add keyword:</label>
<div class="col-sm-4">
<div>
<input type="text" name="seo_page_keywords" class="form-control" maxlength="30"/>
</div>
</div>
<div class="modal-body">
<div class="js_seo_tips" />
<section class="js_seo_keywords_list">
<h3 class="page-header mt16">1. Define Keywords <small>describing your page content</small></h3>
<div class="form-horizontal" role="form">
<div class="form-group">
<label for="seo_page_keywords" class="col-sm-3 control-label">Add keyword:</label>
<div class="col-sm-4">
<div>
<input type="text" name="seo_page_keywords" class="form-control" maxlength="30"/>
</div>
</div>
</div>
<div class="row mt8">
<label for="seo_page_language" class="col-sm-3 control-label">Language:</label>
<div>
<div class="col-sm-4">
<select name="seo_page_language" id="language-box" class="form-control"/>
</div>
</div>
</div>
<div class="row mt8">
<div class="col-md-10 text-center">
<button data-action="add" class="btn btn-default" type="button">Add</button>
</div>
</div>
</div>
<span class="text-muted">Most searched topics related to your keywords, ordered by importance:</span>
<!-- filled in JS -->
</section>
<section>
<h3 class="page-header">2. Reference Your Page <small>using above suggested keywords</small></h3>
<div class="form-horizontal mt16" role="form">
<div class="form-group">
<label for="seo_page_title" class="col-sm-2 control-label">Title</label>
<div class="col-sm-8">
<input type="text" name="seo_page_title" class="form-control" maxlength="70" size="70"/>
</div>
</div>
<div class="form-group">
<label for="seo_page_description" class="col-sm-2 control-label">Description</label>
<div class="col-sm-8">
<textarea name="seo_page_description" class="form-control" rows="3" cols="70" t-att-maxlength="widget.maxDescriptionSize"/>
</div>
</div>
</div>
</section>
<section>
<h3 class="page-header">3. Preview <small>how your page will be listed on Google</small></h3>
<div class="js_seo_preview"></div>
</section>
<!--
<section class="js_image_section">
<h3 class="page-header">4. Describe your images</h3>
<div class="row js_seo_image_list">
</div>
</section>
-->
</div>
<div class="row mt8">
<label for="seo_page_language" class="col-sm-3 control-label">Language:</label>
<div>
<div class="col-sm-4">
<select name="seo_page_language" id="language-box" class="form-control"/>
</div>
</div>
<div class="modal-footer">
<button type="button" data-action="update" class="btn btn-primary">Save</button>
or
<a data-action="discard" data-dismiss="modal" href="#" >Discard</a>
</div>
<div class="row mt8">
<div class="col-md-10 text-center">
<button data-action="add" class="btn btn-default" type="button">Add</button>
</div>
</div>
</div>
</div>
</t>
<span class="text-muted">Most searched topics related to your keywords, ordered by importance:</span>
<!-- filled in JS -->
</section>
<section>
<h3 class="page-header">2. Reference Your Page <small>using above suggested keywords</small></h3>
<div class="form-horizontal mt16" role="form">
<div class="form-group">
<label for="seo_page_title" class="col-sm-2 control-label">Title</label>
<div class="col-sm-8">
<input type="text" name="seo_page_title" class="form-control" maxlength="70" size="70"/>
</div>
</div>
<div class="form-group">
<label for="seo_page_description" class="col-sm-2 control-label">Description</label>
<div class="col-sm-8">
<textarea name="seo_page_description" class="form-control" rows="3" cols="70" t-att-maxlength="widget.maxDescriptionSize"/>
</div>
</div>
</div>
</section>
<section>
<h3 class="page-header">3. Preview <small>how your page will be listed on Google</small></h3>
<div class="js_seo_preview"></div>
</section>
</div>
<t t-name="website.seo_suggestion_list">
<ul class="list-inline mb0">
@@ -6,7 +6,7 @@
</t>
<t t-name="website.TranslatorDialog">
<div class="modal website_modal fade oe_website_translator" tabindex="-1" role="dialog">
<div class="modal o_website_modal fade oe_website_translator" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
+20 -45
View File
@@ -1,49 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="website.mobile_preview">
<div class="modal website_modal fade oe_mobile_preview" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button title="Close" type="button" class="close" data-dismiss="modal">×</button>
<h3 class="modal-title">Mobile preview</h3>
</div>
<div class="modal-body">
<iframe id="mobile-viewport" class="oe_mobile_viewport" style="width: 326px"></iframe>
</div>
</div>
</div>
</div>
<t t-extend="Dialog">
<t t-jquery=".modal-dialog">
$(this).parent().addClass('o_website_modal');
</t>
</t>
<t t-name="website.error_dialog">
<div class="modal website_modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button title="Close" type="button" class="close" data-dismiss="modal">×</button>
<div class="h2"><t t-esc="title"/></div>
</div>
<div class="modal-body" t-if="message or backend_url">
<section>
<t t-raw="message"/>
</section>
<section class="mt32" t-if="backend_url">
<p>The web site has encountered an error.</p>
<p>
It might be possible to edit the relevant items
or fix the issue in <a t-attf-href="#{backend_url}">
the classic Odoo interface</a>.
</p>
</section>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn btn-primary">Close</button>
</div>
</div>
</div>
</div>
</t>
<div t-name="website.mobile_preview">
<iframe id="mobile-viewport" t-att-src="widget.mobile_src"/>
</div>
<div t-name="website.error_dialog">
<section t-if="message">
<t t-raw="message"/>
</section>
<section class="mt32" t-if="backend_url">
<p>The web site has encountered an error.</p>
<p>It might be possible to edit the relevant items or fix the issue in <a t-attf-href="#{backend_url}"> the classic Odoo interface</a>.</p>
</section>
</div>
<t t-name="website.prompt">
<t t-call="website.modal_base">
@@ -63,7 +38,7 @@
</t>
<t t-name="website.modal_base">
<div class="modal website_modal " tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal o_website_modal " tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<t t-call="website.modal_header" />
@@ -84,8 +59,8 @@
<t t-name="website.modal_footer">
<div class="modal-footer">
<button type="button" class="btn btn-primary btn-continue">Continue</button>
<button type="button" class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button>
<button type="button" class="btn btn-sm btn-primary btn-continue">Continue</button>
<button type="button" class="btn btn-sm btn-default" data-dismiss="modal" aria-hidden="true">Cancel</button>
</div>
</t>
@@ -5,7 +5,6 @@ var core = require('web.core');
var Model = require('web.Model');
var base = require('web_editor.base');
var options = require('web_editor.snippets.options');
var snippet_editor = require('web_editor.snippet.editor');
var website = require('website.website');
var _t = core._t;
@@ -7,11 +7,9 @@ var core = require('web.core');
var base = require('web_editor.base');
var web_editor = require('web_editor.editor');
var options = require('web_editor.snippets.options');
var snippet_editor = require('web_editor.snippet.editor');
var website = require('website.website');
var _t = core._t;
var mass_mailing_common = options.Class.extend({
popup_template_id: "editor_new_mailing_list_subscribe_button",
popup_title: _t("Add a Newsletter Subscribe Button"),