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>
534 lines
16 KiB
JavaScript
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,
|
|
};
|
|
});
|