diff options
| author | Christophe Matthieu <chm@odoo.com> | 2014-08-08 11:58:40 +0200 |
|---|---|---|
| committer | Christophe Matthieu <chm@odoo.com> | 2014-08-08 11:58:40 +0200 |
| commit | 777a082bfc8de9d3a4d3e7c144453c9efb14751c (patch) | |
| tree | 3068953a09822f72fe501b16cd1ee047c8e11f80 /addons/website/static/src/js | |
| parent | eb23f30c7e3bcb1fa19c9a9f9d0291d802abe462 (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.js | 111 | ||||
| -rw-r--r-- | addons/website/static/src/js/website.snippets.editor.js | 50 | ||||
| -rw-r--r-- | addons/website/static/src/js/website.theme.js | 263 |
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 = ""; + } + }); + +})(); |
