diff --git a/addons/payment_acquirer_adyen/views/adyen.xml b/addons/payment_acquirer_adyen/views/adyen.xml index 55a5fd4b5b0..5fcd7c8eb80 100644 --- a/addons/payment_acquirer_adyen/views/adyen.xml +++ b/addons/payment_acquirer_adyen/views/adyen.xml @@ -23,7 +23,7 @@ diff --git a/addons/payment_acquirer_ogone/views/ogone.xml b/addons/payment_acquirer_ogone/views/ogone.xml index 6cb06507ff1..df26cce9528 100644 --- a/addons/payment_acquirer_ogone/views/ogone.xml +++ b/addons/payment_acquirer_ogone/views/ogone.xml @@ -44,7 +44,7 @@ diff --git a/addons/payment_acquirer_paypal/views/paypal.xml b/addons/payment_acquirer_paypal/views/paypal.xml index 186d45fc452..631d3832274 100644 --- a/addons/payment_acquirer_paypal/views/paypal.xml +++ b/addons/payment_acquirer_paypal/views/paypal.xml @@ -34,7 +34,7 @@ diff --git a/addons/payment_acquirer_transfer/views/transfer.xml b/addons/payment_acquirer_transfer/views/transfer.xml index 75912a30f42..f9829759340 100644 --- a/addons/payment_acquirer_transfer/views/transfer.xml +++ b/addons/payment_acquirer_transfer/views/transfer.xml @@ -14,7 +14,7 @@ diff --git a/addons/website/models/ir_qweb.py b/addons/website/models/ir_qweb.py index a5f4013a7df..18a5724fb02 100644 --- a/addons/website/models/ir_qweb.py +++ b/addons/website/models/ir_qweb.py @@ -404,11 +404,7 @@ class Contact(orm.AbstractModel): field_browse = self.pool[column._obj].browse(cr, openerp.SUPERUSER_ID, id, context={"show_address": True}) value = werkzeug.utils.escape( field_browse.name_get()[0][1] ) - IMD = self.pool["ir.model.data"] - model, id = IMD.get_object_reference(cr, uid, "website", "contact") - view = self.pool["ir.ui.view"].browse(cr, uid, id, context=context) - - html = view.render({ + val = { 'name': value.split("\n")[0], 'address': werkzeug.utils.escape("\n".join(value.split("\n")[1:])), 'phone': field_browse.phone, @@ -417,7 +413,9 @@ class Contact(orm.AbstractModel): 'email': field_browse.email, 'fields': opf, 'options': options - }, engine='website.qweb', context=context) + } + + html = self.pool["ir.ui.view"].render(cr, uid, "website.contact", val, engine='website.qweb', context=context) return ir_qweb.HTMLSafe(html) diff --git a/addons/website/models/website.py b/addons/website/models/website.py index 8303220e7af..cee457b70fd 100644 --- a/addons/website/models/website.py +++ b/addons/website/models/website.py @@ -117,6 +117,7 @@ class website(osv.osv): 'social_linkedin': fields.char('LinkedIn Account'), 'social_youtube': fields.char('Youtube Account'), 'social_googleplus': fields.char('Google+ Account'), + 'google_analytics_key': fields.char('Google Analytics Key'), 'public_user': fields.function(_get_public_user, relation='res.users', type='many2one', string='Public User'), 'menu_id': fields.function(_get_menu, relation='website.menu', type='many2one', string='Main Menu', store= { @@ -322,7 +323,7 @@ class website(osv.osv): :type rule: werkzeug.routing.Rule :rtype: bool """ - spec = inspect.getargspec(rule.endpoint) + spec = inspect.getargspec(rule.endpoint.method) # if *args bail the fuck out, only dragons can live there if spec.varargs: diff --git a/addons/website/static/src/css/editor.css b/addons/website/static/src/css/editor.css index 386fead7ad3..d0a02ce7b0b 100644 --- a/addons/website/static/src/css/editor.css +++ b/addons/website/static/src/css/editor.css @@ -207,6 +207,44 @@ ul.oe_menu_editor .disclose { visibility: visible !important; } +.modal .font-icons-icons { + font-size: 2em; + max-height: 6em; + overflow: auto; +} +.modal .font-icons-icons .font-icons-icon { + display: inline-block; + width: 2em; + padding: 0.25em; + text-align: center; + cursor: pointer; +} +.modal .font-icons { + position: relative; + display: block; +} +.modal .font-icons:before { + filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=70); + opacity: 0.7; + position: absolute; + top: 2px; + left: 3px; + font-size: 2em; +} +.modal #icon-search { + padding-left: 2.5em; +} +.modal #fa-preview { + text-align: center; +} +.modal #fa-preview span { + cursor: pointer; + padding: 0 15px; +} +.modal #fa-preview .font-icons-selected { + background-color: #dddddd; +} + .existing-attachments .pager .disabled { display: none; } @@ -320,6 +358,56 @@ ul.oe_menu_editor .disclose { -o-border-radius: 0.4em; border-radius: 0.4em; } +.oe_seo_configuration li.oe_seo_preview_g { + line-height: 1.2; + list-style: none; + list-style-image: none; + list-style-position: outside; + list-style-type: none; + font-size: small; + font-family: arial, sans-serif; +} +.oe_seo_configuration li.oe_seo_preview_g h3 { + font-size: medium; +} +.oe_seo_configuration li.oe_seo_preview_g .r { + margin: 0; + font-size: 16px; + font-style: normal; + font-weight: normal; + overflow: hidden; + text-overflow: ellipsis; + -webkit-text-overflow: ellipsis; + white-space: nowrap; +} +.oe_seo_configuration li.oe_seo_preview_g .r a { + color: #1e0fbe; + text-decoration: underline; + text-transform: none; +} +.oe_seo_configuration li.oe_seo_preview_g .r a em { + font-style: normal !important; +} +.oe_seo_configuration li.oe_seo_preview_g .s { + color: #444444; + max-width: 42em; +} +.oe_seo_configuration li.oe_seo_preview_g .kv, .oe_seo_configuration li.oe_seo_preview_g .slp { + display: block; + margin-bottom: 1px; +} +.oe_seo_configuration li.oe_seo_preview_g .f { + color: #666666; + margin-bottom: 1px; +} +.oe_seo_configuration li.oe_seo_preview_g .f cite { + color: #006621; + font-style: normal; + font-size: 14px; +} +.oe_seo_configuration li.oe_seo_preview_g .st { + line-height: 1.24; +} /* ---- ACE EDITOR ---- {{{ */ .oe_ace_view_editor { diff --git a/addons/website/static/src/css/editor.sass b/addons/website/static/src/css/editor.sass index 923bd63e7dd..ce9e43ec1a2 100644 --- a/addons/website/static/src/css/editor.sass +++ b/addons/website/static/src/css/editor.sass @@ -172,6 +172,43 @@ ul.oe_menu_editor display: inline-block !important visibility: visible !important +// fontawesome modal +.modal + .font-icons-icons + font-size: 2em + max-height: 6em + overflow: auto + + .font-icons-icon + display: inline-block + width: 2em + padding: 0.25em + text-align: center + cursor: pointer + + .font-icons + position: relative + display: block + + &:before + +opacity(0.7) + position: absolute + top: 2px + left: 3px + font-size: 2em + #icon-search + padding-left: 2.5em + + #fa-preview + text-align: center + + span + cursor: pointer + padding: 0 15px + .font-icons-selected + background-color: #ddd + + .existing-attachments .pager .disabled display: none @@ -276,6 +313,47 @@ $highlighted_text_color: #ffffff .oe_seo_keyword padding: .2em .4em .2em .5em +border-radius(.4em) + li.oe_seo_preview_g + line-height: 1.2 + list-style: none + list-style-image: none + list-style-position: outside + list-style-type: none + font-size: small + font-family: arial,sans-serif + h3 + font-size: medium + .r + margin: 0 + font-size: 16px + font-style: normal + font-weight: normal + overflow: hidden + text-overflow: ellipsis + -webkit-text-overflow: ellipsis + white-space: nowrap + a + color: rgb(30, 15, 190) + text-decoration: underline + text-transform: none + em + font-style: normal !important + .s + color: #444 + max-width: 42em + .kv,.slp + display: block + margin-bottom: 1px + .f + color: #666 + margin-bottom: 1px + cite + color: #006621 + font-style: normal + font-size: 14px + .st + line-height: 1.24 + // }}} diff --git a/addons/website/static/src/js/website.editor.js b/addons/website/static/src/js/website.editor.js index e687dbb6a31..f5a1c845f28 100644 --- a/addons/website/static/src/js/website.editor.js +++ b/addons/website/static/src/js/website.editor.js @@ -463,6 +463,10 @@ $(window).on('resize', _.debounce(this.check_height.bind(this), 50)); this.check_height(); + if (website.is_editable_button) { + this.$("button[data-action=edit]").removeClass("hidden"); + } + return $.when( this._super.apply(this, arguments), this.rte.appendTo(this.$('#website-top-edit .nav.pull-right')) @@ -607,14 +611,19 @@ */ setup_hover_buttons: function () { var editor = this.rte.editor; - var $link_button = this.make_hover_button(_t("Edit Link"), function () { + var $link_button = this.make_hover_button(_t("Change"), function () { var sel = new CKEDITOR.dom.element(previous); editor.getSelection().selectElement(sel); - link_dialog(editor); + if (previous.tagName.toUpperCase() === 'A') { + link_dialog(editor); + } else if(sel.hasClass('fa')) { + new website.editor.FontIconsDialog(editor, previous) + .appendTo(document.body); + } $link_button.hide(); previous = null; }, 'btn-xs'); - var $image_button = this.make_hover_button(_t("Edit Image"), function () { + var $image_button = this.make_hover_button(_t("Change"), function () { image_dialog(editor, new CKEDITOR.dom.element(previous)); $image_button.hide(); previous = null; @@ -625,12 +634,12 @@ // -ish, because when moving to the button itself ``previous`` is // still set to the element having triggered showing the button. var previous; - $(editor.element.$).on('mouseover', 'a, img', function (e) { + $(editor.element.$).on('mouseover', 'a, img, .fa', function () { // Back from edit button -> ignore if (previous && previous === this) { return; } var selected = new CKEDITOR.dom.element(this); - if (!is_editable_node(selected)) { + if (!is_editable_node(selected) && !selected.hasClass('fa')) { return; } @@ -659,7 +668,7 @@ - $link_button.outerWidth() / 2 }) } - }).on('mouseleave', 'a, img', function (e) { + }).on('mouseleave', 'a, img, .fa', function (e) { var current = document.elementFromPoint(e.clientX, e.clientY); if (current === $link_button[0] || current === $image_button[0]) { return; @@ -817,6 +826,28 @@ document.execCommand("enableInlineTableEditing", false, "false"); } catch (e) {} + + // detect & setup any CKEDITOR widget within a newly dropped + // snippet. There does not seem to be a simple way to do it for + // HTML not inserted via ckeditor APIs: + // https://dev.ckeditor.com/ticket/11472 + $(document.body) + .off('snippet-dropped') + .on('snippet-dropped', function (e, el) { + // CKEDITOR data processor extended by widgets plugin + // to add wrappers around upcasting elements + el.outerHTML = editor.dataProcessor.toHtml(el.outerHTML, { + fixForBody: false, + dontFilter: true, + }); + // then repository.initOnAll() handles the conversion + // from wrapper to actual widget instance (or something + // like that). + setTimeout(function () { + editor.widgets.initOnAll(); + }, 0); + }); + self.trigger('rte:ready'); def.resolve(); }); @@ -1056,15 +1087,20 @@ bind_data: function (text, href, new_window) { href = href || this.element && (this.element.data( 'cke-saved-href') || this.element.getAttribute('href')); - if (!href) { return; } if (new_window === undefined) { - new_window = this.element.getAttribute('target') === '_blank'; + new_window = this.element + ? this.element.getAttribute('target') === '_blank' + : false; } if (text === undefined) { - text = this.element.getText(); + text = this.element ? this.element.getText() : ''; } + this.$('input#link-text').val(text); + this.$('input.window-new').prop('checked', new_window); + + if (!href) { return; } var match, $control; if ((match = /mailto:(.+)/.exec(href))) { $control = this.$('input.email-address').val(match[1]); @@ -1074,9 +1110,6 @@ } this.changed($control); - - this.$('input#link-text').val(text); - this.$('input.window-new').prop('checked', new_window); }, changed: function ($e) { this.$('.url-source').filter(':input').not($e).val('') @@ -1456,6 +1489,34 @@ template: 'website.editor.dialog.font-icons', events : _.extend({}, website.editor.Dialog.prototype.events, { change: 'update_preview', + 'click .font-icons-icon': function (e) { + e.preventDefault(); + e.stopPropagation(); + + this.$('#fa-icon').val(e.target.getAttribute('data-id')); + this.update_preview(); + }, + 'click #fa-preview span': function (e) { + e.preventDefault(); + e.stopPropagation(); + + this.$('#fa-size').val(e.target.getAttribute('data-size')); + this.update_preview(); + }, + 'input input#icon-search': function () { + var needle = this.$('#icon-search').val(); + var icons = this.icons; + if (needle) { + icons = _(icons).filter(function (icon) { + return icon.id.substring(3).indexOf(needle) !== -1; + }); + } + + this.$('div.font-icons-icons').html( + openerp.qweb.render( + 'website.editor.dialog.font-icons.icons', + {icons: icons})); + }, }), // List of FontAwesome icons in 4.0.3, extracted from the cheatsheet. @@ -1474,26 +1535,7 @@ * isn't customizable (?) and the fontawesome glyphs fail to appear. */ start: function () { - var self = this; - var started = this._super(); - this.$('#fa-icon').select2({ - data: this.icons, - initSelection: function (element, callback) { - var id = element.val(), match; - if (id) { - match = _.find(self.icons, function (item) { - return item.id === id; - }) || void 0; - } - - callback(match); - }, - formatSelection: function (object) { - return $('').text(object.text); - }, - formatResultCssClass: function () { return 'fa'; }, - }); - return started.then(this.proxy('load_data')); + return this._super().then(this.proxy('load_data')); }, /** * Removes existing FontAwesome classes on the bound element, and sets @@ -1520,7 +1562,7 @@ for (var i = 0; i < classes.length; i++) { var cls = classes[i]; switch(cls) { - case 'fa-lg':case 'fa-2x':case 'fa-3x':case 'fa-4x':case 'fa-5x': + case 'fa-2x':case 'fa-3x':case 'fa-4x':case 'fa-5x': // size classes this.$('#fa-size').val(cls); continue; @@ -1529,15 +1571,14 @@ case 'fa-flip-horizontal':case 'fa-rotate-vertical': this.$('#fa-rotation').val(cls); continue; - case 'fa-fixed': - this.$('#fa-fixed').prop('checked', true); + case 'fa-fw': continue; case 'fa-border': this.$('#fa-border').prop('checked', true); continue; default: if (!/^fa-/.test(cls)) { continue; } - this.$('#fa-icon').select2('val', cls); + this.$('#fa-icon').val(cls); } } this.update_preview(); @@ -1549,19 +1590,34 @@ get_fa_classes: function () { return [ 'fa', - this.$('#fa-icon').select2('val'), + this.$('#fa-icon').val(), this.$('#fa-size').val(), this.$('#fa-rotation').val(), - this.$('#fa-fixed').prop('checked') ? 'fa-fixed' : '', this.$('#fa-border').prop('checked') ? 'fa-border' : '' ]; }, update_preview: function () { - this.$('#fa-preview')[0].className = this.get_fa_classes().join(' '); + var $preview = this.$('#fa-preview').empty(); + var sizes = ['', 'fa-2x', 'fa-3x', 'fa-4x', 'fa-5x']; + var classes = this.get_fa_classes(); + var no_sizes = _.difference(classes, sizes).join(' '); + var selected = false; + for (var i = sizes.length - 1; i >= 0; i--) { + var size = sizes[i]; + + var $p = $('') + .attr('data-size', size) + .addClass(size) + .addClass(no_sizes); + if ((size && _.contains(classes, size)) || (!size && !selected)) { + $p.addClass('font-icons-selected'); + selected = true; + } + $preview.prepend($p); + } } }); - website.Observer = window.MutationObserver || window.WebkitMutationObserver || window.JsMutationObserver; var OBSERVER_CONFIG = { childList: true, diff --git a/addons/website/static/src/js/website.editor.newpage.js b/addons/website/static/src/js/website.editor.newpage.js index e333e2e451e..fd84c7c893e 100644 --- a/addons/website/static/src/js/website.editor.newpage.js +++ b/addons/website/static/src/js/website.editor.newpage.js @@ -3,11 +3,12 @@ var website = openerp.website; website.is_editable = true; + website.is_editable_button = true; + website.EditorBar.include({ start: function() { var res = this._super(); this.$("a[data-action=new_page]").parents("li").removeClass("hidden"); - this.$("button[data-action=edit]").removeClass("hidden"); this.$(".oe_content_menu li.divider").removeClass("hidden"); return res; }, diff --git a/addons/website/static/src/js/website.js b/addons/website/static/src/js/website.js index 44adbe31f64..c6c2b21f9d4 100644 --- a/addons/website/static/src/js/website.js +++ b/addons/website/static/src/js/website.js @@ -67,6 +67,7 @@ var dom_ready = website.dom_ready = $.Deferred(); $(document).ready(function () { website.is_editable = website.is_editable || $('html').data('editable'); + website.is_editable_button= website.is_editable_button || $('html').data('editable'); dom_ready.resolve(); }); diff --git a/addons/website/static/src/js/website.seo.js b/addons/website/static/src/js/website.seo.js index 563f850486e..8588b7a3765 100644 --- a/addons/website/static/src/js/website.seo.js +++ b/addons/website/static/src/js/website.seo.js @@ -25,7 +25,10 @@ } : htmlPage.isInBody(keyword) ? { title: 'label label-info', description: "This keyword is used in the page content." - } : { title: "", description: "" }; + } : { + title: 'label label-default', + description: "This keyword is not used anywhere on the page." + }; } website.seo.Suggestion = openerp.Widget.extend({ @@ -234,6 +237,16 @@ }, }); + website.seo.Preview = openerp.Widget.extend({ + template: 'website.seo_preview', + init: function (parent, options) { + this.title = options.title; + this.url = options.url; + this.description = options.description || "[ The description will be generated by google unless you specify one ]"; + this._super(parent); + }, + }); + website.seo.HtmlPage = openerp.Class.extend(openerp.PropertiesMixin, { url: function () { var url = window.location.href; @@ -327,7 +340,7 @@ canEditDescription: false, canEditKeywords: false, maxTitleSize: 65, - maxDescriptionSize: 155, + maxDescriptionSize: 150, start: function () { var self = this; var $modal = self.$el; @@ -361,6 +374,7 @@ }); self.keywordList.appendTo($modal.find('.js_seo_keywords_list')); self.disableUnsavableFields(); + self.renderPreview(); $modal.modal(); }, disableUnsavableFields: function () { @@ -376,7 +390,7 @@ if (!self.canEditDescription) { $modal.find('textarea[name=seo_page_description]').attr('disabled', true); } - if (!self.canEditTitle && !canEditDescription && !canEditKeywords) { + if (!self.canEditTitle && !self.canEditDescription && !self.canEditKeywords) { $modal.find('button[data-action=update]').attr('disabled', true); } }); @@ -484,6 +498,7 @@ setTimeout(function () { var title = self.$('input[name=seo_page_title]').val(); self.htmlPage.changeTitle(title); + self.renderPreview(); }, 0); }, descriptionChanged: function () { @@ -491,7 +506,18 @@ setTimeout(function () { var description = self.$('textarea[name=seo_page_description]').attr('value'); self.htmlPage.changeDescription(description); - }, 1); + self.renderPreview(); + }, 0); + }, + renderPreview: function () { + var preview = new website.seo.Preview(this, { + title: this.htmlPage.title(), + description: this.htmlPage.description(), + url: this.htmlPage.url(), + }); + var $preview = this.$('.js_seo_preview'); + $preview.empty(); + preview.appendTo($preview); }, destroy: function () { this.htmlPage.changeKeywords(this.keywordList.keywords()); diff --git a/addons/website/static/src/js/website.snippets.editor.js b/addons/website/static/src/js/website.snippets.editor.js index 1d28df08c75..89f226adfae 100644 --- a/addons/website/static/src/js/website.snippets.editor.js +++ b/addons/website/static/src/js/website.snippets.editor.js @@ -76,6 +76,9 @@ hack_to_add_snippet_id(); }); + // '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 + website.snippet.styles = {}; website.snippet.selector = []; website.snippet.BuildingBlock = openerp.Widget.extend({ diff --git a/addons/website/static/src/js/website.tour.js b/addons/website/static/src/js/website.tour.js index 77136bd4bda..7e8d2aea7a0 100644 --- a/addons/website/static/src/js/website.tour.js +++ b/addons/website/static/src/js/website.tour.js @@ -19,104 +19,108 @@ }); this.registerSteps(); }, - registerSteps: function () { + registerStep: function (step) { var self = this; - this.tour.addSteps(_.map(this.steps, function (step) { - step.title = openerp.qweb.render('website.tour_popover_title', { title: step.title }); - if (!step.element) { - step.orphan = true; - } - if (step.snippet) { - step.element = '#oe_snippets div.oe_snippet[data-snippet-id="'+step.snippet+'"] .oe_snippet_thumbnail'; - } - if (step.trigger) { - if (step.trigger === 'click') { + step.title = openerp.qweb.render('website.tour_popover_title', { title: step.title }); + if (!step.element) { + step.orphan = true; + } + if (step.snippet) { + step.element = '#oe_snippets div.oe_snippet[data-snippet-id="'+step.snippet+'"] .oe_snippet_thumbnail'; + } + if (step.trigger) { + if (step.trigger === 'click') { + step.triggers = function (callback) { + $(step.element).one('click', function () { + (callback || self.moveToNextStep).apply(self); + }); + }; + } else if (step.trigger === 'reload') { + step.triggers = function (callback) { + var stack = JSON.parse(localStorage.getItem("website-reloads")) || []; + var index = stack.indexOf(step.stepId); + if (index !== -1) { + stack.splice(index,1); + (callback || self.moveToNextStep).apply(self); + } else { + stack.push(step.stepId); + } + localStorage.setItem("website-reloads", JSON.stringify(stack)); + }; + } else if (step.trigger.url) { + step.triggers = function (callback) { + var stack = JSON.parse(localStorage.getItem("website-geturls")) || []; + var id = step.trigger.url.toString(); + var index = stack.indexOf(id); + if (index !== -1) { + var url = new website.UrlParser(window.location.href); + var test = typeof step.trigger.url === "string" ? + step.trigger.url == url.pathname+url.search : + step.trigger.url.test(url.pathname+url.search); + if (!test) return; + stack.splice(index,1); + (callback || self.moveToNextStep).apply(self); + } else { + stack.push(id); + } + localStorage.setItem("website-geturls", JSON.stringify(stack)); + }; + } else if (step.trigger === 'drag') { + step.triggers = function (callback) { + self.onSnippetDragged(callback || self.moveToNextStep); + }; + } else if (step.trigger.id) { + if (step.trigger.emitter && step.trigger.type === 'openerp') { step.triggers = function (callback) { - $(step.element).one('click', function () { - (callback || self.moveToNextStep).apply(self); + step.trigger.emitter.on(step.trigger.id, self, function customHandler () { + step.trigger.emitter.off(step.trigger.id, customHandler); + (callback || self.moveToNextStep).apply(self, arguments); }); }; - } else if (step.trigger === 'reload') { + } else { step.triggers = function (callback) { - var stack = JSON.parse(localStorage.getItem("website-reloads")) || []; - var index = stack.indexOf(step.stepId); - if (index !== -1) { - stack.splice(index,1); - (callback || self.moveToNextStep).apply(self); - } else { - stack.push(step.stepId); - } - localStorage.setItem("website-reloads", JSON.stringify(stack)); - }; - } else if (step.trigger && step.trigger.url) { - step.triggers = function (callback) { - var stack = JSON.parse(localStorage.getItem("website-geturls")) || []; - var id = step.trigger.url.toString(); - var index = stack.indexOf(id); - if (index !== -1) { - var url = new website.UrlParser(window.location.href); - var test = typeof step.trigger.url === "string" ? - step.trigger.url == url.pathname+url.search : - step.trigger.url.test(url.pathname+url.search); - if (!test) return; - stack.splice(index,1); - (callback || self.moveToNextStep).apply(self); - } else { - stack.push(id); - } - localStorage.setItem("website-geturls", JSON.stringify(stack)); - }; - } else if (step.trigger === 'drag') { - step.triggers = function (callback) { - self.onSnippetDragged(callback || self.moveToNextStep); - }; - } else if (step.trigger && step.trigger.id) { - if (step.trigger.emitter && step.trigger.type === 'openerp') { - step.triggers = function (callback) { - step.trigger.emitter.on(step.trigger.id, self, function customHandler () { - step.trigger.emitter.off(step.trigger.id, customHandler); - (callback || self.moveToNextStep).apply(self, arguments); - }); - }; - } else { - step.triggers = function (callback) { - var emitter = _.isString(step.trigger.emitter) ? $(step.trigger.emitter) : (step.trigger.emitter || $(step.element)); - if (!emitter.size()) throw "Emitter is undefined"; - emitter.on(step.trigger.id, function () { - (callback || self.moveToNextStep).apply(self, arguments); - }); - }; - } - } else if (step.trigger.modal) { - step.triggers = function (callback) { - var $doc = $(document); - function onStop () { - if (step.trigger.modal.stopOnClose) { - self.stop(); - } - } - $doc.on('hide.bs.modal', onStop); - $doc.one('shown.bs.modal', function () { - $('.modal button.btn-primary').one('click', function () { - $doc.off('hide.bs.modal', onStop); - (callback || self.moveToNextStep).apply(self, [step.trigger.modal.afterSubmit]); - }); - (callback || self.moveToNextStep).apply(self); + var emitter = _.isString(step.trigger.emitter) ? $(step.trigger.emitter) : (step.trigger.emitter || $(step.element)); + if (!emitter.size()) throw "Emitter is undefined"; + emitter.on(step.trigger.id, function () { + (callback || self.moveToNextStep).apply(self, arguments); }); }; } - } - step.onShow = (function () { - var executed = false; - return function () { - if (!executed) { - _.isFunction(step.onStart) && step.onStart(); - _.isFunction(step.triggers) && step.triggers(); - executed = true; + } else if (step.trigger.modal) { + step.triggers = function (callback) { + var $doc = $(document); + function onStop () { + if (step.trigger.modal.stopOnClose) { + self.stop(); + } } + $doc.on('hide.bs.modal', onStop); + $doc.one('shown.bs.modal', function () { + $('.modal button.btn-primary').one('click', function () { + $doc.off('hide.bs.modal', onStop); + (callback || self.moveToNextStep).apply(self, [step.trigger.modal.afterSubmit]); + }); + (callback || self.moveToNextStep).apply(self); + }); }; - }()); - return step; + } + } + step.onShow = (function () { + var executed = false; + return function () { + if (!executed) { + _.isFunction(step.onStart) && step.onStart(); + _.isFunction(step.triggers) && step.triggers(); + executed = true; + } + }; + }()); + return step; + }, + registerSteps: function () { + var self = this; + this.tour.addSteps(_.map(this.steps, function (step) { + return self.registerStep(step); })); }, reset: function () { @@ -152,8 +156,8 @@ this.stop(); } else if (index >= 0) { var self = this; - $('.popover.tour').remove(); setTimeout(function () { + $('.popover.tour').remove(); setTimeout(function () { self.tour.goto(index); }, 0); @@ -323,6 +327,7 @@ var testId = 'test_'+tour.id+'_tour'; this.tours.push(tour); var defaultDelay = 500; //ms + var overlapsCrash; var test = { id: tour.id, run: function (force) { @@ -332,34 +337,63 @@ var actionSteps = _.filter(tour.steps, function (step) { return step.trigger || step.sampleText; }); + window.onbeforeunload = function () { + clearTimeout(overlapsCrash); + }; function executeStep (step) { + var lastStep = window.localStorage.getItem(testId); + var tryStep = lastStep != step.stepId ? 0 : parseInt(window.localStorage.getItem("last-"+testId) || 0, 10)+1; + window.localStorage.setItem("last-"+testId, tryStep); + if (tryStep > 2) { + window.localStorage.removeItem(testId); + throw "Test: '" + testId + "' cycling step: '" + step.stepId + "'"; + } + + var _next = false; window.localStorage.setItem(testId, step.stepId); function next () { + clearTimeout(overlapsCrash); + _next = true; var nextStep = actionSteps.shift(); if (nextStep) { - executeStep(nextStep); + setTimeout(function () { + executeStep(nextStep); + }, step.delay || defaultDelay); } else { window.localStorage.removeItem(testId); } } - setTimeout(function () { - if (step.triggers) step.triggers(next); - var $element = $(step.element); - if (step.snippet && step.trigger === 'drag') { - website.TestConsole.dragAndDropSnippet(step.snippet); - } else if (step.trigger && step.trigger.id === 'change') { - $element.trigger($.Event("change", { srcElement: $element })); - } else if (step.sampleText) { - $element.val(step.sampleText); - $element.trigger($.Event("change", { srcElement: $element })); - } else if ($element.is(":visible")) { // Click by default - $element.trigger($.Event("click", { srcElement: $element })); + overlapsCrash = setTimeout(function () { + window.localStorage.removeItem(testId); + throw "Test: '" + testId + "' can't resolve step: '" + step.stepId + "'"; + }, (step.delay || defaultDelay) + 500); + + var $element = $(step.element); + if (step.triggers) step.triggers(next); + if ((step.trigger === 'reload' || (step.trigger && step.trigger.url)) && _next) return; + + if (step.snippet && step.trigger === 'drag') { + website.TestConsole.dragAndDropSnippet(step.snippet); + } else if (step.trigger && step.trigger.id === 'change') { + $element.trigger($.Event("change", { srcElement: $element })); + } else if (step.sampleText) { + $element.val(step.sampleText); + $element.trigger($.Event("change", { srcElement: $element })); + } else if ($element.is(":visible")) { // Click by default + if (step.trigger.id === 'mousedown') { + $element.trigger($.Event("mousedown", { srcElement: $element })); } - if (!step.triggers) next(); - }, step.delay || defaultDelay); + var evt = document.createEvent("MouseEvents"); + evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); + $element[0].dispatchEvent(evt); + if (step.trigger.id === 'mouseup') { + $element.trigger($.Event("mouseup", { srcElement: $element })); + } + } + if (!step.triggers) next(); } var url = new website.UrlParser(window.location.href); - if (tour.path && url.pathname !== tour.path) { + if (tour.path && url.pathname !== tour.path && !window.localStorage.getItem(testId)) { window.localStorage.setItem(testId, actionSteps[0].stepId); window.location.href = tour.path; } else { diff --git a/addons/website/static/src/js/website.translator.js b/addons/website/static/src/js/website.translator.js index 812f8902c65..399e5e731b2 100644 --- a/addons/website/static/src/js/website.translator.js +++ b/addons/website/static/src/js/website.translator.js @@ -13,9 +13,13 @@ var self = this; this.initial_content = {}; return this._super.apply(this, arguments).then(function () { + self.$("button[data-action=edit]").removeClass("hidden"); self.$('button[data-action=edit]') - .text("Translate") - .after(openerp.qweb.render('website.TranslatorAdditionalButtons')); + .text("Translate"); + if (website.is_editable_button) { + self.$('button[data-action=edit]') + .after(openerp.qweb.render('website.TranslatorAdditionalButtons')); + } self.$('.js_hide_on_translate').hide(); }); }, diff --git a/addons/website/static/src/xml/website.editor.xml b/addons/website/static/src/xml/website.editor.xml index 12fd0774f39..448c615bb07 100644 --- a/addons/website/static/src/xml/website.editor.xml +++ b/addons/website/static/src/xml/website.editor.xml @@ -207,23 +207,18 @@ Icon:
-
- Preview: +
+
-
- + -
- - + + +
+ + + +
@@ -239,16 +234,18 @@
-
-
-
+ + + + + diff --git a/addons/website/static/src/xml/website.seo.xml b/addons/website/static/src/xml/website.seo.xml index be9414ca37f..0c055487dd8 100644 --- a/addons/website/static/src/xml/website.seo.xml +++ b/addons/website/static/src/xml/website.seo.xml @@ -43,19 +43,24 @@
-