diff --git a/addons/website/models/ir_ui_view.py b/addons/website/models/ir_ui_view.py index 955ca4f758b..c85245bb188 100644 --- a/addons/website/models/ir_ui_view.py +++ b/addons/website/models/ir_ui_view.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- - -from lxml import etree, html -from openerp.osv import osv, fields from urlparse import urlparse +from lxml import etree, html + +from openerp.osv import osv, fields +from openerp.addons.base import ir class view(osv.osv): _inherit = "ir.ui.view" @@ -83,13 +84,20 @@ class view(osv.osv): return out def replace_arch_section(self, cr, uid, view_id, section_xpath, replacement, context=None): - arch = replacement - if section_xpath: - previous_arch = etree.fromstring(self.browse(cr, uid, view_id, context=context).arch.encode('utf-8')) + # remove branding from replacement section + for att in ir.ir_ui_view.MOVABLE_BRANDING: + replacement.attrib.pop(att, None) + + if not section_xpath: + # replace all of the arch, not just a fragment + arch = replacement + else: + arch = etree.fromstring(self.browse(cr, uid, view_id, context=context).arch.encode('utf-8')) # ensure there's only one match - [previous_section] = previous_arch.xpath(section_xpath) + [previous_section] = arch.xpath(section_xpath) + previous_section.getparent().replace(previous_section, replacement) - arch = previous_arch + return arch def _normalize_urls(self, element): @@ -98,7 +106,7 @@ class view(osv.osv): attr = 'action' if 'action' in element.attrib else None elif element.tag in ['a', 'link']: attr = 'href' if 'href' in element.attrib else None - elif element.tag in ['frame', 'iframe', 'img', 'input', 'script']: + elif element.tag in ['frame', 'iframe', 'script']: attr = 'src' if 'src' in element.attrib else None if attr: value = element.attrib[attr] diff --git a/addons/website/models/website.py b/addons/website/models/website.py index c79ada6e9e4..b6379bcbb79 100644 --- a/addons/website/models/website.py +++ b/addons/website/models/website.py @@ -386,6 +386,17 @@ class base_language_install(osv.osv): 'website_ids': fields.many2many('website', string='Websites to translate'), } + def default_get(self, cr, uid, fields, context=None): + if context is None: + context = {} + defaults = super(base_language_install, self).default_get(cr, uid, fields, context) + website_id = context.get('params', {}).get('website_id') + if website_id: + if 'website_ids' not in defaults: + defaults['website_ids'] = [] + defaults['website_ids'].append(website_id) + return defaults + def lang_install(self, cr, uid, ids, context=None): if context is None: context = {} diff --git a/addons/website/static/lib/ckeditor/core/dom/range.js b/addons/website/static/lib/ckeditor/core/dom/range.js index d567a50ad43..9a330fc8a70 100644 --- a/addons/website/static/lib/ckeditor/core/dom/range.js +++ b/addons/website/static/lib/ckeditor/core/dom/range.js @@ -1360,7 +1360,7 @@ CKEDITOR.dom.range = function( root ) { * * {@link CKEDITOR#SHRINK_TEXT} - Shrink the range boudaries to anchor by the side of enclosed text * node, range remains if there's no text nodes on boundaries at all. * - * @param {Boolean} selectContents Whether result range anchors at the inner OR outer boundary of the node. + * @param {Boolean} [selectContents] Whether result range anchors at the inner OR outer boundary of the node. */ shrink: function( mode, selectContents, shrinkOnBlockBoundary ) { // Unable to shrink a collapsed range. diff --git a/addons/website/static/lib/ckeditor/core/selection.js b/addons/website/static/lib/ckeditor/core/selection.js index e888c3d557c..f3e47c9debb 100644 --- a/addons/website/static/lib/ckeditor/core/selection.js +++ b/addons/website/static/lib/ckeditor/core/selection.js @@ -798,7 +798,7 @@ * * @method * @member CKEDITOR.editor - * @param {Boolean} forceRealSelection Return real selection, instead of saved or fake one. + * @param {Boolean} [forceRealSelection] Return real selection, instead of saved or fake one. * @returns {CKEDITOR.dom.selection} A selection object or null if not available for the moment. */ CKEDITOR.editor.prototype.getSelection = function( forceRealSelection ) { diff --git a/addons/website/static/src/css/editor.css b/addons/website/static/src/css/editor.css index a3151d14855..26032aaf7ce 100644 --- a/addons/website/static/src/css/editor.css +++ b/addons/website/static/src/css/editor.css @@ -112,6 +112,11 @@ table.editorbar-panel td.selected { background-color: #b1c9d9; } +.oe_translate_or { + color: white; + padding: 0 0.2em; +} + .oe_translate_examples li { margin: 10px; padding: 4px; diff --git a/addons/website/static/src/css/editor.sass b/addons/website/static/src/css/editor.sass index dcfa88b89e7..e4ef24dad70 100644 --- a/addons/website/static/src/css/editor.sass +++ b/addons/website/static/src/css/editor.sass @@ -106,6 +106,9 @@ table.editorbar-panel background-color: #b1c9d9 // ---- TRANSLATIONS ---- {{{ +.oe_translate_or + color: white + padding: 0 0.2em .oe_translate_examples li margin: 10px padding: 4px diff --git a/addons/website/static/src/js/website.editor.js b/addons/website/static/src/js/website.editor.js index c1f05d9b661..2249de2a24d 100644 --- a/addons/website/static/src/js/website.editor.js +++ b/addons/website/static/src/js/website.editor.js @@ -56,7 +56,7 @@ //noinspection JSValidateTypes editor.addCommand('link', { - exec: function (editor, data) { + exec: function (editor) { link_dialog(editor); return true; }, @@ -65,7 +65,7 @@ }); //noinspection JSValidateTypes editor.addCommand('image', { - exec: function (editor, data) { + exec: function (editor) { image_dialog(editor); return true; }, @@ -177,7 +177,7 @@ var editor = new website.EditorBar(); var $body = $(document.body); editor.prependTo($body).then(function () { - if (location.search.indexOf("unable_editor") >= 0) { + if (location.search.indexOf("enable_editor") >= 0) { editor.edit(); } }); @@ -219,7 +219,7 @@ var view_id = $(event.currentTarget).data('view-id'); openerp.jsonRpc('/website/customize_template_toggle', 'call', { 'view_id': view_id - }).then( function(result) { + }).then( function() { window.location.reload(); }); }); @@ -253,7 +253,6 @@ ); }, edit: function () { - var self = this; this.$buttons.edit.prop('disabled', true); this.$('#website-top-view').hide(); this.$('#website-top-edit').show(); @@ -350,6 +349,7 @@ // The detail attribute indicates the number of times a mouse button has been pressed // we just want the triple click if (e.detail !== 3) { return; } + e.preventDefault(); // Get closest block-level element to the triple-clicked // element (using ckeditor's block list because why not) @@ -422,7 +422,7 @@ return true; }, - start_edition: function ($elements) { + start_edition: function () { var self = this; // create a single editor for the whole page var root = document.getElementById('wrapwrap'); @@ -483,7 +483,7 @@ .filter(function () { var $this = $(this); // keep view sections and fields which are *not* in - // view sections for toplevel editables + // view sections for top-level editables return $this.data('oe-model') === 'ir.ui.view' || !$this.closest('[data-oe-model = "ir.ui.view"]').length; }); @@ -854,7 +854,7 @@ this.preview_image(); }, - file_selection: function (e) { + file_selection: function () { this.$('button.filepicker').removeClass('btn-danger btn-success'); var self = this; diff --git a/addons/website/static/src/js/website.js b/addons/website/static/src/js/website.js index 963a0b1664d..682a6175086 100644 --- a/addons/website/static/src/js/website.js +++ b/addons/website/static/src/js/website.js @@ -21,9 +21,6 @@ templates.push(template); }; website.load_templates = function(templates) { - var def = $.Deferred(); - var count = templates.length; - var dones = _(templates).map(function (t) { return new $.Deferred(function (d) { openerp.qweb.add_template(t, function(err) { @@ -39,8 +36,8 @@ }; website.reload = function () { location.hash = "scrollTop=" + window.document.body.scrollTop; - if (location.search.indexOf("unable_editor") > -1) { - window.location.href = window.location.href.replace(/unable_editor(=[^&]*)?/g, ''); + if (location.search.indexOf("enable_editor") > -1) { + window.location.href = window.location.href.replace(/enable_editor(=[^&]*)?/g, ''); } else { window.location.reload(); } @@ -151,7 +148,7 @@ }); }); - $(document).on('click', '.js_publish_management .js_publish_btn', function (e) { + $(document).on('click', '.js_publish_management .js_publish_btn', function () { var $data = $(this).parents(".js_publish_management:first"); var $btn = $data.find('.btn:first'); var publish = $btn.hasClass("btn-success"); diff --git a/addons/website/static/src/js/website.snippets.js b/addons/website/static/src/js/website.snippets.js index ee759e3d153..0b1ab4e13cd 100644 --- a/addons/website/static/src/js/website.snippets.js +++ b/addons/website/static/src/js/website.snippets.js @@ -196,7 +196,7 @@ } self.make_active($target); }); - $("[data-oe-model]").on('click', function (ev) { + $("[data-oe-model]").on('click', function () { if (!snipped_event_flag && self.$active_snipped_id && !self.$active_snipped_id.parents("[data-snippet-id]:first")) { self.make_active(false); } @@ -224,6 +224,7 @@ }, clean_for_save: function () { for (var k in this.snippets) { + if (!this.snippets.hasOwnProperty(k)) { continue; } var editor = $(this.snippets[k]).data("snippet-editor"); if (editor) { editor.clean_for_save(); @@ -342,9 +343,9 @@ }, stop: function(ev, ui){ if (action === 'insert' && ! dropped) { - var el = $('.oe_drop_zone').nearest({x: ui.position.left, y: ui.position.top}).first() - if (el) { - el.after($toInsert) + var $el = $('.oe_drop_zone').nearest({x: ui.position.left, y: ui.position.top}).first(); + if ($el) { + $el.after($toInsert); dropped = true; } } @@ -460,7 +461,7 @@ // count += $zones.length; // $zones.remove(); - $zones = $('.oe_drop_zone > .oe_drop_zone:not(.oe_vertical)').remove(); // no recusrive zones + $zones = $('.oe_drop_zone > .oe_drop_zone:not(.oe_vertical)').remove(); // no recursive zones count += $zones.length; $zones.remove(); } while (count > 0); @@ -471,14 +472,13 @@ var zone = $(this); var prev = zone.prev(); var next = zone.next(); - var float_prev = zone.prev().css('float') || 'none'; - var float_next = zone.next().css('float') || 'none'; - var disp_prev = zone.prev().css('display') || null; - var disp_next = zone.next().css('display') || null; + var float_prev = prev.css('float') || 'none'; + var float_next = next.css('float') || 'none'; + var disp_prev = prev.css('display') || null; + var disp_next = next.css('display') || null; if( (float_prev === 'left' || float_prev === 'right') && (float_next === 'left' || float_next === 'right') ){ zone.remove(); - return; }else if( !( disp_prev === null || disp_next === null || disp_prev === 'block' @@ -689,7 +689,7 @@ var self = this; var $styles = this.$overlay.find('.oe_options'); var $ul = $styles.find('ul:first'); - _.each(this.parent.style_templates, function (val, key) { + _.each(this.parent.style_templates, function (val) { if (!self.parent.dom_filter(val.selector).is(self.$target)) { return; } @@ -757,7 +757,7 @@ /* * build_snippet - * This method is called just after that a thumbnail is drag and droped into a drop zone + * This method is called just after that a thumbnail is drag and dropped into a drop zone * (after the insertion of this.$body, if this.$body exists) */ build_snippet: function ($target) { @@ -771,7 +771,7 @@ }, /* onFocus - * This method is called when the user click outide the snippet in the dom, after a focus + * This method is called when the user click outside the snippet in the dom, after a focus */ onBlur : function () { this.$overlay.removeClass('oe_active'); @@ -790,7 +790,7 @@ var $ul = this.$editor.find(ul_options); var bg_value = (typeof bg === 'string' ? this.$target.find(bg) : $(bg)).css("background-image").replace(/url\(['"]*|['"]*\)/g, ""); - // bind envent on options + // bind event on options var $li = $ul.find("li"); $li.on('click', function (event) { if ($(this).data("value")) { @@ -893,7 +893,8 @@ var regClass = new RegExp("\\s*" + resize[0][begin].replace(/[-]*[0-9]+/, '[-]*[0-9]+'), 'g'); var cursor = $handle.css("cursor")+'-important'; - $("body").addClass(cursor); + var $body = $(document.body); + $body.addClass(cursor); var body_mousemove = function (event){ event.preventDefault(); @@ -920,15 +921,15 @@ self.parent.cover_target(self.$overlay, self.$target); } }; - $('body').mousemove(body_mousemove); var body_mouseup = function(){ - $('body').unbind('mousemove', body_mousemove); - $('body').unbind('mouseup', body_mouseup); - $("body").removeClass(cursor); + $body.unbind('mousemove', body_mousemove); + $body.unbind('mouseup', body_mouseup); + $body.removeClass(cursor); self.parent.editor_busy = false; }; - $('body').mouseup(body_mouseup); + $body.mousemove(body_mousemove); + $body.mouseup(body_mouseup); }); }, getSize: function () { @@ -998,7 +999,7 @@ if (compass !== 'w') return; - // don't change the rigth border position when we change the offset (replace col size) + // don't change the right border position when we change the offset (replace col size) var beginCol = Number(beginClass.match(/col-md-([0-9]+)|$/)[1] || 0); var beginOffset = Number(beginClass.match(/col-md-offset-([0-9-]+)|$/)[1] || beginClass.match(/col-lg-offset-([0-9-]+)|$/)[1] || 0); var offset = Number(this.grid.w[0][current].match(/col-md-offset-([0-9-]+)|$/)[1] || 0); @@ -1128,7 +1129,6 @@ var style = false; var $el = this.$inner.find('.item.active'); var $ul = this.$editor.find('ul[name="carousel-style"]'); - var $li = $ul.find("li"); if ($el.hasClass('text_only')) style = 'text_only'; @@ -1160,7 +1160,6 @@ }); }, change_size: function () { - var self = this; var $el = this.$target; var size = 'oe_big'; @@ -1197,7 +1196,6 @@ this.change_size(); }, scroll: function(){ - var self = this; var $ul = this.$editor.find('ul[name="parallax-scroll"]'); var $li = $ul.find("li"); var $parallax = this.$target.find('.parallax'); @@ -1207,7 +1205,7 @@ $li.on('click', function (event) { $li.removeClass("active"); $(this).addClass("active"); - var speed = $(this).data('value') + var speed = $(this).data('value'); $parallax.attr('data-stellar-background-ratio', speed); }); diff --git a/addons/website/static/src/js/website.tour.basic.js b/addons/website/static/src/js/website.tour.basic.js index 82ad4790c25..876d2a7b5b9 100644 --- a/addons/website/static/src/js/website.tour.basic.js +++ b/addons/website/static/src/js/website.tour.basic.js @@ -10,6 +10,7 @@ name: "Insert a banner", init: function (editor) { var self = this; + var $body = $(document.body); self.steps = [ { stepId: 'welcome', @@ -56,15 +57,16 @@ onShow: function () { function beginDrag () { $('.popover.tour').remove(); - $('body').off('mousedown', beginDrag); function goToNextStep () { $('#oe_snippets').hide(); self.movetoStep('edit-title'); - $('body').off('mouseup', goToNextStep); + $body.off('mouseup', goToNextStep); } - $('body').on('mouseup', goToNextStep); + $body.off('mousedown', beginDrag); + $body.on('mouseup', goToNextStep); } - $('body').on('mousedown', beginDrag); + + $body.on('mousedown', beginDrag); }, }, { @@ -121,7 +123,7 @@ title: "Help is always available", content: "But you can always click here if you want more tutorials.", template: render('website.tour_popover', { end: "Close" }), - }, + } ]; return this._super(); }, @@ -158,4 +160,4 @@ }, }); -}()); \ No newline at end of file +}()); diff --git a/addons/website/static/src/js/website.translator.js b/addons/website/static/src/js/website.translator.js index fddb5ef7b51..7e237598530 100644 --- a/addons/website/static/src/js/website.translator.js +++ b/addons/website/static/src/js/website.translator.js @@ -6,11 +6,16 @@ var nodialog = 'website_translator_nodialog'; website.EditorBar.include({ + events: _.extend({}, website.EditorBar.prototype.events, { + 'click a[data-action=edit_master]': 'edit_master', + }), start: function () { var self = this; this.initial_content = {}; return this._super.apply(this, arguments).then(function () { - self.$('button[data-action=edit]').text("Translate"); + self.$('button[data-action=edit]') + .text("Translate") + .after(openerp.qweb.render('website.TranslatorAdditionalButtons')); self.$('[data-action=snippet]').hide(); self.$('#customize-menu-button').hide(); }); @@ -24,7 +29,7 @@ dialog.on('activate', this, function () { localStorage[nodialog] = dialog.$('input[name=do_not_show]').prop('checked') || ''; dialog.$el.modal('hide'); - this.translate().then(function () { + self.translate().then(function () { mysuper.call(self); }); }); @@ -34,6 +39,14 @@ }); } }, + edit_master: function (ev) { + ev.preventDefault(); + var link = $('.js_language_selector a[data-default-lang]')[0]; + if (link) { + link.search += (link.search ? '&' : '?') + 'enable_editor=1'; + window.location = link.attributes.href.value; + } + }, translate: function () { var self = this; this.translations = null; @@ -44,7 +57,7 @@ self.translations = translations; self.processTranslatableNodes(); // Disable non translatable t-fields - $('[data-oe-type][data-oe-translate=0]').removeAttr('data-oe-type'); + $('[data-oe-type][data-oe-translate="0"]').removeAttr('data-oe-type'); }); }, processTranslatableNodes: function () { @@ -143,7 +156,6 @@ if (node.attributes['data-oe-translate'].value == '1') { node.className += ' oe_translatable_field'; } - return; } else if (node.childNodes.length === 1 && this.isTextNode(node.childNodes[0]) && !node.getAttribute('data-oe-model')) { @@ -175,7 +187,7 @@ $(root).click(function (ev) { ev.preventDefault(); }); - return $('[data-oe-translate=1]'); + return $('[data-oe-translate="1"]'); } }); diff --git a/addons/website/static/src/xml/website.translator.xml b/addons/website/static/src/xml/website.translator.xml index f35cf583da9..dac074688d8 100644 --- a/addons/website/static/src/xml/website.translator.xml +++ b/addons/website/static/src/xml/website.translator.xml @@ -1,5 +1,9 @@ + + or + Edit Master +