Files
odoo_source/addons/website_links/static/src/js/website_links.js
T
Romain Derie c78da8a80d [FIX] website_links: fix multiple bugs + add tests
Commit 6d67ce5b7c refactored the JS from multiple website modules including
`website_links`.
A few error needed to be fixed:
  - recent links would not appear anymore
  - graphs would not be displayed anymore
  - graph resize on tab change would not be fired

This commit fixes it and also add some tests to be sure this module is now
strongly tested.

Note: tests are skipped for now as there is a race condition happening only
      with docker and this fix is getting urgent for Odoo.com

closes odoo/odoo#31507

Signed-off-by: Romain Derie (rde) <rde@odoo.com>
2019-03-11 12:40:32 +00:00

534 lines
16 KiB
JavaScript

odoo.define('website_links.website_links', function (require) {
'use strict';
var core = require('web.core');
var Widget = require('web.Widget');
var sAnimations = require('website.content.snippets.animation');
var _t = core._t;
var SelectBox = Widget.extend({
events: {
'change': '_onChange',
},
/**
* @constructor
* @param {Object} parent
* @param {Object} obj
* @param {String} placeholder
*/
init: function (parent, obj, placeholder) {
this._super.apply(this, arguments);
this.obj = obj;
this.placeholder = placeholder;
},
/**
* @override
*/
willStart: function () {
var self = this;
var defs = [this._super.apply(this, arguments)];
defs.push(this._rpc({
model: this.obj,
method: 'search_read',
}).then(function (result) {
self.objects = _.map(result, function (val) {
return {id: val.id, text: val.name};
});
}));
return $.when.apply($, defs);
},
/**
* @override
*/
start: function () {
var self = this;
this.$el.select2({
placeholder: self.placeholder,
allowClear: true,
createSearchChoice: function (term) {
if (self._objectExists(term)) {
return null;
}
return {id: term, text: _.str.sprintf("Create '%s'", term)};
},
createSearchChoicePosition: 'bottom',
multiple: false,
data: self.objects,
});
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* @private
* @param {String} query
*/
_objectExists: function (query) {
return _.find(this.objects, function (val) {
return val.text.toLowerCase() === query.toLowerCase();
}) !== undefined;
},
/**
* @private
* @param {String} name
*/
_createObject: function (name) {
var self = this;
return this._rpc({
model: this.obj,
method: 'create',
args: [{name: name}],
}).then(function (record) {
self.$el.attr('value', record);
self.objects.push({'id': record, 'text': name});
});
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @private
* @param {Object} ev
*/
_onChange: function (ev) {
if (!ev.added || !_.isString(ev.added.id)) {
return;
}
this._createObject(ev.added.id);
},
});
var RecentLinkBox = Widget.extend({
template: 'website_links.RecentLink',
xmlDependencies: ['/website_links/static/src/xml/recent_link.xml'],
events: {
'click .btn_shorten_url_clipboard': '_toggleCopyButton',
'click .o_website_links_edit_code': '_editCode',
'click .o_website_links_ok_edit': '_onLinksOkClick',
'click .o_website_links_cancel_edit': '_onLinksCancelClick',
'submit #o_website_links_edit_code_form': '_onSubmitCode',
},
/**
* @constructor
* @param {Object} parent
* @param {Object} obj
*/
init: function (parent, obj) {
this._super.apply(this, arguments);
this.link_obj = obj;
this.animating_copy = false;
},
/**
* @override
*/
start: function () {
new ClipboardJS(this.$('.btn_shorten_url_clipboard').get(0));
return this._super.apply(this, arguments);
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* @private
*/
_toggleCopyButton: function () {
if (this.animating_copy) {
return;
}
var self = this;
this.animating_copy = true;
var top = this.$('.o_website_links_short_url').position().top;
this.$('.o_website_links_short_url').clone()
.css('position', 'absolute')
.css('left', 15)
.css('top', top - 2)
.css('z-index', 2)
.removeClass('o_website_links_short_url')
.addClass('animated-link')
.insertAfter(this.$('.o_website_links_short_url'))
.animate({
opacity: 0,
top: '-=20',
}, 500, function () {
self.$('.animated-link').remove();
self.animating_copy = false;
});
},
/**
* @private
* @param {String} message
*/
_notification: function (message) {
this.$('.notification').append('<strong>' + message + '</strong>');
},
/**
* @private
*/
_editCode: function () {
var initCode = this.$('#o_website_links_code').html();
this.$('#o_website_links_code').html('<form style="display:inline;" id="o_website_links_edit_code_form"><input type="hidden" id="init_code" value="' + initCode + '"/><input type="text" id="new_code" value="' + initCode + '"/></form>');
this.$('.o_website_links_edit_code').hide();
this.$('.copy-to-clipboard').hide();
this.$('.o_website_links_edit_tools').show();
},
/**
* @private
*/
_cancelEdit: function () {
this.$('.o_website_links_edit_code').show();
this.$('.copy-to-clipboard').show();
this.$('.o_website_links_edit_tools').hide();
this.$('.o_website_links_code_error').hide();
var oldCode = this.$('#o_website_links_edit_code_form #init_code').val();
this.$('#o_website_links_code').html(oldCode);
this.$('#code-error').remove();
this.$('#o_website_links_code form').remove();
},
/**
* @private
*/
_submitCode: function () {
var self = this;
var initCode = this.$('#o_website_links_edit_code_form #init_code').val();
var newCode = this.$('#o_website_links_edit_code_form #new_code').val();
if (newCode === '') {
self.$('.o_website_links_code_error').html(_t("The code cannot be left empty"));
self.$('.o_website_links_code_error').show();
return;
}
function showNewCode(newCode) {
self.$('.o_website_links_code_error').html('');
self.$('.o_website_links_code_error').hide();
self.$('#o_website_links_code form').remove();
// Show new code
var host = self.$('#o_website_links_host').html();
self.$('#o_website_links_code').html(newCode);
// Update button copy to clipboard
self.$('.btn_shorten_url_clipboard').attr('data-clipboard-text', host + newCode);
// Show action again
self.$('.o_website_links_edit_code').show();
self.$('.copy-to-clipboard').show();
self.$('.o_website_links_edit_tools').hide();
}
if (initCode === newCode) {
showNewCode(newCode);
} else {
this._rpc({
route: '/website_links/add_code',
params: {
init_code: initCode,
new_code: newCode,
},
}).then(function (result) {
showNewCode(result[0].code);
}, function () {
self.$('.o_website_links_code_error').show();
self.$('.o_website_links_code_error').html(_t("This code is already taken"));
});
}
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @private
* @param {Event} ev
*/
_onLinksOkClick: function (ev) {
ev.preventDefault();
this._submitCode();
},
/**
* @private
* @param {Event} ev
*/
_onLinksCancelClick: function (ev) {
ev.preventDefault();
this._cancelEdit();
},
/**
* @private
* @param {Event} ev
*/
_onSubmitCode: function (ev) {
ev.preventDefault();
this._submitCode();
},
});
var RecentLinks = Widget.extend({
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* @private
*/
getRecentLinks: function (filter) {
var self = this;
return this._rpc({
route: '/website_links/recent_links',
params: {
filter: filter,
limit: 20,
},
}).then(function (result) {
_.each(result.reverse(), function (link) {
self._addLink(link);
});
self._updateNotification();
}, function () {
var message = _t("Unable to get recent links");
self.$el.append('<div class="alert alert-danger">' + message + '</div>');
});
},
/**
* @private
*/
_addLink: function (link) {
var nbLinks = this.getChildren().length;
var recentLinkBox = new RecentLinkBox(this, link);
recentLinkBox.prependTo(this.$el);
$('.link-tooltip').tooltip();
if (nbLinks === 0) {
this._updateNotification();
}
},
/**
* @private
*/
removeLinks: function () {
_.invoke(this.getChildren(), 'destroy');
},
/**
* @private
*/
_updateNotification: function () {
if (this.getChildren().length === 0) {
var message = _t("You don't have any recent links.");
$('.o_website_links_recent_links_notification').html('<div class="alert alert-info">' + message + '</div>');
} else {
$('.o_website_links_recent_links_notification').empty();
}
},
});
sAnimations.registry.websiteLinks = sAnimations.Class.extend({
selector: '.o_website_links_create_tracked_url',
read_events: {
'click #filter-newest-links': '_onFilterNewestLinksClick',
'click #filter-most-clicked-links': '_onFilterMostClickedLinksClick',
'click #filter-recently-used-links': '_onFilterRecentlyUsedLinksClick',
'click #generated_tracked_link a': '_onGeneratedTrackedLinkClick',
'keyup #url': '_onUrlKeyUp',
'click #btn_shorten_url': '_onShortenUrlButtonClick',
'submit #o_website_links_link_tracker_form': '_onFormSubmit',
},
/**
* @override
*/
start: function () {
var defs = [this._super.apply(this, arguments)];
// UTMS selects widgets
var campaignSelect = new SelectBox(this, 'utm.campaign', _t("e.g. Promotion of June, Winter Newsletter, .."));
defs.push(campaignSelect.attachTo($('#campaign-select')));
var mediumSelect = new SelectBox(this, 'utm.medium', _t("e.g. Newsletter, Social Network, .."));
defs.push(mediumSelect.attachTo($('#channel-select')));
var sourceSelect = new SelectBox(this, 'utm.source', _t("e.g. Search Engine, Website page, .."));
defs.push(sourceSelect.attachTo($('#source-select')));
// Recent Links Widgets
this.recentLinks = new RecentLinks(this);
defs.push(this.recentLinks.appendTo($('#o_website_links_recent_links')));
this.recentLinks.getRecentLinks('newest');
// Clipboard Library
new ClipboardJS($('#btn_shorten_url').get(0));
this.url_copy_animating = false;
$('[data-toggle="tooltip"]').tooltip();
return $.when.apply($, defs);
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @private
*/
_onFilterNewestLinksClick: function () {
this.recentLinks.removeLinks();
this.recentLinks.getRecentLinks('newest');
},
/**
* @private
*/
_onFilterMostClickedLinksClick: function () {
this.recentLinks.removeLinks();
this.recentLinks.getRecentLinks('most-clicked');
},
/**
* @private
*/
_onFilterRecentlyUsedLinksClick: function () {
this.recentLinks.removeLinks();
this.recentLinks.getRecentLinks('recently-used');
},
/**
* @private
*/
_onGeneratedTrackedLinkClick: function () {
$('#generated_tracked_link a').text(_t("Copied")).removeClass('btn-primary').addClass('btn-success');
setTimeout(function () {
$('#generated_tracked_link a').text(_t("Copy")).removeClass('btn-success').addClass('btn-primary');
}, 5000);
},
/**
* @private
* @param {Event} ev
*/
_onUrlKeyUp: function (ev) {
if (!$('#btn_shorten_url').hasClass('btn-copy') || ev.which === 13) {
return;
}
$('#btn_shorten_url').removeClass('btn-success btn-copy').addClass('btn-primary').html('Get tracked link');
$('#generated_tracked_link').css('display', 'none');
$('.o_website_links_utm_forms').show();
},
/**
* @private
*/
_onShortenUrlButtonClick: function () {
if (!$('#btn_shorten_url').hasClass('btn-copy') || this.url_copy_animating) {
return;
}
var self = this;
this.url_copy_animating = true;
$('#generated_tracked_link').clone()
.css('position', 'absolute')
.css('left', '78px')
.css('bottom', '8px')
.css('z-index', 2)
.removeClass('#generated_tracked_link')
.addClass('url-animated-link')
.appendTo($('#generated_tracked_link'))
.animate({
opacity: 0,
bottom: '+=20',
}, 500, function () {
$('.url-animated-link').remove();
self.url_copy_animating = false;
});
},
/**
* Add the RecentLinkBox widget and send the form when the user generate the link
*
* @private
* @param {Event} ev
*/
_onFormSubmit: function (ev) {
var self = this;
ev.preventDefault();
if ($('#btn_shorten_url').hasClass('btn-copy')) {
return;
}
ev.stopPropagation();
// Get URL and UTMs
var campaignID = $('#campaign-select').attr('value');
var mediumID = $('#channel-select').attr('value');
var sourceID = $('#source-select').attr('value');
var params = {};
params.url = $('#url').val();
if (campaignID !== '') {
params.campaign_id = parseInt(campaignID);
}
if (mediumID !== '') {
params.medium_id = parseInt(mediumID);
}
if (sourceID !== '') {
params.source_id = parseInt(sourceID);
}
$('#btn_shorten_url').text(_t("Generating link..."));
this._rpc({
route: '/website_links/new',
params: params,
}).then(function (result) {
if ('error' in result) {
// Handle errors
if (result.error === 'empty_url') {
$('.notification').html('<div class="alert alert-danger">The URL is empty.</div>');
} else if (result.error === 'url_not_found') {
$('.notification').html('<div class="alert alert-danger">URL not found (404)</div>');
} else {
$('.notification').html('<div class="alert alert-danger">An error occur while trying to generate your link. Try again later.</div>');
}
} else {
// Link generated, clean the form and show the link
var link = result[0];
$('#btn_shorten_url').removeClass('btn-primary').addClass('btn-success btn-copy').html('Copy');
$('#btn_shorten_url').attr('data-clipboard-text', link.short_url);
$('.notification').html('');
$('#generated_tracked_link').html(link.short_url);
$('#generated_tracked_link').css('display', 'inline');
self.recentLinks._addLink(link);
// Clean URL and UTM selects
$('#campaign-select').select2('val', '');
$('#channel-select').select2('val', '');
$('#source-select').select2('val', '');
$('.o_website_links_utm_forms').hide();
}
});
},
});
return {
SelectBox: SelectBox,
RecentLinkBox: RecentLinkBox,
RecentLinks: RecentLinks,
};
});