diff options
| author | Frederic van der Essen <fva@openerp.com / fvdessen+o@gmail.com> | 2014-08-25 16:42:57 +0200 |
|---|---|---|
| committer | Frederic van der Essen <fva@openerp.com / fvdessen+o@gmail.com> | 2014-08-25 16:42:57 +0200 |
| commit | d7f93defb899b2b48a14d679e5dffffdb4a00eff (patch) | |
| tree | f8572183b480477622917a1f504cf49a8e202f6e /addons/website/static/src/js | |
| parent | 2b67528fe9e366829d44d8aba756bc6e359b4c61 (diff) | |
| parent | 36146b3fadc47543f4b696ab75c31b3459afb15b (diff) | |
Merge branch 'master' into master-pos-new-payment-screen-fva
Conflicts:
addons/point_of_sale/point_of_sale.py
addons/point_of_sale/point_of_sale_view.xml
Diffstat (limited to 'addons/website/static/src/js')
| -rw-r--r-- | addons/website/static/src/js/website.editor.js | 123 | ||||
| -rw-r--r-- | addons/website/static/src/js/website.snippets.animation.js | 77 | ||||
| -rw-r--r-- | addons/website/static/src/js/website.snippets.editor.js | 1011 | ||||
| -rw-r--r-- | addons/website/static/src/js/website.snippets.gallery.js | 348 | ||||
| -rw-r--r-- | addons/website/static/src/js/website.theme.js | 277 |
5 files changed, 1301 insertions, 535 deletions
diff --git a/addons/website/static/src/js/website.editor.js b/addons/website/static/src/js/website.editor.js index f15278ee49f..205d8dde076 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', @@ -356,7 +461,13 @@ observer.disconnect(); var editor = this.rte.editor; var root = editor.element && editor.element.$; - editor.destroy(); + try { + editor.destroy(); + } + catch(err) { + // Hack to avoid the lost of all changes because ckeditor fails in destroy + console.log("Error in editor.destroy() : " + err.toString() + "\n " + err.stack); + } // FIXME: select editables then filter by dirty? var defs = this.rte.fetch_editables(root) .filter('.oe_dirty') @@ -558,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; @@ -862,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: [{ @@ -894,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'}, ], }; }, @@ -1457,9 +1568,9 @@ } var callback = _.uniqueId('func_'); this.$('input[name=func]').val(callback); - window[callback] = function (url, error) { + window[callback] = function (attachments, error) { delete window[callback]; - self.file_selected(url, error); + self.file_selected(attachments[0]['website_url'], error); }; }, file_selection: function () { diff --git a/addons/website/static/src/js/website.snippets.animation.js b/addons/website/static/src/js/website.snippets.animation.js index c72e2c3b84e..785027795ce 100644 --- a/addons/website/static/src/js/website.snippets.animation.js +++ b/addons/website/static/src/js/website.snippets.animation.js @@ -1,7 +1,9 @@ (function () { 'use strict'; + var website = openerp.website; + if (!website.snippet) website.snippet = {}; website.snippet.readyAnimation = []; @@ -37,7 +39,14 @@ } }); }; + + $(document).ready(function () { + if ($(".o_gallery:not(.oe_slideshow)").size()) { + // load gallery modal template + website.add_template_file('/website/static/src/xml/website.gallery.xml'); + } + website.snippet.start_animation(); }); @@ -69,7 +78,7 @@ website.snippet.animationRegistry.slider = website.snippet.Animation.extend({ selector: ".carousel", start: function () { - this.$target.carousel({interval: 10000}); + this.$target.carousel(); }, stop: function () { this.$target.carousel('pause'); @@ -154,4 +163,70 @@ this.$target.html('<div class="css_editable_mode_display"> </div><iframe src="'+this.$target.data("src")+'" frameborder="0" allowfullscreen="allowfullscreen"></iframe>'); }, }); + + /* ------------------------------------------------------------------------- + Gallery Animation + + This ads a Modal window containing a slider when an image is clicked + inside a gallery + -------------------------------------------------------------------------*/ + website.snippet.animationRegistry.gallery = website.snippet.Animation.extend({ + selector: ".o_gallery:not(.o_slideshow)", + start: function() { + var self = this; + this.$el.on("click", "img", this.click_handler); + }, + click_handler : function(event) { + var self = this; + var $cur = $(event.currentTarget); + var edition_mode = ($cur.closest("[contenteditable='true']").size() !== 0); + + // show it only if not in edition mode + if (!edition_mode) { + var urls = [], + idx = undefined, + milliseconds = undefined, + params = undefined, + $images = $cur.closest(".o_gallery").find("img"), + dimensions = { + min_width : Math.round( window.innerWidth * 0.7), + min_height : Math.round( window.innerHeight * 0.7), + max_width : Math.round( window.innerWidth * 0.7), + max_height : Math.round( window.innerHeight * 0.7), + height : Math.round( window.innerHeight * 0.7) + }; + + $images.each(function() { + urls.push($(this).attr("src")); + }); + var $img = ($cur.is("img") === true) ? $cur : $cur.closest("img"); + idx = urls.indexOf($img.attr("src")); + + milliseconds = $cur.closest(".o_gallery").data("interval") || false; + var params = { + srcs : urls, + index: idx, + dim : dimensions, + interval : milliseconds, + id: _.uniqueId("slideshow_") + }; + var $modal = $(openerp.qweb.render('website.gallery.slideshow.lightbox', params)); + $modal.modal({ + keyboard : true, + backdrop : true + }); + $modal.on('hidden.bs.modal', function() { + $(this).hide(); + $(this).siblings().filter(".modal-backdrop").remove(); // bootstrap leaves a modal-backdrop + $(this).remove(); + + }); + $modal.find(".modal-content, .modal-body.o_slideshow").css("height", "100%"); + + $modal.appendTo(document.body); + $modal.find(".carousel").carousel(); + } + } // click_handler + }); + })(); diff --git a/addons/website/static/src/js/website.snippets.editor.js b/addons/website/static/src/js/website.snippets.editor.js index 16304f95d01..fc06f4e6aaa 100644 --- a/addons/website/static/src/js/website.snippets.editor.js +++ b/addons/website/static/src/js/website.snippets.editor.js @@ -1,135 +1,6 @@ (function () { 'use strict'; -/* Building block / Snippet Editor - - The building blocks appear in the edit bar website. These prebuilt html block - allowing the designer to easily generate content on a page (drag and drop). - Options allow snippets to add customizations part html code according to their - selector (jQuery) and javascript object. - - How to create content? - - Designers can add their own html block in the "snippets" (/website/views/snippets.xml). - The block must be added in one of four menus (structure, content, feature or effect). - Structure: - <div> - <div class="oe_snippet_thumbnail"> - <img class="oe_snippet_thumbnail_img" src="...image src..."/> - <span class="oe_snippet_thumbnail_title">...Block Name...</span> - </div> - <div class="oe_snippet_body"> - ... - <!-- - The block with class 'oe_snippet_body' is inserted in the page. - This class is removed when the block is dropped. - The block can be made of any html tag and content. --> - </div> - </div> - - How to create options? - - Designers can add their own html block in the "snippet_options" (/website/views/snippets.xml). - Structure: - - <div data-snippet-option-id='...' <!-- Required: javascript object id (but javascript - for this option object is not required) --> - data-selector="..." <!-- Required: jQuery selector. - Apply options on all The part of html who - match with this jQuery selector. - E.g.: If the selector is div, all div will be selected - and can be highlighted and assigned an editor. --> - data-selector-siblings="..." <!-- Optional: jQuery selector. - The html part can be insert or move beside - the selected html block --> - data-selector-children="..." <!-- Optional: jQuery selector. - The html part can be insert or move inside - the selected html block --> - data-selector-vertical-children='...'> <!-- Optional: jQuery selector. - The html part can be insert or move inside - the selected html block. The drop zone is - displayed vertically --> - ... - <li><a href="#">...</a></li> <!-- Optional: html li list. - List of menu items displayed in customize - menu. If the li tag have 'data-class', the - class is automaticcally added or removed to - the html content when the user select this item. --> - ... - <li class="dropdown-submenu" <!-- Optional: html li list exemple. !--> - data-required="true"> <!-- Optional: if only one item can be selected - and can't be unselect. !--> - <a tabindex="-1" href="#">...</a> <!-- bootstrap dropdown button !--> - <ul class="dropdown-menu"> - <li data-value="text_only"><a>...</a></li> <!-- by default data-value is apply - like a class to html block !--> - </ul> - </li> - </div> - - How to create a javascript object for an options? - - openerp.website.snippet.options["...option-id..."] = website.snippet.Option.extend({ - // start is called when the user click into a block or when the user drop a block - // into the page (just after the init method). - // start is usually used to bind event. - // - // this.$target: block html inserted inside the page - // this.$el: html li list of this options - // this.$overlay: html editor overlay who content resize bar, customize menu... - start: function () {}, - - - // onFocus is called when the user click inside the block inserted in page - // and when the user drop on block into the page - onFocus : function () {}, - - - // onBlur is called when the user click outside the block inserted in page, if - // the block is focused - onBlur : function () {}, - - - // on_clone is called when the snippet is duplicate - // @variables: $clone is allready inserted is the page - on_clone: function ($clone) {}, - - - // on_remove is called when the snippet is removed (dom is removing after this tigger) - on_remove: function () {}, - - - // drop_and_build_snippet is called just after that a thumbnail is drag and dropped - // into a drop zone. The content is already inserted in the page. - drop_and_build_snippet: function () {}, - - // select is called when a user select an item in the li list of options - // By default, if the li item have a data-value attribute, the data-vlue it's apply - // like a class to the html block (this.$target) - // @variables: next_previous = {$next, $prev} - // $next = next item selected or false - // $prev = previous item selected or false - select: function (event, next_previous) {} - - // preview is called when a user is on mouse over or mouse out of an item - // variables: next_previous = {$next, $prev} - // $next = next item selected or false - // $prev = previous item selected or false - preview: function (event, next_previous) {} - - // clean_for_save - // clean_for_save is called just before to save the vue - // Sometime it's important to remove or add some datas (contentEditable, added - // classes to a running animation...) - clean_for_save: function () {} - }); - - - // 'snippet-dropped' is triggered on '#oe_snippets' whith $target as attribute when a snippet is dropped - // 'snippet-activated' is triggered on '#oe_snippets' (and on snippet) when a snippet is activated - -*/ - var dummy = function () {}; var website = openerp.website; @@ -177,8 +48,25 @@ } }); + $.extend($.expr[':'],{ + checkData: function(node,i,m){ + var dataName = m[3]; + while (node) { + if (node.dataset && node.dataset[dataName]) { + return true; + } else { + node = node.parentNode; + } + } + return false; + }, + hasData: function(node,i,m){ + return !!_.toArray(node.dataset).length; + }, + }); + if (!website.snippet) website.snippet = {}; - website.snippet.templateOptions = {}; + website.snippet.templateOptions = []; website.snippet.globalSelector = ""; website.snippet.selector = []; website.snippet.BuildingBlock = openerp.Widget.extend({ @@ -198,25 +86,6 @@ subtree: true, }); }, - dom_filter: function (dom, sibling) { - if (typeof dom === "string") { - var include = "[data-oe-model]"; - var sdom = dom.split(','); - dom = ""; - _.each(sdom, function (val) { - val = val.replace(/^\s+|\s+$/g, ''); - dom += include + " " + val + ", "; - if (!sibling) { - val = val.split(" "); - dom += val.shift() + include + val.join(" ") + ", "; - } - }); - dom = dom.replace(/,\s*$/g, ''); - return $(dom); - } else { - return (!sibling && $(dom).is("[data-oe-model]")) || $(dom).parents("[data-oe-model]").length ? $(dom) : $(""); - } - }, start: function() { var self = this; @@ -224,18 +93,16 @@ .prependTo(this.parent.$("#website-top-edit ul")) .find("button"); - this.$button.click(function () { - self.make_active(false); - self.$el.toggleClass("hidden"); - }); - $("#wrapwrap").click(function () { + this.$button.click(_.bind(this.show_blocks, this)); + + this.$snippet = $("#oe_snippets"); + this.$wrapwrap = $("#wrapwrap"); + this.$wrapwrap.click(function () { self.$el.addClass("hidden"); }); this.fetch_snippet_templates(); - this.bind_snippet_click_editor(); - this.$el.addClass("hidden"); $(document).on('click', '.dropdown-submenu a[tabindex]', function (e) { @@ -245,11 +112,69 @@ this.getParent().on('change:height', this, function (editor) { self.$el.css('top', editor.get('height')); }); - self.$el.css('top', this.parent.get('height')); + this.$el.css('top', this.parent.get('height')); + }, + show_blocks: function () { + var self = this; + this.make_active(false); + this.$el.toggleClass("hidden"); + if (this.$el.hasClass("hidden")) { + return; + } + + //this.enable_snippets( this.$snippet.find(".tab-pane.active") ); + var categories = this.$snippet.find(".tab-pane.active") + .add(this.$snippet.find(".tab-pane:not(.active)")) + .get().reverse(); + function enable() { + self.enable_snippets( $(categories.pop()) ); + if (categories.length) { + setTimeout(enable,10); + } + } + setTimeout(enable,0); + }, + enable_snippets: function ($category) { + var self = this; + $category.find(".oe_snippet_body").each(function () { + var $snippet = $(this); + + if (!$snippet.data('selectors')) { + var selectors = []; + for (var k in website.snippet.templateOptions) { + var option = website.snippet.templateOptions[k]; + if ($snippet.is(option.base_selector)) { + + var dropzone = []; + if (option['drop-near']) dropzone.push(option['drop-near']); + if (option['drop-in']) dropzone.push(option['drop-in']); + if (option['drop-in-vertical']) dropzone.push(option['drop-in-vertical']); + selectors = selectors.concat(dropzone); + } + } + $snippet.data('selectors', selectors.length ? selectors.join(":first, ") + ":first" : ""); + } + + if ($snippet.data('selectors').length && self.$wrapwrap.find($snippet.data('selectors')).size()) { + $snippet.closest(".oe_snippet").removeClass("disable"); + } else { + $snippet.closest(".oe_snippet").addClass("disable"); + } + }); + $('#oe_snippets .scroll a[data-toggle="tab"][href="#' + $category.attr("id") + '"]') + .toggle(!!$category.find(".oe_snippet:not(.disable)").size()); }, _get_snippet_url: function () { return '/website/snippets'; }, + _add_check_selector : function (selector, no_check) { + var data = selector.split(","); + var selectors = []; + for (var k in data) { + selectors.push(data[k].replace(/^\s+|\s+$/g, '') + (no_check ? "" : ":checkData(oeModel)")); + } + return selectors.join(", "); + }, fetch_snippet_templates: function () { var self = this; @@ -258,34 +183,30 @@ var $html = $(html); var selector = []; - var $styles = $html.find("[data-snippet-option-id]"); + var $styles = $html.find("[data-option], [data-selector]"); $styles.each(function () { var $style = $(this); - var style_id = $style.data('snippet-option-id'); - website.snippet.templateOptions[style_id] = { - 'snippet-option-id' : style_id, - 'selector': $style.data('selector'), + var no_check = $style.data('no-check'); + var option_id = $style.data('option'); + var option = { + 'option' : option_id, + 'base_selector': $style.data('selector'), + 'selector': self._add_check_selector($style.data('selector'), no_check), '$el': $style, - 'selector-siblings': $style.data('selector-siblings'), - 'selector-children': $style.data('selector-children'), - 'selector-vertical-children': $style.data('selector-vertical-children'), + 'drop-near': $style.data('drop-near') && self._add_check_selector($style.data('drop-near'), no_check), + 'drop-in': $style.data('drop-in') && self._add_check_selector($style.data('drop-in'), no_check), + 'drop-in-vertical': $style.data('drop-in-vertical') && self._add_check_selector($style.data('drop-in-vertical'), no_check), 'data': $style.data() }; - selector.push($style.data('selector')); + website.snippet.templateOptions.push(option); + selector.push(option.selector); }); $styles.addClass("hidden"); website.snippet.globalSelector = selector.join(","); self.$snippets = $html.find(".tab-content > div > div").addClass("oe_snippet"); - self.$el.append($html); - - var snippets = 0; - self.$snippets.each(function () { - if (self.snippet_have_dropzone($(this))) - snippets++; - }); - if (!snippets) self.$button.css("display", "none"); + self.$el.append($html); self.make_snippet_draggable(self.$snippets); }); @@ -310,17 +231,10 @@ hide: function () { this.$el.addClass("hidden"); }, - - snippet_have_dropzone: function ($snippet) { - return (($snippet.data('selector-siblings') && this.dom_filter($snippet.data('selector-siblings')).size() > 0) || - ($snippet.data('selector-children') && this.dom_filter($snippet.data('selector-children')).size() > 0) || - ($snippet.data('selector-vertical-children') && this.dom_filter($snippet.data('selector-vertical-children')).size() > 0)); - }, - bind_snippet_click_editor: function () { var self = this; var snipped_event_flag; - $("#wrapwrap").on('click', function (event) { + self.$wrapwrap.on('click', function (event) { if (snipped_event_flag || !event.srcElement) { return; } @@ -337,9 +251,6 @@ $target = $target.parents(website.snippet.globalSelector).first(); } - if (!self.dom_filter($target).length) { - $target = false; - } if (self.$active_snipped_id && self.$active_snipped_id.is($target)) { return; } @@ -349,14 +260,14 @@ snippet_blur: function ($snippet) { if ($snippet) { if ($snippet.data("snippet-editor")) { - $snippet.data("snippet-editor").onBlur(); + $snippet.data("snippet-editor").on_blur(); } } }, snippet_focus: function ($snippet) { if ($snippet) { if ($snippet.data("snippet-editor")) { - $snippet.data("snippet-editor").onFocus(); + $snippet.data("snippet-editor").on_focus(); } } }, @@ -364,15 +275,15 @@ var self = this; var options = website.snippet.options; var template = website.snippet.templateOptions; - for (var k in options) { - if (template[k] && options[k].prototype.clean_for_save !== dummy) { - var $snippet = this.dom_filter(template[k].selector); - $snippet.each(function () { - new options[k](self, null, $(this), k).clean_for_save(); + for (var k in template) { + var Option = options[template[k]['option']]; + if (Option && Option.prototype.clean_for_save !== dummy) { + self.$wrapwrap.find(template[k].selector).each(function () { + new Option(self, null, $(this), k).clean_for_save(); }); } } - $("*[contentEditable], *[attributeEditable]") + self.$wrapwrap.find("*[contentEditable], *[attributeEditable]") .removeAttr('contentEditable') .removeAttr('attributeEditable'); }, @@ -392,7 +303,7 @@ this.create_overlay(this.$active_snipped_id); this.snippet_focus($snippet); } - $("#oe_snippets").trigger('snippet-activated', $snippet); + this.$snippet.trigger('snippet-activated', $snippet); if ($snippet) { $snippet.trigger('snippet-activated', $snippet); } @@ -406,15 +317,6 @@ this.cover_target($snippet.data('overlay'), $snippet); }, - path_eval: function(path){ - var obj = window; - path = path.split('.'); - do{ - obj = obj[path.shift()]; - }while(path.length && obj); - return obj; - }, - // activate drag and drop for the snippets in the snippet toolbar make_snippet_draggable: function($snippets){ var self = this; @@ -437,32 +339,32 @@ start: function(){ self.hide(); dropped = false; - // snippet_selectors => to get selector-siblings, selector-children, selector-vertical-children + // snippet_selectors => to get drop-near, drop-in, drop-in-vertical $snippet = $(this); - $toInsert = $snippet.find('.oe_snippet_body').clone(); - + var $base_body = $snippet.find('.oe_snippet_body'); var selector = []; var selector_siblings = []; var selector_children = []; var selector_vertical_children = []; for (var k in website.snippet.templateOptions) { - if ($toInsert.is(website.snippet.templateOptions[k].selector)) { - selector.push(website.snippet.templateOptions[k].selector); - if (website.snippet.templateOptions[k]['selector-siblings']) - selector_siblings.push(website.snippet.templateOptions[k]['selector-siblings']); - if (website.snippet.templateOptions[k]['selector-children']) - selector_children.push(website.snippet.templateOptions[k]['selector-children']); - if (website.snippet.templateOptions[k]['selector-vertical-children']) - selector_vertical_children.push(website.snippet.templateOptions[k]['selector-vertical-children']); + if ($base_body.is(website.snippet.templateOptions[k].base_selector)) { + selector.push(website.snippet.templateOptions[k].base_selector); + if (website.snippet.templateOptions[k]['drop-near']) + selector_siblings.push(website.snippet.templateOptions[k]['drop-near']); + if (website.snippet.templateOptions[k]['drop-in']) + selector_children.push(website.snippet.templateOptions[k]['drop-in']); + if (website.snippet.templateOptions[k]['drop-in-vertical']) + selector_vertical_children.push(website.snippet.templateOptions[k]['drop-in-vertical']); } } + $toInsert = $base_body.clone(); action = $snippet.find('.oe_snippet_body').size() ? 'insert' : 'mutate'; if( action === 'insert'){ if (!selector_siblings.length && !selector_children.length && !selector_vertical_children.length) { - console.debug($snippet.data("snippet-id") + " have oe_snippet_body class and have not for insert action"+ - "data-selector-siblings, data-selector-children or data-selector-vertical-children tag for mutate action"); + console.debug($snippet.find(".oe_snippet_thumbnail_title").text() + " have not insert action: "+ + "data-drop-near, data-drop-in or data-drop-in-vertical"); return; } self.activate_insertion_zones({ @@ -473,7 +375,7 @@ } else if( action === 'mutate' ){ if (!$snippet.data('selector')) { - console.debug($snippet.data("snippet-id") + " have not oe_snippet_body class and have not data-selector tag"); + console.debug($snippet.data("option") + " have not oe_snippet_body class and have not data-selector tag"); return; } var $targets = self.activate_overlay_zones(selector_children.join(",")); @@ -504,38 +406,24 @@ stop: function(ev, ui){ $toInsert.removeClass('oe_snippet_body'); - if (action === 'insert' && ! dropped && $('.oe_drop_zone') && ui.position.top > 3) { - var el = $('.oe_drop_zone').nearest({x: ui.position.left, y: ui.position.top}).first(); + if (action === 'insert' && ! dropped && self.$wrapwrap.find('.oe_drop_zone') && ui.position.top > 3) { + var el = self.$wrapwrap.find('.oe_drop_zone').nearest({x: ui.position.left, y: ui.position.top}).first(); if (el.length) { el.after($toInsert); dropped = true; } } - $('.oe_drop_zone').droppable('destroy').remove(); + self.$wrapwrap.find('.oe_drop_zone').droppable('destroy').remove(); if (dropped) { var $target = false; $target = $toInsert; setTimeout(function () { - $("#oe_snippets").trigger('snippet-dropped', $target); + self.$snippet.trigger('snippet-dropped', $target); website.snippet.start_animation(true, $target); - // drop_and_build_snippet - self.create_overlay($target); - if ($target.data("snippet-editor")) { - $target.data("snippet-editor").drop_and_build_snippet(); - } - for (var k in website.snippet.templateOptions) { - $target.find(website.snippet.templateOptions[k].selector).each(function () { - var $snippet = $(this); - self.create_overlay($snippet); - if ($snippet.data("snippet-editor")) { - $snippet.data("snippet-editor").drop_and_build_snippet(); - } - }); - } // reset snippet for rte $target.removeData("snippet-editor"); @@ -551,7 +439,22 @@ $snippet.removeData("overlay"); } }); + // end + + // drop_and_build_snippet self.create_overlay($target); + if ($target.data("snippet-editor")) { + $target.data("snippet-editor").drop_and_build_snippet(); + } + for (var k in website.snippet.templateOptions) { + $target.find(website.snippet.templateOptions[k].selector).each(function () { + var $snippet = $(this); + self.create_overlay($snippet); + if ($snippet.data("snippet-editor")) { + $snippet.data("snippet-editor").drop_and_build_snippet(); + } + }); + } // end self.make_active($target); @@ -566,7 +469,7 @@ // return the original snippet in the editor bar from a snippet id (string) get_snippet_from_id: function(id){ return $('.oe_snippet').filter(function(){ - return $(this).data('snippet-id') === id; + return $(this).data('option') === id; }).first(); }, @@ -584,7 +487,7 @@ var zone_template = "<div class='oe_drop_zone oe_insert'></div>"; if(child_selector){ - self.dom_filter(child_selector).each(function (){ + self.$wrapwrap.find(child_selector).each(function (){ var $zone = $(this); $zone.find('> *:not(.oe_drop_zone):visible').after(zone_template); $zone.prepend(zone_template); @@ -592,7 +495,7 @@ } if(vertical_child_selector){ - self.dom_filter(vertical_child_selector).each(function (){ + self.$wrapwrap.find(vertical_child_selector).each(function (){ var $zone = $(this); var $template = $(zone_template).addClass("oe_vertical"); var nb = 0; @@ -623,7 +526,7 @@ } if(sibling_selector){ - self.dom_filter(sibling_selector, true).each(function (){ + self.$wrapwrap.find(sibling_selector, true).each(function (){ var $zone = $(this); if($zone.prev('.oe_drop_zone:visible').length === 0){ $zone.before(zone_template); @@ -641,13 +544,13 @@ // count += $zones.length; // $zones.remove(); - $zones = $('.oe_drop_zone > .oe_drop_zone:not(.oe_vertical)').remove(); // no recursive zones + $zones = self.$wrapwrap.find('.oe_drop_zone > .oe_drop_zone:not(.oe_vertical)').remove(); // no recursive zones count += $zones.length; $zones.remove(); } while (count > 0); // Cleaning up zones placed between floating or inline elements. We do not like these kind of zones. - var $zones = $('.oe_drop_zone:not(.oe_vertical)'); + var $zones = self.$wrapwrap.find('.oe_drop_zone:not(.oe_vertical)'); $zones.each(function (){ var zone = $(this); var prev = zone.prev(); @@ -671,14 +574,9 @@ // 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(selector){ - var $targets = this.dom_filter(selector); + var $targets = typeof selector === "string" ? this.$wrapwrap.find(selector) : selector; var self = this; - if (typeof selector !== 'string' && !$targets.length) { - console.debug( "A good node must have a [data-oe-model] attribute or must have at least one parent with [data-oe-model] attribute."); - console.debug( "Wrong node(s): ", selector); - } - function is_visible($el){ return $el.css('display') != 'none' && $el.css('opacity') != '0' @@ -719,9 +617,14 @@ $target.on("DOMNodeInserted DOMNodeRemoved DOMSubtreeModified", function () { self.cover_target($zone, $target); }); - $('body').on("resize", function () { - self.cover_target($zone, $target); - }); + var resize = function () { + if ($zone.parent().length) { + self.cover_target($zone, $target); + } else { + $('body').off("resize", resize); + } + }; + $('body').on("resize", resize); } self.cover_target($target.data('overlay'), $target); }); @@ -733,97 +636,86 @@ website.snippet.options = {}; website.snippet.Option = openerp.Class.extend({ // initialisation (don't overwrite) - init: function (BuildingBlock, editor, $target, snippet_id) { + init: function (BuildingBlock, editor, $target, option_id) { this.BuildingBlock = BuildingBlock; this.editor = editor; this.$target = $target; + var option = website.snippet.templateOptions[option_id]; var styles = this.$target.data("snippet-option-ids") || {}; - styles[snippet_id] = this; + styles[option_id] = this; this.$target.data("snippet-option-ids", styles); this.$overlay = this.$target.data('overlay'); - this['snippet-option-id'] = snippet_id; - var $option = website.snippet.templateOptions[snippet_id].$el; - this.$el = $option.find(">li").clone(); - this.data = $option.data(); - - this.required = this.$el.data("required"); + this.option= option_id; + this.$el = option.$el.find(">li").clone(); + this.data = option.$el.data(); this.set_active(); - this.$el.find('li[data-value] a').on('mouseenter mouseleave click', _.bind(this._mouse, this)); - this.$el.not(':not([data-value])').find("a").on('mouseenter mouseleave click', _.bind(this._mouse, this)); - this.$target.on('snippet-style-reset', _.bind(this.set_active, this)); + this.$target.on('snippet-option-reset', _.bind(this.set_active, this)); + this._bind_li_menu(); this.start(); }, - _mouse: function (event) { - var self = this; - if (event.type === 'mouseleave') { - if (!this.over) return; - this.over = false; - } else if (event.type === 'click') { - this.over = false; - }else { - this.over = true; - } + _bind_li_menu: function () { + this.$el.filter("li:hasData").find('a:first') + .off('mouseenter click') + .on('mouseenter click', _.bind(this._mouse, this)); - var $prev, $next; - if (event.type === 'mouseleave') { - $prev = $(event.currentTarget).parent(); - $next = this.$el.find("li[data-value].active"); - } else { - $prev = this.$el.find("li[data-value].active"); - $next = $(event.currentTarget).parent(); - } - if (!$prev.length) { - $prev = false; - } - if ($prev && $prev[0] === $next[0]) { - $next = false; - if (this.required) { - return; - } - } + this.$el + .off('mouseenter click', "li:hasData a") + .on('mouseenter click', "li:hasData a", _.bind(this._mouse, this)); + + this.$el.closest("ul").add(this.$el) + .off('mouseleave') + .on('mouseleave', _.bind(this.reset, this)); - var np = {'$next': $next, '$prev': $prev}; + this.$el + .off('mouseleave', "ul") + .on('mouseleave', "ul", _.bind(this.reset, this)); + this.reset_methods = []; + this.reset_time = null; + }, + + /** + * this method handles mouse:over and mouse:leave on the snippet editor menu + */ + _time_mouseleave: null, + _mouse: function (event) { + var $next = $(event.currentTarget).parent(); + + // triggers preview or apply methods if a menu item has been clicked + this.select(event.type === "click" ? "click" : "over", $next); if (event.type === 'click') { - setTimeout(function () { - self.set_active(); - self.$target.trigger("snippet-style-change", [self, np]); - },0); - this.select({'$next': $next, '$prev': $prev}); + this.set_active(); + this.$target.trigger("snippet-option-change", [this]); } else { - setTimeout(function () { - self.$target.trigger("snippet-style-preview", [self, np]); - },0); - this.preview(np); + this.$target.trigger("snippet-option-preview", [this]); } }, - /* set_active + /* * select and set item active or not (add highlight item and his parents) * called before start */ set_active: function () { - var self = this; - this.$el.find('li').removeClass("active"); - var $active = this.$el.find('li[data-value]') - .filter(function () { - var $li = $(this); - return ($li.data('value') && self.$target.hasClass($li.data('value'))); - }) - .first() + var classes = _.uniq((this.$target.attr("class") || '').split(/\s+/)); + this.$el.find('[data-check_class], [data-select_class]') + .add(this.$el) + .filter('[data-check_class], [data-select_class]') + .removeClass("active") + .filter('[data-check_class="' + classes.join('"], [data-check_class="') + '"] ,'+ + '[data-select_class="' + classes.join('"], [data-select_class="') + '"]') .addClass("active"); - this.$el.find('li:has(li[data-value].active)').addClass("active"); }, start: function () { }, - onFocus : function () { + on_focus : function () { + this._bind_li_menu(); }, - onBlur : function () { + on_blur : function () { }, on_clone: function ($clone) { @@ -835,110 +727,208 @@ drop_and_build_snippet: function () { }, - select: function (np) { - var self = this; - // add or remove html class - if (np.$prev && this.required) { - this.$target.removeClass(np.$prev.data('value' || "")); + reset: function (event) { + var self = this, $el, method; + for (var k in self.reset_methods) { + method = self.reset_methods[k]; + var $li = self.$el.find('[data-'+method+']').add(self.$el).filter('.active, :has(.active)'); + if ($li.size()) { + $li.each(function () { + self.select("reset", $(this)); + }); + } else { + self[method]("reset", null, null); + } + } + self.reset_methods = []; + self.$target.trigger("snippet-option-reset", [this]); + }, + + // call data-method args as method + select: function (type, $li) { + var self = this, + $methods = [], + el = $li[0], + $el; + clearTimeout(this.reset_time); + + function filter (k) { return k !== 'oeId' && k !== 'oeModel' && k !== 'oeField' && k !== 'oeXpath' && k !== 'oeSourceId';} + function hasData(el) { + for (var k in el.dataset) { + if (filter (k)) { + return true; + } + } + return false; } - if (np.$next) { - this.$target.addClass(np.$next.data('value') || ""); + function method(el) { + var data = {}; + for (var k in el.dataset) { + if (filter (k)) { + data[k] = el.dataset[k]; + } + } + return data; } + + while (el && this.$el.is(el) || _.some(this.$el.map(function () {return $.contains(this, el);}).get()) ) { + if (hasData(el)) { + $methods.push(el); + } + el = el.parentNode; + } + + $methods.reverse(); + + _.each($methods, function (el) { + var $el = $(el); + var methods = method(el); + for (var k in methods) { + if (self[k]) { + if (self.reset_methods.indexOf(k) === -1) { + self.reset_methods.push(k); + } + self[k](type, methods[k], $el); + } else { + console.error("'"+self.option+"' snippet have not method '"+k+"'"); + } + } + }); }, - preview: function (np) { - var self = this; + // default method for snippet + check_class: function (type, value, $li) { + var $lis = this.$el.find('[data-check_class]').add(this.$el).filter('[data-check_class]'); - // add or remove html class - if (np.$prev) { - this.$target.removeClass(np.$prev.data('value') || ""); + function map ($lis) { + return $lis.map(function () {return $(this).data("check_class");}).get().join(" "); } - if (np.$next) { - this.$target.addClass(np.$next.data('value') || ""); + var classes = map($lis); + var active_classes = map($lis.filter('.active, :has(.active)')); + + this.$target.removeClass(classes); + this.$target.addClass(active_classes); + + if (type !== 'reset') { + this.$target.toggleClass(value); } }, + select_class: function (type, value, $li) { + var $lis = this.$el.find('[data-select_class]').add(this.$el).filter('[data-select_class]'); + + var classes = $lis.map(function () {return $(this).data('select_class');}).get(); + + this.$target.removeClass(classes.join(" ")); + if(value) this.$target.addClass(value); + }, clean_for_save: dummy }); - website.snippet.options.background = website.snippet.Option.extend({ - _get_bg: function () { - return this.$target.css("background-image").replace(/url\(['"]*|['"]*\)|^none$/g, ""); - }, - _set_bg: function (src) { - this.$target.css("background-image", src && src !== "" ? 'url(' + src + ')' : ""); - }, start: function () { this._super(); - var src = this._get_bg(); - this.$el.find("li[data-value].active.oe_custom_bg").data("src", src); + var src = this.$target.css("background-image").replace(/url\(['"]*|['"]*\)|^none$/g, ""); + if (this.$target.hasClass('oe_custom_bg')) { + this.$el.find('li[data-choose_image]').data("background", src).attr("data-background", src); + } }, - select: function(np) { - var self = this; - this._super(np); - if (np.$next) { - if (np.$next.hasClass("oe_custom_bg")) { - var $image = $('<img class="hidden"/>'); - $image.attr("src", np.$prev ? np.$prev.data("src") : ''); - $image.appendTo(self.$target); - - self.element = new CKEDITOR.dom.element($image[0]); - var editor = new website.editor.MediaDialog(self, self.element); - editor.appendTo(document.body); - editor.$('[href="#editor-media-video"], [href="#editor-media-icon"]').addClass('hidden'); - - $image.on('saved', self, function (o) { - var src = $image.attr("src"); - self._set_bg(src); - np.$next.data("src", src); - self.$target.trigger("snippet-style-change", [self, np]); - $image.remove(); - }); - editor.on('cancel', self, function () { - if (!np.$prev || np.$prev.data("src") === "") { - self.$target.removeClass(np.$next.data("value")); - self.$target.trigger("snippet-style-change", [self, np]); - } - $image.remove(); - }); - } else { - this._set_bg(np.$next.data("src")); - } + background: function(type, value, $li) { + if (value && value.length) { + this.$target.css("background-image", 'url(' + value + ')'); } else { - this._set_bg(false); - this.$target.removeClass(np.$prev.data("value")); + this.$target.css("background-image", "").removeClass("oe_img_bg"); } }, - preview: function (np) { - this._super(np); - if (np.$next) { - this._set_bg(np.$next.data("src")); - } + choose_image: function(type, value, $li) { + if(type !== "click") return; + + var self = this; + var $image = $('<img class="hidden"/>'); + $image.attr("src", value); + $image.appendTo(self.$target); + + self.element = new CKEDITOR.dom.element($image[0]); + var editor = new website.editor.MediaDialog(self, self.element); + editor.appendTo(document.body); + editor.$('[href="#editor-media-video"], [href="#editor-media-icon"]').addClass('hidden'); + + $image.on('saved', self, function (o) { + var value = $image.attr("src"); + self.$target.css("background-image", 'url(' + value + ')'); + self.$el.find('li[data-select_class="oe_custom_bg"]').data("src", value); + self.$target.trigger("snippet-option-change", [self]); + $image.remove(); + self.$target.addClass('oe_custom_bg').removeClass('oe_img_bg'); + self.set_active(); + }); + editor.on('cancel', self, function () { + self.$target.removeClass("oe_img_bg") + .trigger("snippet-option-change", [self]); + $image.remove(); + }); }, set_active: function () { var self = this; - var bg = self.$target.css("background-image"); - this.$el.find('li').removeClass("active"); - this.$el.find('li').removeClass("btn-primary"); - var $active = this.$el.find('li[data-value]') - .filter(function () { - var $li = $(this); - return ($li.data('src') && bg.indexOf($li.data('src')) >= 0) || - (!$li.data('src') && self.$target.hasClass($li.data('value'))); - }) - .first(); - if (!$active.length) { - $active = this.$target.css("background-image") !== 'none' ? - this.$el.find('li[data-value].oe_custom_bg') : - this.$el.find('li[data-value=""]'); + var src = this.$target.css("background-image").replace(/url\(['"]*|['"]*\)|^none$/g, ""); + this._super(); + + this.$el.find('li[data-background]') + .filter(':not([data-background=""])') + .removeClass("active") + .each(function () { + var background = $(this).data("background"); + if ((src.length && background.length && src.indexOf(background) !== -1) || (!src.length && !background.length)) { + $(this).addClass("active"); + } + }); + if(!this.$el.find('li.active').size()) { + this.$el.find('li[data-select_class=""][data-background=""], '+ + 'li[data-select_class=""] li[data-background=""], '+ + 'li[data-background=""] li[data-select_class=""]').addClass("active"); + this.$el.filter('li[data-select_class=""]').find('li[data-background=""]').addClass("active"); + this.$el.filter('li[data-background=""]').find('li[data-select_class=""]').addClass("active"); } + } + }); - //don't set active on an OpenDialog link, else it not possible to click on it again after. - // TODO in Saas-4 - Once bootstrap is in less - // - add a class active-style to get the same display but without the active behaviour used by bootstrap in JS. - var classStr = _.string.contains($active[0].className, "oe_custom_bg") ? "btn-primary" : "active"; - $active.addClass(classStr); - this.$el.find('li:has(li[data-value].active)').addClass(classStr); + 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"); + }); } }); @@ -975,10 +965,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; @@ -987,14 +977,12 @@ this.id = this.$target.attr("id"); this.$inner = this.$target.find('.carousel-inner'); this.$indicators = this.$target.find('.carousel-indicators'); - - this.$el.find(".js_add").on('click', function () {self.on_add_slide(); return false;}); - this.$el.find(".js_remove").on('click', function () {self.on_remove_slide(); return false;}); - this.$target.carousel('pause'); this.rebind_event(); }, - on_add_slide: function () { + add_slide: function (type, value) { + if(type !== "click") return; + var self = this; var cycle = this.$inner.find('.item').length; var $active = this.$inner.find('.item.active, .item.prev, .item.next').first(); @@ -1012,7 +1000,9 @@ },0); return $clone; }, - on_remove_slide: function () { + remove_slide: function (type, value) { + if(type !== "click") return; + if (this.remove_process) { return; } @@ -1041,6 +1031,13 @@ this.$target.find('.carousel-control, .carousel-indicators').addClass("hidden"); } }, + interval : function(type, value) { + this.$target.attr("data-interval", value); + }, + set_active: function () { + this.$el.find('li[data-interval]').removeClass("active") + .filter('li[data-interval='+this.$target.attr("data-interval")+']').addClass("active"); + }, }); website.snippet.options.carousel = website.snippet.options.slider.extend({ getSize: function () { @@ -1050,12 +1047,11 @@ }, clean_for_save: function () { this._super(); - this.$target.css("background-image", ""); - this.$target.removeClass(this._class); + this.$target.removeClass('oe_img_bg ' + this._class).css("background-image", ""); }, load_style_options : function () { this._super(); - $(".snippet-style-size li[data-value='']").remove(); + $(".snippet-option-size li[data-value='']").remove(); }, start : function () { var self = this; @@ -1066,46 +1062,30 @@ if (c) self._class = (self._class || "").replace(new RegExp("[ ]+" + c.replace(" ", "|[ ]+")), '') + ' ' + c; return self._class || ""; }; - this.$target.on('snippet-style-change snippet-style-preview', function (event, style, np) { - var $active = self.$target.find(".item.active"); - if (style['snippet-option-id'] === "size") return; - if (style['snippet-option-id'] === "background") { - $active.css("background-image", self.$target.css("background-image")); + this.$target.on('slid.bs.carousel', function () { + if(self.editor && self.editor.styles.background) { + self.editor.styles.background.$target = self.$target.find(".item.active"); + self.editor.styles.background.set_active(); } - if (np.$prev) { - $active.removeClass(np.$prev.data("value")); - } - if (np.$next) { - $active.addClass(np.$next.data("value")); - add_class(np.$next.data("value")); - } - }); - this.$target.on('slid', function () { // slide.bs.carousel - var $active = self.$target.find(".item.active"); - self.$target - .css("background-image", $active.css("background-image")) - .removeClass(add_class($active.attr("class"))) - .addClass($active.attr("class")) - .trigger("snippet-style-reset"); - self.$target.carousel("pause"); }); - this.$target.trigger('slid'); + this.$target.trigger('slid.bs.carousel'); }, - on_add_slide: function () { - var $clone = this._super(); + add_slide: function (type, data) { + if(type !== "click") return; + var $clone = this._super(type, data); // choose an other background var bg = this.$target.data("snippet-option-ids").background; if (!bg) return $clone; - var $styles = bg.$el.find("li[data-value]:not(.oe_custom_bg)"); - var styles_index = $styles.index($styles.filter(".active")[0]); - $styles.removeClass("active"); - var $select = $($styles[styles_index >= $styles.length-1 ? 0 : styles_index+1]); + var $styles = bg.$el.find("li[data-background]"); + var $select = $styles.filter(".active").removeClass("active").next("li[data-background]"); + if (!$select.length) { + $select = $styles.first(); + } $select.addClass("active"); - $clone.css("background-image", $select.data("src") ? "url('"+ $select.data("src") +"')" : ""); - $clone.addClass($select.data("value") || ""); + $clone.css("background-image", $select.data("background") ? "url('"+ $select.data("background") +"')" : ""); return $clone; }, @@ -1120,7 +1100,6 @@ this._super(); }, }); - website.snippet.options.marginAndResize = website.snippet.Option.extend({ start: function () { var self = this; @@ -1248,7 +1227,7 @@ return this.grid; }, - onFocus : function () { + on_focus : function () { this._super(); this.change_cursor(); }, @@ -1348,7 +1327,7 @@ hide_remove_button: function() { this.$overlay.find('.oe_snippet_remove').toggleClass("hidden", !this.$target.siblings().length); }, - onFocus : function () { + on_focus : function () { this._super(); this.hide_remove_button(); }, @@ -1359,20 +1338,8 @@ return false; }, on_remove: function () { - if (!this.$target.siblings().length) { - var $parent = this.$target.parents(".row:first"); - if($parent.find("[class*='col-md']").length > 1) { - return false; - } else { - if (!$parent.data("snippet-editor")) { - this.BuildingBlock.create_overlay($parent); - } - $parent.data("snippet-editor").on_remove(); - } - } this._super(); this.hide_remove_button(); - return false; }, on_resize: function (compass, beginClass, current) { if (compass === 'w') { @@ -1399,7 +1366,7 @@ }, }); - website.snippet.options["resize"] = website.snippet.options.marginAndResize.extend({ + website.snippet.options.resize = website.snippet.options.marginAndResize.extend({ getSize: function () { this.grid = this._super(); this.grid.size = 8; @@ -1423,7 +1390,7 @@ this.$target.data("snippet-view", new website.snippet.animationRegistry.parallax(this.$target)); } this.scroll(); - this.$target.on('snippet-style-change snippet-style-preview', function () { + this.$target.on('snippet-option-change snippet-option-preview', function () { self.$target.data("snippet-view").set_values(); }); this.$target.attr('contentEditable', 'false'); @@ -1432,22 +1399,15 @@ this.$target.find('> div > div:not(.oe_structure) > .oe_structure').attr('contentEditable', 'true'); }, - scroll: function () { - var self = this; - var $ul = this.$el.find('ul[name="parallax-scroll"]'); - var $li = $ul.find("li"); - var speed = this.$target.data('scroll-background-ratio') || 0.6 ; - $ul.find('[data-value="' + speed + '"]').addClass('active'); - $li.on('click', function (event) { - $li.removeClass("active"); - $(this).addClass("active"); - var speed = $(this).data('value'); - self.$target.attr('data-scroll-background-ratio', speed); - self.$target.data("snippet-view").set_values(); - return false; - }); + scroll: function (type, value) { + this.$target.attr('data-scroll-background-ratio', value); this.$target.data("snippet-view").set_values(); }, + set_active: function () { + var value = this.$target.attr('data-scroll-background-ratio') || 0; + this.$el.find('[data-scroll]').removeClass("active") + .filter('[data-scroll="' + (this.$target.attr('data-scroll-background-ratio') || 0) + '"]').addClass("active"); + }, clean_for_save: function () { this._super(); this.$target.find(".parallax") @@ -1460,24 +1420,22 @@ start: function () { var self = this; this._super(); - - this.$el.find(".clear-style").click(function (event) { - self.$target.removeClass("fa-spin").attr("style", ""); - self.resetTransfo(); - }); - - this.$el.find(".style").click(function (event) { - var settings = self.$target.data("transfo").settings; - self.$target.transfo({ hide: (settings.hide = !settings.hide) }); - }); - this.$overlay.find('.oe_snippet_clone, .oe_handles').addClass('hidden'); - this.$overlay.find('[data-toggle="dropdown"]') .on("mousedown", function () { self.$target.transfo("hide"); }); }, + style: function (type, value) { + if (type !== 'click') return; + var settings = this.$target.data("transfo").settings; + this.$target.transfo({ hide: (settings.hide = !settings.hide) }); + }, + clear_style: function (type, value) { + if (type !== 'click') return; + this.$target.removeClass("fa-spin").attr("style", ""); + this.resetTransfo(); + }, resetTransfo: function () { var self = this; this.$target.transfo("destroy"); @@ -1499,10 +1457,10 @@ }) .mouseover(); }, - onFocus : function () { + on_focus : function () { this.resetTransfo(); }, - onBlur : function () { + on_blur : function () { this.$target.transfo("hide"); }, }); @@ -1515,21 +1473,19 @@ website.snippet.start_animation(true, this.$target); $(document.body).on("media-saved", self, function (event, prev , item) { - self.editor.onBlur(); + self.editor.on_blur(); self.BuildingBlock.make_active(false); if (self.$target.parent().data("oe-field") !== "image") { self.BuildingBlock.make_active($(item)); } }); - - this.$el.find(".edition").click(function (event) { - event.preventDefault(); - event.stopPropagation(); - self.element = new CKEDITOR.dom.element(self.$target[0]); - new website.editor.MediaDialog(self, self.element).appendTo(document.body); - }); }, - onFocus : function () { + edition: function (type, value) { + if(type !== "click") return; + this.element = new CKEDITOR.dom.element(this.$target[0]); + new website.editor.MediaDialog(this, this.element).appendTo(document.body); + }, + on_focus : function () { var self = this; if (this.$target.parent().data("oe-field") === "image") { this.$overlay.addClass("hidden"); @@ -1540,39 +1496,16 @@ }, }); - website.snippet.Editor = openerp.Class.extend({ init: function (BuildingBlock, dom) { this.BuildingBlock = BuildingBlock; this.$target = $(dom); this.$overlay = this.$target.data('overlay'); - this.snippet_id = this.$target.data("snippet-id"); - this._readXMLData(); this.load_style_options(); this.get_parent_block(); this.start(); }, - /* - * _readXMLData - * Read data XML and set value into: - * this.$el : - * all xml data - * this.$overlay : - * Dom hover the $target who content options - */ - _readXMLData: function() { - var self = this; - if(this && this.BuildingBlock && this.BuildingBlock.$snippets) { - this.$el = this.BuildingBlock.$snippets.filter(function () { return $(this).data("snippet-id") == self.snippet_id; }).clone(); - } - var $options = this.$overlay.find(".oe_overlay_options"); - if ($options.find(".oe_options ul li").length) { - $options.find(".oe_options").removeClass("hidden"); - } - }, - - // activate drag and drop for the snippets in the snippet toolbar _drag_and_drop: function(){ var self = this; @@ -1658,18 +1591,18 @@ this.selector_siblings = []; this.selector_children = []; this.selector_vertical_children = []; - _.each(website.snippet.templateOptions, function (val) { + _.each(website.snippet.templateOptions, function (val, option_id) { if (!self.$target.is(val.selector)) { return; } - if (val['selector-siblings']) self.selector_siblings.push(val['selector-siblings']); - if (val['selector-children']) self.selector_children.push(val['selector-children']); - if (val['selector-vertical-children']) self.selector_vertical_children.push(val['selector-vertical-children']); - - var style = val['snippet-option-id']; - var Editor = website.snippet.options[style] || website.snippet.Option; - var editor = self.styles[style] = new Editor(self.BuildingBlock, self, self.$target, style); - $ul.append(editor.$el.addClass("snippet-style-" + style)); + if (val['drop-near']) self.selector_siblings.push(val['drop-near']); + if (val['drop-in']) self.selector_children.push(val['drop-in']); + if (val['drop-in-vertical']) self.selector_vertical_children.push(val['drop-in-vertical']); + + var option = val['option']; + var Editor = website.snippet.options[option] || website.snippet.Option; + var editor = self.styles[option] = new Editor(self.BuildingBlock, self, self.$target, option_id); + $ul.append(editor.$el.addClass("snippet-option-" + option)); }); this.selector_siblings = this.selector_siblings.join(","); if (this.selector_siblings === "") @@ -1682,7 +1615,7 @@ this.selector_vertical_children = false; if (!this.selector_siblings && !this.selector_children && !this.selector_vertical_children) { - this.$overlay.find(".oe_snippet_move").addClass('hidden'); + this.$overlay.find(".oe_snippet_move, .oe_snippet_clone, .oe_snippet_remove").addClass('hidden'); } @@ -1730,13 +1663,35 @@ }, on_remove: function () { - this.onBlur(); + this.on_blur(); var index = _.indexOf(this.BuildingBlock.snippets, this.$target.get(0)); for (var i in this.styles){ this.styles[i].on_remove(); } delete this.BuildingBlock.snippets[index]; + + // remove node and his empty + var parent, + node = this.$target.parent()[0]; + this.$target.remove(); + function check(node) { + if ($(node).outerHeight() > 8) { + return false; + } + for (var k=0; k<node.children.length; k++) { + if (node.children[k].tagName || node.children[k].textContent.match(/[^\s]/)) { + return false; + } + } + return true; + } + while (check(node)) { + parent = node.parentNode; + parent.removeChild(node); + node = parent; + } + this.$overlay.remove(); return false; }, @@ -1752,22 +1707,22 @@ } }, - /* onFocus + /* on_focus * This method is called when the user click inside the snippet in the dom */ - onFocus : function () { + on_focus : function () { this.$overlay.addClass('oe_active'); for (var i in this.styles){ - this.styles[i].onFocus(); + this.styles[i].on_focus(); } }, - /* onFocus + /* on_focus * This method is called when the user click outside the snippet in the dom, after a focus */ - onBlur : function () { + on_blur : function () { for (var i in this.styles){ - this.styles[i].onBlur(); + this.styles[i].on_blur(); } this.$overlay.removeClass('oe_active'); }, diff --git a/addons/website/static/src/js/website.snippets.gallery.js b/addons/website/static/src/js/website.snippets.gallery.js new file mode 100644 index 00000000000..ed700bdd371 --- /dev/null +++ b/addons/website/static/src/js/website.snippets.gallery.js @@ -0,0 +1,348 @@ +(function() { + 'use strict'; + + var website = openerp.website, + _t = openerp._t; + + /*-------------------------------------------------------------------------- + Template files to load + --------------------------------------------------------------------------*/ + website.add_template_file('/website/static/src/xml/website.gallery.xml'); + + /*-------------------------------------------------------------------------- + Gallery Snippet + + This is the snippet responsible for configuring the image galleries. + Look at /website/views/snippets.xml for the available options + ------------------------------------------------------------------------*/ + website.snippet.options.gallery = website.snippet.Option.extend({ + start : function() { + this._super(); + this.bind_change(); + }, + 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) { + this.$target.find('.carousel:first').attr("data-interval", value); + }, + reapply : function() { + var self = this, + modes = [ 'o_nomode', 'o_grid', 'o_masonry', 'o_slideshow' ], + classes = this.$target.attr("class").split(/\s+/); + if (this.block) return; + modes.forEach(function(mode) { + if (classes.indexOf(mode) != -1) { + self.mode("reapply", mode); + return; + } + }); + }, + bind_change: function () { + var self = this; + return this.$target.find("img").off('saved').on('saved', function (event, img) { + var $parent = $(img).parent(); + $parent.addClass("saved_active"); + var index = self.$target.find(".item.saved_active").index(); + $parent.removeClass("saved_active"); + self.$target.find(".carousel:first li[data-target]:eq("+index+")").css("background-image", "url("+$(img).attr("src")+")"); + }); + }, + get_imgs: function () { + return this.$target.find("img").addClass("img img-thumbnail img-responsive mb8 mt8").detach(); + }, + mode: function (type, value) { + if (this.block) return; + if (!value) value = 'nomode'; + this[value](); + this.$target.removeClass('o_nomode o_masonry o_grid o_slideshow').addClass("o_"+value); + this.bind_change(); + }, + replace: function ($content) { + var $container = this.$target.find(".container:first"); + $container.empty().append($content); + return $container; + }, + nomode : function() { + var self = this, + $row = $('<div class="row"></div>'), + $imgs = this.get_imgs().wrap('<div>').parent(); + + this.replace($row); + + $imgs.each(function () { + var img = this.childNodes[0]; + if (img.width >= img.height * 2) { + $(this).addClass("col-md-6"); + } else if (img.width > 600) { + $(this).addClass("col-md-6"); + } else { + $(this).addClass("col-md-3"); + } + }); + $row.append($imgs); + this.$target.css("height", ""); + }, + masonry : function() { + var self = this, + $imgs = this.get_imgs(), + columns = this.get_columns(), + colClass = undefined, + $cols = []; + + var $row = $("<div class='row'/>"); + this.replace($row); + + // if no columns let's default to 3, here we must update the DOM accordingly :'( + if (columns === 0) { + columns = 3; + this.$target.attr("data-columns", columns); + } + colClass = "col-md-"+(12/columns); + + // create columns + for (var c = 0; c < columns; c++) { + var $col = $('<div class="col"></div>').addClass(colClass); + $row.append($col); + $cols.push($col.get()[0]); + } + + this.block = true; + $cols = $($cols); + var imgs = $imgs.get(); + function add() { + self.lowest($cols).append(imgs.pop()); + if (imgs.length) setTimeout(add, 0); + else self.block = false; + } + if (imgs.length) add(); + this.$target.css("height", ""); + }, + grid : function() { + var self = this, + $cols = this.get_imgs().wrap('<div>').parent(), + $col, $img, + $row = $('<div class="row"></div>'), + columns = this.get_columns() || 3, + colClass = "col-md-"+(12/columns), + $container = this.replace($row); + + $cols.each(function(index) { // 0 based index + $col = $(this); + $img = $col.find('img'); + self.img_preserve_styles($img); + self.img_responsive($img); + $col.addClass(colClass); + $col.appendTo($row); + if ( (index+1) % columns === 0) { + $row = $('<div class="row"></div>'); + $row.appendTo($container); + } + }); + this.$target.css("height", ""); + }, + slideshow :function () { + var self = this; + var $imgs = this.$target.find("img").detach(), + urls = $imgs.map(function() { return $(this).attr("src"); } ).get(), + params = { + srcs : urls, + index: 1, + title: "", + interval : this.$target.data("interval") || false, + id: _.uniqueId("slideshow_") + }, + $slideshow = $(openerp.qweb.render('website.gallery.slideshow', params)); + this.replace($slideshow); + this.$target.css("height", Math.round(window.innerHeight*0.7)); + }, + columns : function(type, value) { + if (this.block) return; + this.$target.attr("data-columns", value); + this.reapply(); + }, + albumimages : function(type, value) { + if(type === "click") this[value](); + }, + images_add : function() { + /* will be moved in ImageDialog from MediaManager */ + var self = this, + $container = this.$target.find(".container:first"), + $upload_form = $(openerp.qweb.render('website.gallery.dialog.upload')), + $progress = $upload_form.find(".fa"); + + $upload_form.appendTo(document.body); + + $upload_form.on('modal.bs.hide', function() { $(this).remove(); } ); + + $upload_form.find(".alert-success").hide(); + $upload_form.find(".alert-danger").hide(); + + $upload_form.on("change", 'input[name="upload"]', function(event) { + $upload_form.find('input[type="submit"]').parent().removeClass("hidden"); + $upload_form.find(".alert").hide(); + }); + + $upload_form.find("form").on("submit", function(event) { + event.preventDefault(); + var files = $(this).find('input[type="file"]')[0].files; + var formData = new FormData(); + for (var i = 0; i < files.length; i++ ) { + var file = files[i]; + formData.append('upload', file, file.name); + } + + /* + * hide submit button + */ + $('input[name="upload"], input[type="submit"]', this).parent().addClass("hidden"); + + /* + * show progress + */ + $progress.removeClass("hidden"); + + /* + * Images upload callback + */ + var callback = _.uniqueId('func_'); + formData.append("func", callback); + window[callback] = function (attachments, error) { + delete window[callback]; + + $('input[name="upload"]', this).parent().removeClass("hidden"); + + if (error) { /* failure */ + + $upload_form.find(".alert-danger").show(); + + } else { /* success */ + + $upload_form.find(".alert-success").show(); + for (var i = 0 ; i < attachments.length; i++) { + $('<img class="img img-thumbnail img-responsive mb8 mt8"/>') + .attr("src", attachments[i].website_url) + .appendTo($container); + } + $progress.addClass("hidden"); + $upload_form.remove(); + self.reapply(); // refresh the $target + } + }; + + /* + * Images upload : don't change order of contentType & processData + * and don't change their values, otherwise the XHR will be + * wrongly conceived by jQuery. + * + * (missing boundary in the content-type header field) + * Leading to an upload failure. + */ + $.ajax('/website/attach', { + type: 'POST', + data: formData, + contentType: false, /* multipart/form-data for files */ + processData: false, + dataType: 'text' + }).done(function (script) { + $(script).appendTo('head').remove(); + }); + }); + $upload_form.modal({ backdrop : false }); + + $upload_form.find('input[name="upload"]').click(); + }, + images_rm : function() { + this.replace($('<div class="alert alert-info css_editable_mode_display" style="display: none;"/>').text(_t("Add Images from the 'Customize' menu"))); + }, + sizing : function() { // done via css, keep it to avoid undefined error + }, + /* + * helpers + */ + styles_to_preserve : function($img) { + var styles = [ 'img-rounded', 'img-thumbnail', 'img-circle', 'shadow', 'fa-spin' ]; + var preserved = []; + + for (var style in styles) { + if ($img.hasClass(style)) { + preserved.push(style); + } + } + return preserved.join(' '); + }, + img_preserve_styles : function($img) { + var classes = this.styles_to_preserve($img); + $img.removeAttr("class"); + $img.addClass(classes); + return $img; + }, + img_from_src : function(src) { + var self = this; + var $img = $("<img/>").attr("src", src); + return $img; + }, + img_responsive : function(img) { + img.addClass("img img-responsive"); + return img; + }, + lowest : function($cols) { + var height = 0, min = -1, col=0, lowest = undefined; + $cols.each(function () { + var $col = $(this); + height = $col.height(); + if (min === -1 || height < min) { + min = height; + lowest = $col; + } + }); + return lowest; + }, + get_columns : function() { + return parseInt(this.$target.attr("data-columns") || 3); + }, + + clean_for_save: function() { + var self = this; + if (this.$target.hasClass("slideshow")) { + this.$target.removeAttr("style"); + } + }, + + set_active: function () { + this._super(); + var classes = _.uniq((this.$target.attr("class").replace(/(^|\s)o_/g, ' ') || '').split(/\s+/)); + var $li = this.$el.find('[data-mode]') + .removeClass("active") + .filter('[data-mode="' + classes.join('"], [data-mode="') + '"]').addClass("active"); + var mode = this.$el.find('[data-mode].active').data('mode'); + + var classes = _.uniq((this.$target.find("img:first").attr("class") || '').split(/\s+/)); + var $li = this.$el.find('[data-styling]') + .removeClass("active") + .filter('[data-styling="' + classes.join('"], [data-styling="') + '"]').addClass("active"); + + this.$el.find('li[data-interval]').removeClass("active") + .filter('li[data-interval='+this.$target.find(".carousel:first").attr("data-interval")+']') + .addClass("active"); + + var interval = this.$target.find('.carousel:first').attr("data-interval"); + var $li = this.$el.find('[data-interval]') + .removeClass("active") + .filter('[data-interval=' + interval + ']').addClass("active"); + + var columns = this.get_columns(); + var $li = this.$el.find('[data-columns]') + .removeClass("active") + .filter('[data-columns=' + columns + ']').addClass("active"); + + this.$el.find('[data-columns]:first, [data-select_class="spc-none"]') + .parent().parent().toggle(["grid", "masonry"].indexOf(mode) !== -1); + this.$el.find('[data-interval]:first').parent().parent().toggle(mode === "slideshow"); + }, + }); // website.snippet.Option.extend + +})(); // anonymous function 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..26bce16c0b6 --- /dev/null +++ b/addons/website/static/src/js/website.theme.js @@ -0,0 +1,277 @@ +(function () { + 'use strict'; + + openerp.jsonRpc('/web/dataset/call', 'call', { + 'model': 'ir.ui.view', + 'method': 'read_template', + 'args': ['website.theme_customize', openerp.website.get_context()] + }).done(function (data) { + openerp.qweb.add_template(data); + }); + openerp.jsonRpc('/web/dataset/call', 'call', { + 'model': 'ir.ui.view', + 'method': 'read_template', + 'args': ['website.colorpicker', openerp.website.get_context()] + }).done(function (data) { + openerp.qweb.add_template(data); + }); + + 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 Theme = openerp.website.Theme; + if (Theme.open && !Theme.open.isDestroyed()) return; + Theme.open = new Theme(); + Theme.open.appendTo("body"); + + var error = window.getComputedStyle(document.body, ':before').getPropertyValue('content'); + if (error && error !== 'none') { + themeError(eval(error)); + } + } + $(document).on('click', "#theme_customize a",theme_customize); + if ((window.location.hash || "").indexOf("theme=true") !== -1) { + theme_customize(); + window.location.hash = ""; + } + }); + +})(); |
