summaryrefslogtreecommitdiff
path: root/addons/website/static/src/js/website.seo.js
diff options
context:
space:
mode:
authorqsm-odoo <qsm@odoo.com>2017-06-07 17:45:15 +0200
committerqsm-odoo <qsm@odoo.com>2017-08-16 10:59:39 +0200
commit4f925af06fd3cebfcfb56eb947ab68c8a2ca4490 (patch)
treeb13bd049b6b3e7bbdfb537d19b53c95fc4025ea5 /addons/website/static/src/js/website.seo.js
parentf205bfcd4ddcf3f1d8676ee87ee0b29941bd6773 (diff)
[MOV] web_editor, website: reorganize files
Diffstat (limited to 'addons/website/static/src/js/website.seo.js')
-rw-r--r--addons/website/static/src/js/website.seo.js582
1 files changed, 0 insertions, 582 deletions
diff --git a/addons/website/static/src/js/website.seo.js b/addons/website/static/src/js/website.seo.js
deleted file mode 100644
index 93b434a5f44..00000000000
--- a/addons/website/static/src/js/website.seo.js
+++ /dev/null
@@ -1,582 +0,0 @@
-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,
-};
-
-});