summaryrefslogtreecommitdiff
path: root/addons/website/static/src/js
diff options
context:
space:
mode:
authorChristophe Matthieu <chm@odoo.com>2014-08-08 11:58:40 +0200
committerChristophe Matthieu <chm@odoo.com>2014-08-08 11:58:40 +0200
commit777a082bfc8de9d3a4d3e7c144453c9efb14751c (patch)
tree3068953a09822f72fe501b16cd1ee047c8e11f80 /addons/website/static/src/js
parenteb23f30c7e3bcb1fa19c9a9f9d0291d802abe462 (diff)
[IMP] website: create customize theme application and color-picker; Create theme_bootswatch and use less files.
Diffstat (limited to 'addons/website/static/src/js')
-rw-r--r--addons/website/static/src/js/website.editor.js111
-rw-r--r--addons/website/static/src/js/website.snippets.editor.js50
-rw-r--r--addons/website/static/src/js/website.theme.js263
3 files changed, 417 insertions, 7 deletions
diff --git a/addons/website/static/src/js/website.editor.js b/addons/website/static/src/js/website.editor.js
index 60076b9664b..9b86002626c 100644
--- a/addons/website/static/src/js/website.editor.js
+++ b/addons/website/static/src/js/website.editor.js
@@ -209,6 +209,111 @@
}
});
+ CKEDITOR.plugins.add('customColor', {
+ requires: 'panelbutton,floatpanel',
+ init: function (editor) {
+ function create_button (buttonID, label) {
+ var btnID = buttonID;
+ editor.ui.add(buttonID, CKEDITOR.UI_PANELBUTTON, {
+ label: label,
+ title: label,
+ modes: { wysiwyg: true },
+ editorFocus: true,
+ context: 'font',
+ panel: {
+ css: [ '/web/css/web.assets_common/' + (new Date().getTime()),
+ '/web/css/website.assets_frontend/' + (new Date().getTime()),
+ '/web/css/website.assets_editor/' + (new Date().getTime())],
+ attributes: { 'role': 'listbox', 'aria-label': label },
+ },
+ enable: function () {
+ this.setState(CKEDITOR.TRISTATE_OFF);
+ },
+ disable: function () {
+ this.setState(CKEDITOR.TRISTATE_DISABLED);
+ },
+ onBlock: function (panel, block) {
+ var self = this;
+ var html = openerp.qweb.render('website.colorpicker');
+ block.autoSize = true;
+ block.element.setHtml( html );
+ $(block.element.$).on('click', 'button', function () {
+ self.clicked(this);
+ });
+ if (btnID === "TextColor") {
+ $(".only-text", block.element.$).css("display", "block");
+ $(".only-bg", block.element.$).css("display", "none");
+ }
+ var $body = $(block.element.$).parents("body");
+ setTimeout(function () {
+ $body.css('background-color', '#fff');
+ }, 0);
+ },
+ getClasses: function () {
+ var self = this;
+ var classes = [];
+ var id = this._.id;
+ var block = this._.panel._.panel._.blocks[id];
+ var $root = $(block.element.$);
+ $root.find("button").map(function () {
+ var color = self.getClass(this);
+ if(color) classes.push( color );
+ });
+ return classes;
+ },
+ getClass: function (button) {
+ var color = btnID === "BGColor" ? $(button).attr("class") : $(button).attr("class").replace(/^bg-/i, 'text-');
+ return color.length && color;
+ },
+ clicked: function (button) {
+ var className = this.getClass(button);
+ var ancestor = editor.getSelection().getCommonAncestor();
+
+ editor.focus();
+ this._.panel.hide();
+ editor.fire('saveSnapshot');
+
+ // remove style
+ var classes = [];
+ var $ancestor = $(ancestor.$);
+ var $fonts = $(ancestor.$).find('font');
+ if (!ancestor.$.tagName) {
+ $ancestor = $ancestor.parent();
+ }
+ if ($ancestor.is('font')) {
+ $fonts = $fonts.add($ancestor[0]);
+ }
+
+ $fonts.filter("."+this.getClasses().join(",.")).map(function () {
+ var className = $(this).attr("class");
+ if (classes.indexOf(className) === -1) {
+ classes.push(className);
+ }
+ });
+ for (var k in classes) {
+ editor.removeStyle( new CKEDITOR.style({
+ element: 'font',
+ attributes: { 'class': classes[k] },
+ }) );
+ }
+
+ // add new style
+ if (className) {
+ editor.applyStyle( new CKEDITOR.style({
+ element: 'font',
+ attributes: { 'class': className },
+ }) );
+ }
+ editor.fire('saveSnapshot');
+ }
+
+ });
+ }
+ create_button("BGColor", "Background Color");
+ create_button("TextColor", "Text Color");
+ }
+ });
+
CKEDITOR.plugins.add('oeref', {
requires: 'widget',
@@ -564,7 +669,7 @@
website.EditorBarCustomize = openerp.Widget.extend({
events: {
'mousedown a.dropdown-toggle': 'load_menu',
- 'click ul a[data-action!=ace]': 'do_customize',
+ 'click li:not(#html_editor):not(#theme_customize):not(#install_apps) a': 'do_customize',
},
start: function() {
var self = this;
@@ -868,7 +973,7 @@
fillEmptyBlocks: false,
filebrowserImageUploadUrl: "/website/attach",
// Support for sharedSpaces in 4.x
- extraPlugins: 'sharedspace,customdialogs,tablebutton,oeref',
+ extraPlugins: 'customColor,sharedspace,customdialogs,tablebutton,oeref',
// Place toolbar in controlled location
sharedSpaces: { top: 'oe_rte_toolbar' },
toolbar: [{
@@ -900,7 +1005,7 @@
{name: "Heading 5", element: 'h5'},
{name: "Heading 6", element: 'h6'},
{name: "Formatted", element: 'pre'},
- {name: "Address", element: 'address'}
+ {name: "Address", element: 'address'},
],
};
},
diff --git a/addons/website/static/src/js/website.snippets.editor.js b/addons/website/static/src/js/website.snippets.editor.js
index 16304f95d01..4630206748f 100644
--- a/addons/website/static/src/js/website.snippets.editor.js
+++ b/addons/website/static/src/js/website.snippets.editor.js
@@ -942,6 +942,48 @@
}
});
+ website.snippet.options.colorpicker = website.snippet.Option.extend({
+ start: function () {
+ var self = this;
+ var res = this._super();
+
+ this.$el.find('li').append( openerp.qweb.render('website.colorpicker') );
+
+ var classes = [];
+ this.$el.find("table.colorpicker td > *").map(function () {
+ var $color = $(this);
+ var color = $color.attr("class");
+ if (self.$target.hasClass(color)) {
+ self.color = color;
+ $color.parent().addClass("selected");
+ }
+ classes.push(color);
+ });
+ this.classes = classes.join(" ");
+
+ this.bind_events();
+ return res;
+ },
+ bind_events: function () {
+ var self = this;
+ var $td = this.$el.find("table.colorpicker td");
+ var $colors = $td.children();
+ $colors
+ .mouseenter(function () {
+ self.$target.removeClass(self.classes).addClass($(this).attr("class"));
+ })
+ .mouseleave(function () {
+ self.$target.removeClass(self.classes)
+ .addClass($td.filter(".selected").children().attr("class"));
+ })
+ .click(function () {
+ $td.removeClass("selected");
+ $(this).parent().addClass("selected");
+ });
+ }
+ });
+
+
website.snippet.options.slider = website.snippet.Option.extend({
unique_id: function () {
var id = 0;
@@ -975,10 +1017,10 @@
},
clean_for_save: function () {
this._super();
- this.$target.find(".item").removeClass("next prev left right active");
- this.$target.find(".item:first").addClass("active");
- this.$indicators.find('li').removeClass('active');
- this.$indicators.find('li:first').addClass('active');
+ this.$target.find(".item").removeClass("next prev left right active")
+ .first().addClass("active");
+ this.$indicators.find('li').removeClass('active')
+ .first().addClass("active");
},
start : function () {
var self = this;
diff --git a/addons/website/static/src/js/website.theme.js b/addons/website/static/src/js/website.theme.js
new file mode 100644
index 00000000000..af23b6e3dc5
--- /dev/null
+++ b/addons/website/static/src/js/website.theme.js
@@ -0,0 +1,263 @@
+(function () {
+ 'use strict';
+
+ openerp.website.add_template_file('/website/static/src/xml/website.theme.xml');
+
+ openerp.website.Theme = openerp.Widget.extend({
+ template: 'website.theme_customize',
+ events: {
+ 'change input[data-xmlid],input[data-enable],input[data-disable]': 'change_selection',
+ 'click .close': 'close',
+ },
+ start: function () {
+ var self = this;
+ this.timer = null;
+ this.reload = false;
+ this.flag = false;
+ this.$el.addClass("theme_customize_modal");
+ this.active_select_tags();
+ this.$inputs = $("input[data-xmlid],input[data-enable],input[data-disable]");
+ setTimeout(function () {self.$el.addClass('in');}, 0);
+ return this.load_xml_data().then(function () {
+ self.flag = true;
+ });
+ },
+ active_select_tags: function () {
+ var uniqueID = 0;
+ var self = this;
+ var $selects = this.$('select:has(option[data-xmlid],option[data-enable],option[data-disable])');
+ $selects.each(function () {
+ uniqueID++;
+ var $select = $(this);
+ var $options = $select.find('option[data-xmlid], option[data-enable], option[data-disable]');
+ $options.each(function () {
+ var $option = $(this);
+ var $input = $('<input style="display: none;" type="radio" name="theme_customize_modal-select-'+uniqueID+'"/>');
+ $input.attr('id', $option.attr('id'));
+ $input.attr('data-xmlid', $option.data('xmlid'));
+ $input.attr('data-enable', $option.data('enable'));
+ $input.attr('data-disable', $option.data('disable'));
+ $option.removeAttr('id');
+ $option.data('input', $input);
+ $input.on('update', function () {
+ $option.attr('selected', $(this).prop("checked"));
+ });
+ self.$el.append($input);
+ });
+ $select.data("value", $options.first());
+ $options.first().attr("selected", true);
+ });
+ $selects.change(function () {
+ var $option = $(this).find('option:selected');
+ $(this).data("value").data("input").prop("checked", true).change();
+ $(this).data("value", $option);
+ $option.data("input").change();
+ });
+ },
+ load_xml_data: function (xml_ids) {
+ var self = this;
+ $('#theme_error').remove();
+ return openerp.jsonRpc('/website/theme_customize_get', 'call', {
+ 'xml_ids': this.get_xml_ids(this.$inputs)
+ }).done(function (data) {
+ self.$inputs.filter('[data-xmlid]').each(function () {
+ if (!_.difference(self.get_xml_ids($(this)), data[1]).length) {
+ $(this).prop("checked", false).change();
+ }
+ if (!_.difference(self.get_xml_ids($(this)), data[0]).length) {
+ $(this).prop("checked", true).change();
+ }
+ });
+ }).fail(function (d, error) {
+ $('body').prepend($('<div id="theme_error"/>').text(error.data.message));
+ });
+ },
+ get_inputs: function (string) {
+ return this.$inputs.filter('#'+string.split(",").join(", #"));
+ },
+ get_xml_ids: function ($inputs) {
+ var xml_ids = [];
+ $inputs.each(function () {
+ if ($(this).data('xmlid') && $(this).data('xmlid').length) {
+ xml_ids = xml_ids.concat($(this).data('xmlid').split(","));
+ }
+ });
+ return xml_ids;
+ },
+ compute_stylesheets: function () {
+ var self = this;
+ self.has_error = false;
+ $('link[href*=".assets_"]').attr('data-loading', true);
+ function theme_customize_css_onload() {
+ if ($('link[data-loading]').size()) {
+ $('body').toggleClass('theme_customize_css_loading');
+ setTimeout(theme_customize_css_onload, 50);
+ } else {
+ $('body').removeClass('theme_customize_css_loading');
+ self.$el.removeClass("loading");
+
+ if (window.getComputedStyle($('button[data-toggle="collapse"]:first')[0]).getPropertyValue('position') === 'static' ||
+ window.getComputedStyle($('#theme_customize_modal')[0]).getPropertyValue('display') === 'none') {
+ if (self.has_error) {
+ window.location.hash = "theme=true";
+ window.location.reload();
+ } else {
+ self.has_error = true;
+ $('link[href*=".assets_"][data-error]').removeAttr('data-error').attr('data-loading', true);
+ self.update_stylesheets();
+ setTimeout(theme_customize_css_onload, 50);
+ }
+ }
+ }
+ }
+ theme_customize_css_onload();
+ },
+ update_stylesheets: function () {
+ $('link[href*=".assets_"]').each(function update () {
+ var $style = $(this);
+ var href = $style.attr("href").replace(/[^\/]+$/, new Date().getTime());
+ var $asset = $('<link rel="stylesheet" href="'+href+'"/>');
+ $asset.attr("onload", "$(this).prev().attr('disable', true).remove(); $(this).removeAttr('onload').removeAttr('onerror');");
+ $asset.attr("onerror", "$(this).prev().removeAttr('data-loading').attr('data-error','loading'); $(this).attr('disable', true).remove();");
+ $style.after($asset);
+ });
+ },
+ update_style: function (enable, disable, reload) {
+ var self = this;
+ if (this.$el.hasClass("loading")) return;
+ this.$el.addClass("loading");
+
+ if (!reload && $('link[href*=".assets_"]').size()) {
+ this.compute_stylesheets();
+ return openerp.jsonRpc('/website/theme_customize', 'call', {
+ 'enable': enable,
+ 'disable': disable
+ }).then(function () {
+ self.update_stylesheets();
+ });
+ } else {
+ var href = '/website/theme_customize_reload'+
+ '?href='+encodeURIComponent(window.location.href)+
+ '&enable='+encodeURIComponent(enable.join(","))+
+ '&disable='+encodeURIComponent(disable.join(","));
+ window.location.href = href;
+ return $.Deferred();
+ }
+ },
+ enable_disable: function (data, enable) {
+ if (!data) return;
+ this.$('#'+data.split(",").join(", #")).each(function () {
+ var check = $(this).prop("checked");
+ var $label = $(this).closest("label");
+ $(this).attr("checked", enable);
+ if (enable) $label.addClass("checked");
+ else $label.removeClass("checked");
+ if (check != enable) {
+ $(this).change();
+ }
+ });
+ },
+ change_selection: function (event) {
+ var self = this;
+ if (this.$el.hasClass("loading")) return;
+
+ var $option = $(event.target),
+ checked = $option.prop("checked");
+
+ if (checked) {
+ this.enable_disable($option.data('enable'), true);
+ this.enable_disable($option.data('disable'), false);
+ $option.closest("label").addClass("checked");
+ } else {
+ $option.closest("label").removeClass("checked");
+ }
+ $option.prop("checked", checked);
+
+ var $enable = this.$inputs.filter('[data-xmlid]:checked');
+ $enable.closest("label").addClass("checked");
+ var $disable = this.$inputs.filter('[data-xmlid]:not(:checked)');
+ $disable.closest("label").removeClass("checked");
+
+ var $sets = this.$inputs.filter('input[data-enable]:not([data-xmlid]), input[data-disable]:not([data-xmlid])');
+ $sets.each(function () {
+ var $set = $(this);
+ var checked = true;
+ if ($set.data("enable")) {
+ self.get_inputs($(this).data("enable")).each(function () {
+ if (!$(this).prop("checked")) checked = false;
+ });
+ }
+ if ($set.data("disable")) {
+ self.get_inputs($(this).data("disable")).each(function () {
+ if ($(this).prop("checked")) checked = false;
+ });
+ }
+ if (checked) {
+ $set.prop("checked", true).closest("label").addClass("checked");
+ } else {
+ $set.prop("checked", false).closest("label").removeClass("checked");
+ }
+ $set.trigger('update');
+ });
+
+ if (this.flag && $option.data('reload') && document.location.href.match(new RegExp( $option.data('reload') ))) {
+ this.reload = true;
+ }
+
+ clearTimeout(this.timer);
+ if (this.flag) {
+ this.timer = setTimeout(function () {
+ self.update_style(self.get_xml_ids($enable), self.get_xml_ids($disable), self.reload);
+ self.reload = false;
+ },0);
+ } else {
+ this.timer = setTimeout(function () { self.reload = false; },0);
+ }
+ },
+ close: function () {
+ var self = this;
+ $('#theme_error').remove();
+ $('link[href*=".assets_"]').removeAttr('data-loading');
+ this.$el.removeClass('in');
+ this.$el.addClass('out');
+ setTimeout(function () {self.destroy();}, 500);
+ }
+ });
+
+ function themeError(message) {
+ var _t = openerp._t;
+
+ if (message.indexOf('lessc')) {
+ message = '<span class="text-muted">' + message + "</span><br/><br/>" + _t("Please install or update node-less");
+ }
+
+ var $error = $( openerp.qweb.render('website.error_dialog', {
+ title: _t("Theme Error"),
+ message: message
+ }));
+ $error.appendTo("body").modal();
+ $error.on('hidden.bs.modal', function () {
+ $(this).remove();
+ });
+ }
+
+
+ openerp.website.ready().done(function() {
+ function theme_customize() {
+ var error = window.getComputedStyle(document.body, ':before').getPropertyValue('content');
+ if (error && error !== 'none') {
+ return themeError(eval(error));
+ }
+ var Theme = openerp.website.Theme;
+ if (Theme.open && !Theme.open.isDestroyed()) return;
+ Theme.open = new Theme();
+ Theme.open.appendTo("body");
+ }
+ $(document).on('click', "#theme_customize a",theme_customize);
+ if ((window.location.hash || "").indexOf("theme=true") !== -1) {
+ theme_customize();
+ window.location.hash = "";
+ }
+ });
+
+})();