diff options
| author | qsm-odoo <qsm@odoo.com> | 2017-06-07 17:45:15 +0200 |
|---|---|---|
| committer | qsm-odoo <qsm@odoo.com> | 2017-08-16 10:59:39 +0200 |
| commit | 4f925af06fd3cebfcfb56eb947ab68c8a2ca4490 (patch) | |
| tree | b13bd049b6b3e7bbdfb537d19b53c95fc4025ea5 /addons/website/static/src/js/menu | |
| parent | f205bfcd4ddcf3f1d8676ee87ee0b29941bd6773 (diff) | |
[MOV] web_editor, website: reorganize files
Diffstat (limited to 'addons/website/static/src/js/menu')
| -rw-r--r-- | addons/website/static/src/js/menu/content.js | 361 | ||||
| -rw-r--r-- | addons/website/static/src/js/menu/mobile_view.js | 49 | ||||
| -rw-r--r-- | addons/website/static/src/js/menu/planner.js | 41 | ||||
| -rw-r--r-- | addons/website/static/src/js/menu/seo.js | 582 | ||||
| -rw-r--r-- | addons/website/static/src/js/menu/translate.js | 104 |
5 files changed, 1137 insertions, 0 deletions
diff --git a/addons/website/static/src/js/menu/content.js b/addons/website/static/src/js/menu/content.js new file mode 100644 index 00000000000..70f35871e74 --- /dev/null +++ b/addons/website/static/src/js/menu/content.js @@ -0,0 +1,361 @@ +odoo.define('website.contentMenu', function (require) { +"use strict"; + +var core = require('web.core'); +var ajax = require('web.ajax'); +var Widget = require('web.Widget'); +var base = require('web_editor.base'); +var editor = require('web_editor.editor'); +var widget = require('web_editor.widget'); +var website = require('website.website'); + +var _t = core._t; +var qweb = core.qweb; + +ajax.loadXML('/website/static/src/xml/website.contentMenu.xml', qweb); + +var TopBarContent = Widget.extend({ + start: function () { + var self = this; + + // Add page modal + menu content event + this.$el.add($('#o_website_add_page_modal')).on('click', 'a[data-action]', function (e) { + e.preventDefault(); + self[$(this).data('action')](); + }); + + return this._super(); + }, + edit_menu: function (action_before_reload) { + var context = base.get_context(); + var def = $.Deferred(); + if ($("[data-content_menu_id]").length) { + var select = new SelectEditMenuDialog(); + select.on('save', this, function (root) { + def.resolve(root); + }); + select.open(); + } else { + def.resolve(null); + } + + return def.then(function (root_id) { + return ajax.jsonRpc('/web/dataset/call_kw', 'call', { + model: 'website.menu', + method: 'get_tree', + args: [context.website_id, root_id], + kwargs: { + context: context + }, + }).then(function (menu) { + var dialog = new EditMenuDialog(this, {}, menu).open(); + dialog.on("save", null, function () { + $.when(action_before_reload && action_before_reload()).then(function () { + editor.reload(); + }); + }); + return dialog; + }); + }); + }, + new_page: function () { + website.prompt({ + id: "editor_new_page", + window_title: _t("New Page"), + input: _t("Page Title"), + init: function () { + var $group = this.$dialog.find("div.form-group"); + $group.removeClass("mb0"); + + var $add = $('<div/>', {'class': 'form-group mb0'}) + .append($('<span/>', {'class': 'col-sm-offset-3 col-sm-9 text-left'}) + .append(qweb.render('web_editor.components.switch', {id: 'switch_addTo_menu', label: _t("Add page in menu")}))); + $add.find('input').prop('checked', true); + $group.after($add); + } + }).then(function (val, field, $dialog) { + if (val) { + var url = '/website/add/' + encodeURIComponent(val); + if ($dialog.find('input[type="checkbox"]').is(':checked')) url +="?add_menu=1"; + document.location = url; + } + }); + }, + rename_page: function () { + var self = this; + var context = base.get_context(); + self.mo_id = self.getMainObject().id; + + ajax.jsonRpc('/web/dataset/call_kw', 'call', { + model: 'website', + method: 'page_search_dependencies', + args: [self.mo_id], + kwargs: { + context: context + }, + }).then(function (deps) { + website.prompt({ + id: "editor_rename_page", + window_title: _t("Rename This Page"), + dependencies: deps, + }, 'website.rename_page').then(function (val, field, $dialog) { + ajax.jsonRpc('/web/dataset/call_kw', 'call', { + model: 'website', + method: 'rename_page', + args: [ + self.mo_id, + val, + ], + kwargs: { + context: context + }, + }).then(function (new_name) { + window.location = "/page/" + encodeURIComponent(new_name); + }); + }); + }); + }, + delete_page: function () { + var self = this; + var context = base.get_context(); + self.mo_id = self.getMainObject().id; + + ajax.jsonRpc('/web/dataset/call_kw', 'call', { + model: 'website', + method: 'page_search_dependencies', + args: [self.mo_id], + kwargs: { + context: context, + }, + }).then(function (deps) { + website.prompt({ + id: "editor_delete_page", + window_title: _t("Delete Page"), + dependencies: deps, + init: function () { $('.btn-continue').prop("disabled", true); }, + }, 'website.delete_page').then(function (val, field, $dialog) { + + if ($dialog.find('input[type="checkbox"]').is(':checked')) { + ajax.jsonRpc('/web/dataset/call_kw', 'call', { + model: 'website', + method: 'delete_page', + args: [self.mo_id], + kwargs: { + context: context + }, + }).then(function () { + window.location = "/"; + }); + } + }); + }); + }, + getMainObject: function () { + var repr = $('html').data('main-object'); + var m = repr.match(/(.+)\((\d+),(.*)\)/); + if (!m) { + return null; + } else { + return { + model: m[1], + id: m[2]|0 + }; + } + } +}); + +website.TopBar.include({ + start: function () { + this.content_menu = new TopBarContent(); + var def = this.content_menu.attachTo($('.oe_content_menu')); + return $.when(this._super(), def); + } +}); + +var SelectEditMenuDialog = widget.Dialog.extend({ + template: 'website.contentMenu.dialog.select', + init: function (parent, options) { + var self = this; + self.roots = [{id: null, name: _t("Top Menu")}]; + $("[data-content_menu_id]").each(function () { + self.roots.push({id: $(this).data("content_menu_id"), name: $(this).attr("name")}); + }); + this._super(parent, _.extend({}, { + title: _t("Select a Menu"), + save_text: _t("Continue") + }, options || {})); + }, + save: function () { + this.final_data = parseInt(this.$el.find("select").val() || null); + this._super.apply(this, arguments); + } +}); + +var EditMenuDialog = widget.Dialog.extend({ + template: 'website.contentMenu.dialog.edit', + events: _.extend({}, widget.Dialog.prototype.events, { + 'click a.js_add_menu': 'add_menu', + 'click button.js_edit_menu': 'edit_menu', + 'click button.js_delete_menu': 'delete_menu', + }), + init: function (parent, options, menu) { + this.menu = menu; + this.root_menu_id = menu.id; + this.flat = this.flatenize(menu); + this.to_delete = []; + this._super(parent, _.extend({}, { + title: _t("Edit Menu"), + size: 'medium', + }, options || {})); + }, + start: function () { + var r = this._super.apply(this, arguments); + this.$('.oe_menu_editor').nestedSortable({ + listType: 'ul', + handle: 'div', + items: 'li', + maxLevels: 2, + toleranceElement: '> div', + forcePlaceholderSize: true, + opacity: 0.6, + placeholder: 'oe_menu_placeholder', + tolerance: 'pointer', + attribute: 'data-menu-id', + expression: '()(.+)', // nestedSortable takes the second match of an expression (*sigh*) + }); + return r; + }, + flatenize: function (node, dict) { + dict = dict || {}; + var self = this; + dict[node.id] = node; + node.children.forEach(function (child) { + self.flatenize(child, dict); + }); + return dict; + }, + add_menu: function () { + var self = this; + var dialog = new MenuEntryDialog(this, {menu_link_options: true}, undefined, {}); + dialog.on('save', this, function (link) { + var new_menu = { + id: _.uniqueId('new-'), + name: link.text, + url: link.url, + new_window: link.isNewWindow, + parent_id: false, + sequence: 0, + children: [], + }; + self.flat[new_menu.id] = new_menu; + self.$('.oe_menu_editor').append( + qweb.render('website.contentMenu.dialog.submenu', { submenu: new_menu })); + }); + dialog.open(); + }, + edit_menu: function (ev) { + var self = this; + var menu_id = $(ev.currentTarget).closest('[data-menu-id]').data('menu-id'); + var menu = self.flat[menu_id]; + if (menu) { + var dialog = new MenuEntryDialog(this, {}, undefined, menu); + dialog.on('save', this, function (link) { + var id = link.id; + var menu_obj = self.flat[id]; + _.extend(menu_obj, { + 'name': link.text, + 'url': link.url, + 'new_window': link.isNewWindow, + }); + var $menu = self.$('[data-menu-id="' + id + '"]'); + $menu.find('.js_menu_label').first().text(menu_obj.name); + }); + dialog.open(); + } else { + alert("Could not find menu entry"); + } + }, + delete_menu: function (ev) { + var $menu = $(ev.currentTarget).closest('[data-menu-id]'); + var mid = $menu.data('menu-id')|0; + if (mid) { + this.to_delete.push(mid); + } + $menu.remove(); + }, + save: function () { + var _super = this._super.bind(this); + var self = this; + var new_menu = this.$('.oe_menu_editor').nestedSortable('toArray', {startDepthCount: 0}); + var levels = []; + var data = []; + var context = base.get_context(); + // Resequence, re-tree and remove useless data + new_menu.forEach(function (menu) { + if (menu.id) { + levels[menu.depth] = (levels[menu.depth] || 0) + 1; + var mobj = self.flat[menu.id]; + mobj.sequence = levels[menu.depth]; + mobj.parent_id = (menu.parent_id|0) || menu.parent_id || self.root_menu_id; + delete(mobj.children); + data.push(mobj); + } + }); + ajax.jsonRpc('/web/dataset/call_kw', 'call', { + model: 'website.menu', + method: 'save', + args: [[context.website_id], { data: data, to_delete: self.to_delete }], + kwargs: { + context: context + }, + }).then(function () { + return _super(); + }); + }, +}); + +var MenuEntryDialog = widget.LinkDialog.extend({ + init: function (parent, options, editor, data) { + data.text = data.name || ''; + data.isNewWindow = data.new_window; + this.data = data; + this.menu_link_options = options.menu_link_options; + return this._super.apply(this, arguments); + }, + start: function () { + var self = this; + this.$(".o_link_dialog_preview").remove(); + this.$(".window-new, .link-style").closest(".form-group").remove(); + this.$("label[for='o_link_dialog_label_input']").text(_t("Menu Label")); + if (this.menu_link_options) { // add menu link option only when adding new menu + this.$('#o_link_dialog_label_input').closest('.form-group').after(qweb.render('website.contentMenu.dialog.edit.link_menu_options')); + this.$('input[name=link_menu_options]').on('change', function() { + self.$('#o_link_dialog_url_input').closest('.form-group').toggle(); + }); + } + this.$modal.find('.modal-lg').removeClass('modal-lg') + .find('.col-md-8').removeClass('col-md-8').addClass('col-xs-12'); + + return this._super.apply(this, arguments); + }, + save: function () { + var $e = this.$('#o_link_dialog_label_input'); + if (!$e.val() || !$e[0].checkValidity()) { + $e.closest('.form-group').addClass('has-error'); + $e.focus(); + return; + } + if (this.$('input[name=link_menu_options]:checked').val() === 'new_page') { + window.location = '/website/add/' + encodeURIComponent($e.val()) + '?add_menu=1'; + return; + } + return this._super.apply(this, arguments); + } +}); + +return { + 'TopBar': TopBarContent, + 'EditMenuDialog': EditMenuDialog, +}; + +}); diff --git a/addons/website/static/src/js/menu/mobile_view.js b/addons/website/static/src/js/menu/mobile_view.js new file mode 100644 index 00000000000..791775f57b8 --- /dev/null +++ b/addons/website/static/src/js/menu/mobile_view.js @@ -0,0 +1,49 @@ +odoo.define('website.mobile', function (require) { +'use strict'; + +var ajax = require('web.ajax'); +var core = require('web.core'); +var Dialog = require('web.Dialog'); +var Widget = require('web.Widget'); +var base = require('web_editor.base'); +var website = require('website.website'); + +var _t = core._t; + +var MobilePreviewDialog = Dialog.extend({ + template: 'website.mobile_preview', + + init: function () { + this._super.apply(this, arguments); + this.mobile_src = $.param.querystring(window.location.href, 'mobilepreview'); + }, + + start: function () { + var self = this; + this.$modal.addClass('oe_mobile_preview'); + this.$modal.on('click', '.modal-header', function () { + self.$el.toggleClass('o_invert_orientation'); + }); + this.$iframe = this.$('iframe'); + this.$iframe.on('load', function (e) { + self.$iframe.contents().find('body').removeClass('o_connected_user'); + self.$iframe.contents().find('#oe_main_menu_navbar, #o_website_add_page_modal').remove(); + }); + + return this._super.apply(this, arguments); + }, +}); + +website.TopBar.include({ + start: function () { + var self = this; + this.$el.on('click', 'a[data-action=show-mobile-preview]', function () { + new MobilePreviewDialog(self, { + title: _t('Mobile preview') + " <span class='fa fa-refresh'/>", + }).open(); + }); + return this._super(); + }, +}); + +}); diff --git a/addons/website/static/src/js/menu/planner.js b/addons/website/static/src/js/menu/planner.js new file mode 100644 index 00000000000..59adfef92a0 --- /dev/null +++ b/addons/website/static/src/js/menu/planner.js @@ -0,0 +1,41 @@ +odoo.define('web.planner.website', function (require) { +'use strict'; + +var ajax = require('web.ajax'); +var core = require('web.core'); +var planner = require('web.planner.common'); +var rpc = require('web.rpc'); +var session = require('web.session'); +var website = require('website.website'); + +var qweb = core.qweb; + +var WebsitePlannerLauncher = planner.PlannerLauncher.extend({ + _fetch_planner_data: function () { + return rpc.query({ + model: 'web.planner', + method: 'search_read', + args: [[['planner_application', '=', 'planner_website']]], + }) + .then((function (planner) { + if (!planner.length) return; + + planner[0].data = $.parseJSON(planner[0].data) || {}; + this._setup_for_planner(planner[0]); + }).bind(this)); + }, +}); + +if (session.is_system) { + website.TopBar.include({ + start: function () { + var websitePlannerLauncher = new WebsitePlannerLauncher(); + var def = ajax.loadXML('/web_planner/static/src/xml/web_planner.xml', qweb).then((function() { + return websitePlannerLauncher.prependTo(this.$(".o_menu_systray")); + }).bind(this)); + return $.when(this._super.apply(this, arguments), def); + }, + }); +} + +}); diff --git a/addons/website/static/src/js/menu/seo.js b/addons/website/static/src/js/menu/seo.js new file mode 100644 index 00000000000..93b434a5f44 --- /dev/null +++ b/addons/website/static/src/js/menu/seo.js @@ -0,0 +1,582 @@ +odoo.define('website.seo', function (require) { +'use strict'; + +var core = require('web.core'); +var ajax = require('web.ajax'); +var Class = require('web.Class'); +var Dialog = require('web.Dialog'); +var mixins = require('web.mixins'); +var rpc = require("web.rpc"); +var Widget = require('web.Widget'); +var base = require('web_editor.base'); +var website = require('website.website'); + +var _t = core._t; + +var qweb = core.qweb; + +ajax.loadXML('/website/static/src/xml/website.seo.xml', qweb); + + // This replaces \b, because accents(e.g. à, é) are not seen as word boundaries. + // Javascript \b is not unicode aware, and words beginning or ending by accents won't match \b + var WORD_SEPARATORS_REGEX = '([\\u2000-\\u206F\\u2E00-\\u2E7F\'!"#\\$%&\\(\\)\\*\\+,\\-\\.\\/:;<=>\\?¿¡@\\[\\]\\^_`\\{\\|\\}~\\s]+|^|$)'; + +function analyzeKeyword(htmlPage, keyword) { + return htmlPage.isInTitle(keyword) ? { + title: 'label label-success', + description: "This keyword is used in the page title", + } : htmlPage.isInDescription(keyword) ? { + title: 'label label-primary', + description: "This keyword is used in the page description", + } : htmlPage.isInBody(keyword) ? { + title: 'label label-info', + description: "This keyword is used in the page content." + } : { + title: 'label label-default', + description: "This keyword is not used anywhere on the page." + }; +} + +var Suggestion = Widget.extend({ + template: 'website.seo_suggestion', + events: { + 'click .js_seo_suggestion': 'select', + }, + init: function (parent, options) { + this.root = options.root; + this.keyword = options.keyword; + this.language = options.language; + this.htmlPage = options.page; + this._super(parent); + }, + start: function () { + this.htmlPage.on('title-changed', this, this.renderElement); + this.htmlPage.on('description-changed', this, this.renderElement); + }, + analyze: function () { + return analyzeKeyword(this.htmlPage, this.keyword); + }, + highlight: function () { + return this.analyze().title; + }, + tooltip: function () { + return this.analyze().description; + }, + select: function () { + this.trigger('selected', this.keyword); + }, +}); + +var SuggestionList = Widget.extend({ + template: 'website.seo_suggestion_list', + init: function (parent, options) { + this.root = options.root; + this.language = options.language; + this.htmlPage = options.page; + this._super(parent); + }, + start: function () { + this.refresh(); + }, + refresh: function () { + var self = this; + self.$el.append(_t("Loading...")); + var language = self.language || base.get_context().lang.toLowerCase(); + ajax.jsonRpc('/website/seo_suggest', 'call', { + 'keywords': self.root, + 'lang': language, + }).then(function (keyword_list) { + self.addSuggestions(JSON.parse(keyword_list)); + }); + }, + addSuggestions: function (keywords) { + var self = this; + self.$el.empty(); + // TODO Improve algorithm + Ajust based on custom user keywords + var regex = new RegExp(self.root, "gi"); + var keywords = _.map(_.uniq(keywords), function (word) { + return word.replace(regex, "").trim(); + }); + // TODO Order properly ? + _.each(keywords, function (keyword) { + if (keyword) { + var suggestion = new Suggestion(self, { + root: self.root, + language: self.language, + keyword: keyword, + page: self.htmlPage, + }); + suggestion.on('selected', self, function (word, language) { + self.trigger('selected', word, language); + }); + suggestion.appendTo(self.$el); + } + }); + }, +}); + +var Keyword = Widget.extend({ + template: 'website.seo_keyword', + events: { + 'click a[data-action=remove-keyword]': 'destroy', + }, + maxWordsPerKeyword: 4, // TODO Check + init: function (parent, options) { + this.keyword = options.word; + this.language = options.language; + this.htmlPage = options.page; + this._super(parent); + }, + start: function () { + this.htmlPage.on('title-changed', this, this.updateLabel); + this.htmlPage.on('description-changed', this, this.updateLabel); + this.suggestionList = new SuggestionList(this, { + root: this.keyword, + language: this.language, + page: this.htmlPage, + }); + this.suggestionList.on('selected', this, function (word, language) { + this.trigger('selected', word, language); + }); + this.suggestionList.appendTo(this.$('.js_seo_keyword_suggestion')); + }, + analyze: function () { + return analyzeKeyword(this.htmlPage, this.keyword); + }, + highlight: function () { + return this.analyze().title; + }, + tooltip: function () { + return this.analyze().description; + }, + updateLabel: function () { + var cssClass = "oe_seo_keyword js_seo_keyword " + this.highlight(); + this.$(".js_seo_keyword").attr('class', cssClass); + this.$(".js_seo_keyword").attr('title', this.tooltip()); + }, + destroy: function () { + this.trigger('removed'); + this._super(); + }, +}); + +var KeywordList = Widget.extend({ + template: 'website.seo_list', + maxKeywords: 10, + init: function (parent, options) { + this.htmlPage = options.page; + this._super(parent); + }, + start: function () { + var self = this; + var existingKeywords = self.htmlPage.keywords(); + if (existingKeywords.length > 0) { + _.each(existingKeywords, function (word) { + self.add.call(self, word); + }); + } + }, + keywords: function () { + var result = []; + this.$('.js_seo_keyword').each(function () { + result.push($(this).data('keyword')); + }); + return result; + }, + isFull: function () { + return this.keywords().length >= this.maxKeywords; + }, + exists: function (word) { + return _.contains(this.keywords(), word); + }, + add: function (candidate, language) { + var self = this; + // TODO Refine + var word = candidate ? candidate.replace(/[,;.:<>]+/g, " ").replace(/ +/g, " ").trim().toLowerCase() : ""; + if (word && !self.isFull() && !self.exists(word)) { + var keyword = new Keyword(self, { + word: word, + language: language, + page: this.htmlPage, + }); + keyword.on('removed', self, function () { + self.trigger('list-not-full'); + self.trigger('removed', word); + self.trigger('content-updated', true); + }); + keyword.on('selected', self, function (word, language) { + self.trigger('selected', word, language); + }); + keyword.appendTo(self.$el); + } + if (self.isFull()) { + self.trigger('list-full'); + } + self.trigger('content-updated'); + }, +}); + +var Image = Widget.extend({ + template: 'website.seo_image', + init: function (parent, options) { + this.src = options.src; + this.alt = options.alt; + this._super(parent); + }, +}); + +var ImageList = Widget.extend({ + init: function (parent, options) { + this.htmlPage = options.page; + this._super(parent); + }, + start: function () { + var self = this; + this.htmlPage.images().each(function (index, image) { + new Image(self, image).appendTo(self.$el); + }); + }, + images: function () { + var result = []; + this.$('input').each(function () { + var $input = $(this); + result.push({ + src: $input.attr('src'), + alt: $input.val(), + }); + }); + return result; + }, + add: function (image) { + new Image(this, image).appendTo(this.$el); + }, +}); + +var Preview = 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); + }, +}); + +var HtmlPage = Class.extend(mixins.PropertiesMixin, { + url: function () { + var url = window.location.href; + var hashIndex = url.indexOf('#'); + return hashIndex >= 0 ? url.substring(0, hashIndex) : url; + }, + title: function () { + var $title = $('title'); + return ($title.length > 0) && $title.text() && $title.text().trim(); + }, + changeTitle: function (title) { + // TODO create tag if missing + $('title').text(title); + this.trigger('title-changed', title); + }, + description: function () { + var $description = $('meta[name=description]'); + return ($description.length > 0) && ($description.attr('content') && $description.attr('content').trim()); + }, + changeDescription: function (description) { + // TODO create tag if missing + $('meta[name=description]').attr('content', description); + this.trigger('description-changed', description); + }, + keywords: function () { + var $keywords = $('meta[name=keywords]'); + var parsed = ($keywords.length > 0) && $keywords.attr('content') && $keywords.attr('content').split(","); + return (parsed && parsed[0]) ? parsed: []; + }, + changeKeywords: function (keywords) { + // TODO create tag if missing + $('meta[name=keywords]').attr('content', keywords.join(",")); + this.trigger('keywords-changed', keywords); + }, + headers: function (tag) { + return $('#wrap '+tag).map(function () { + return $(this).text(); + }); + }, + images: function () { + return $('#wrap img').map(function () { + var $img = $(this); + return { + src: $img.attr('src'), + alt: $img.attr('alt'), + }; + }); + }, + company: function () { + return $('html').attr('data-oe-company-name'); + }, + bodyText: function () { + return $('body').children().not('.js_seo_configuration').text(); + }, + isInBody: function (text) { + return new RegExp(WORD_SEPARATORS_REGEX+text+WORD_SEPARATORS_REGEX, "gi").test(this.bodyText()); + }, + isInTitle: function (text) { + return new RegExp(WORD_SEPARATORS_REGEX+text+WORD_SEPARATORS_REGEX, "gi").test(this.title()); + }, + isInDescription: function (text) { + return new RegExp(WORD_SEPARATORS_REGEX+text+WORD_SEPARATORS_REGEX, "gi").test(this.description()); + }, +}); + +var Tip = Widget.extend({ + template: 'website.seo_tip', + events: { + 'closed.bs.alert': 'destroy', + }, + init: function (parent, options) { + this.message = options.message; + // cf. http://getbootstrap.com/components/#alerts + // success, info, warning or danger + this.type = options.type || 'info'; + this._super(parent); + }, +}); + +var Configurator = Dialog.extend({ + template: 'website.seo_configuration', + events: { + 'keyup input[name=seo_page_keywords]': 'confirmKeyword', + 'blur input[name=seo_page_title]': 'titleChanged', + 'blur textarea[name=seo_page_description]': 'descriptionChanged', + 'click button[data-action=add]': 'addKeyword', + }, + canEditTitle: false, + canEditDescription: false, + canEditKeywords: false, + canEditLanguage: false, + maxTitleSize: 65, + maxDescriptionSize: 160, // TODO master: remove me and add warning + + init: function (parent, options) { + options = options || {}; + _.defaults(options, { + title: _t('Promote This Page'), + subtitle: _t('Get this page efficiently referenced in Google to attract more visitors.'), + buttons: [ + {text: _t('Save'), classes: 'btn-primary', click: this.update}, + {text: _t('Discard'), close: true}, + ], + }); + + this._super(parent, options); + }, + start: function () { + var self = this; + + this.$modal.addClass('oe_seo_configuration js_seo_configuration'); + + this.htmlPage = new HtmlPage(); + this.$('.js_seo_page_url').text(this.htmlPage.url()); + this.$('input[name=seo_page_title]').val(this.htmlPage.title()); + this.$('textarea[name=seo_page_description]').val(this.htmlPage.description()); + + this.keywordList = new KeywordList(self, { page: this.htmlPage }); + this.keywordList.on('list-full', self, function () { + self.$('input[name=seo_page_keywords]').attr({ + readonly: "readonly", + placeholder: "Remove a keyword first" + }); + self.$('button[data-action=add]').prop('disabled', true).addClass('disabled'); + }); + this.keywordList.on('list-not-full', self, function () { + self.$('input[name=seo_page_keywords]').removeAttr('readonly').attr('placeholder', ""); + self.$('button[data-action=add]').prop('disabled', false).removeClass('disabled'); + }); + this.keywordList.on('selected', self, function (word, language) { + self.keywordList.add(word, language); + }); + this.keywordList.on('content-updated', self, function (removed) { + self.updateTable(removed); + }); + this.keywordList.insertAfter(this.$('.table thead')); + this.disableUnsavableFields(); + this.renderPreview(); + this.getLanguages(); + this.updateTable(); + }, + getLanguages: function () { + var self = this; + ajax.jsonRpc('/web/dataset/call_kw', 'call', { + model: 'website', + method: 'get_languages', + args: [[base.get_context().website_id]], + kwargs: {context: base.get_context()} + }).then( function (data) { + self.$('#language-box').html(core.qweb.render('Configurator.language_promote', { + 'language': data, + 'def_lang': base.get_context().lang + })); + }); + }, + disableUnsavableFields: function () { + var self = this; + this.loadMetaData().then(function (data) { + self.canEditTitle = data && ('website_meta_title' in data); + self.canEditDescription = data && ('website_meta_description' in data); + self.canEditKeywords = data && ('website_meta_keywords' in data); + if (!self.canEditTitle) { + self.$('input[name=seo_page_title]').attr('disabled', true); + } + if (!self.canEditDescription) { + self.$('textarea[name=seo_page_description]').attr('disabled', true); + } + if (!self.canEditTitle && !self.canEditDescription && !self.canEditKeywords) { + self.$footer.find('button[data-action=update]').attr('disabled', true); + } + }); + }, + suggestImprovements: function () { + var self = this; + var tips = []; + _.each(tips, function (tip) { + displayTip(tip.message, tip.type); + }); + + function displayTip(message, type) { + new Tip(self, { + message: message, + type: type, + }).appendTo(self.$('.js_seo_tips')); + } + }, + confirmKeyword: function (e) { + if (e.keyCode == 13) { + this.addKeyword(); + } + }, + addKeyword: function (word) { + var $input = this.$('input[name=seo_page_keywords]'); + var $language = this.$('select[name=seo_page_language]'); + var keyword = _.isString(word) ? word : $input.val(); + var language = $language.val().toLowerCase(); + this.keywordList.add(keyword, language); + $input.val("").focus(); + }, + update: function () { + var self = this; + var data = {}; + if (this.canEditTitle) { + data.website_meta_title = this.htmlPage.title(); + } + if (this.canEditDescription) { + data.website_meta_description = this.htmlPage.description(); + } + if (this.canEditKeywords) { + data.website_meta_keywords = this.keywordList.keywords().join(", "); + } + this.saveMetaData(data).then(function () { + self.close(); + }); + }, + getMainObject: function () { + var repr = $('html').data('main-object'); + var m = repr.match(/(.+)\((\d+),(.*)\)/); + if (!m) { + return null; + } else { + return { + model: m[1], + id: m[2]|0 + }; + } + }, + loadMetaData: function () { + var obj = this.getMainObject(); + var def = $.Deferred(); + if (!obj) { + // return $.Deferred().reject(new Error("No main_object was found.")); + def.resolve(null); + } else { + var fields = ['website_meta_title', 'website_meta_description', 'website_meta_keywords']; + rpc.query({ + model: obj.model, + method: 'read', + args: [[obj.id], fields, base.get_context()], + }).then(function (data) { + if (data.length) { + var meta = data[0]; + meta.model = obj.model; + def.resolve(meta); + } else { + def.resolve(null); + } + }).fail(function () { + def.reject(); + }); + } + return def; + }, + saveMetaData: function (data) { + var obj = this.getMainObject(); + if (!obj) { + return $.Deferred().reject(); + } else { + return rpc.query({ + model: obj.model, + method: 'write', + args: [[obj.id], data, base.get_context()], + }); + } + }, + titleChanged: function () { + var self = this; + _.defer(function () { + var title = self.$('input[name=seo_page_title]').val(); + self.htmlPage.changeTitle(title); + self.renderPreview(); + }); + }, + descriptionChanged: function () { + var self = this; + _.defer(function () { + var description = self.$('textarea[name=seo_page_description]').val(); + self.htmlPage.changeDescription(description); + self.renderPreview(); + }); + }, + renderPreview: function () { + var preview = new 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()); + this._super.apply(this, arguments); + }, + updateTable : function (removed) { + var self = this, + val = removed ? (this.$el.find('tbody > tr').length - 1) : (this.$el.find('tbody > tr').length); + this.$('table').toggleClass('js_seo_has_content', val > 0 ); + this.$el.scrollTop(self.$el[0].scrollHeight); + }, +}); + +website.TopBar.include({ + start: function () { + var self = this; + this.$el.on('click', 'a[data-action=promote-current-page]', function () { + new Configurator(self).open(); + }); + return this._super(); + } +}); + +return { + Configurator: Configurator, +}; + +}); diff --git a/addons/website/static/src/js/menu/translate.js b/addons/website/static/src/js/menu/translate.js new file mode 100644 index 00000000000..c9b7de4ed8b --- /dev/null +++ b/addons/website/static/src/js/menu/translate.js @@ -0,0 +1,104 @@ +odoo.define('website.translator', function (require) { +'use strict'; + +var core = require('web.core'); +var ajax = require('web.ajax'); +var Widget = require('web.Widget'); +var base = require('web_editor.base'); +var translate = require('web_editor.translate'); +var website = require('website.website'); +var local_storage = require('web.local_storage'); +var utils = require('web.utils'); + +var qweb = core.qweb; + +if (!translate.translatable) { + return; +} + + +website.TopBar.include({ + events: _.extend({}, website.TopBar.prototype.events, { + 'click [data-action="edit_master"]': 'edit_master', + 'click [data-action="translate"]': 'translate', + }), + translate: function (ev) { + ev.preventDefault(); + if (translate.edit_translations) { + translate.instance.edit(); + } else { + location.search += '&edit_translations'; + } + }, + edit_master: function (ev) { + ev.preventDefault(); + + var lang = '/' + utils.get_cookie('frontend_lang'); + + var current = document.createElement('a'); + current.href = window.location.toString(); + current.search += (current.search ? '&' : '?') + 'enable_editor=1'; + if (current.pathname.indexOf(lang) === 0) { + current.pathname = current.pathname.replace(lang, ''); + } + + var link = document.createElement('a'); + link.href = '/website/lang/default'; + link.search += (link.search ? '&' : '?') + 'r=' + encodeURIComponent(current.pathname + current.search + current.hash); + + window.location = link.href; + }, +}); + + +if (!translate.edit_translations) { + return; +} + +ajax.loadXML('/website/static/src/xml/website.translator.xml', qweb); + +var nodialog = 'website_translator_nodialog'; + +var Translate = translate.Class.include({ + onTranslateReady: function () { + if(this.gengo_translate) { + this.translation_gengo_display(); + } + this._super(); + }, + edit: function () { + $("#oe_main_menu_navbar").hide(); + if (!local_storage.getItem(nodialog)) { + var dialog = new TranslatorDialog(); + dialog.appendTo($(document.body)); + dialog.on('activate', this, function () { + if (dialog.$('input[name=do_not_show]').prop('checked')) { + local_storage.removeItem(nodialog); + } else { + local_storage.setItem(nodialog, true); + } + dialog.$el.modal('hide'); + }); + } + return this._super(); + }, + cancel: function () { + $("#oe_main_menu_navbar").show(); + return this._super(); + } +}); + +var TranslatorDialog = Widget.extend({ + events: _.extend({}, website.TopBar.prototype.events, { + 'hidden.bs.modal': 'destroy', + 'click button[data-action=activate]': function (ev) { + this.trigger('activate'); + }, + }), + template: 'website.TranslatorDialog', + start: function () { + this.$el.modal(); + }, +}); + +}); |
