[REF] website_links: reorganize javascript

This commit is contained in:
Andrea Ulliana
2018-11-28 09:49:09 +00:00
committed by qsm-odoo
parent 2cdcdedef6
commit 1eab58bdbd
5 changed files with 847 additions and 642 deletions
@@ -1,266 +1,364 @@
odoo.define('website_links.website_links', function (require) {
'use strict';
require('web.dom_ready');
var sAnimations = require('website.content.snippets.animation');
var ajax = require('web.ajax');
var core = require('web.core');
var rpc = require('web.rpc');
var Widget = require('web.Widget');
var base = require('web_editor.base');
var weContext = require('web_editor.context');
var qweb = core.qweb;
var _t = core._t;
var exports = {};
if (!$('.o_website_links_create_tracked_url').length) {
return $.Deferred().reject("DOM doesn't contain '.o_website_links_create_tracked_url'");
}
var SelectBox = Widget.extend({
xmlDependencies: ['/website_links/static/src/xml/recent_link.xml'],
/**
* @override
* @param {Object} obj
*/
init: function (obj) {
this.obj = obj;
},
/**
* @override
* @param {Object} parent
* @param {Object} element
* @param {String} placeholder
*/
start: function (element, placeholder, parent) {
var self = this;
this.element = element;
this.placeholder = placeholder;
var SelectBox = Widget.extend({
init: function (obj) {
this.obj = obj;
},
start: function (element, placeholder) {
var self = this;
this.element = element;
this.placeholder = placeholder;
this._fetchObjects().then(function (results) {
self.objects = results;
this.fetch_objects().then(function (results) {
self.objects = results;
element.select2({
placeholder: self.placeholder,
allowClear: true,
createSearchChoice: function (term) {
if (self._objectExists(term)) { return null; }
element.select2({
placeholder: self.placeholder,
allowClear: true,
createSearchChoice: function (term) {
if (self.object_exists(term)) { return null; }
return {id:term, text:_.str.sprintf("Create '%s'", term)};
},
createSearchChoicePosition: 'bottom',
multiple: false,
data: self.objects,
});
return {id:term, text:_.str.sprintf("Create '%s'", term)};
},
createSearchChoicePosition: 'bottom',
multiple: false,
data: self.objects,
});
element.on('change', function (e) {
self._onChange(e);
});
});
},
element.on('change', function (e) {
self.on_change(e);
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* @private
*/
_fetchObjects: function () {
return this._rpc({
model: this.obj,
method: 'search_read',
})
.then(function (result) {
return _.map(result, function (val) {
return {id: val.id, text:val.name};
});
});
},
/**
* @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.element.attr('value', record);
self.objects.push({'id': record, 'text': name});
});
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @override
* @param {Object} e
*/
_onChange: function (e) {
if (e.added && _.isString(e.added.id)) {
this._createObject(e.added.id);
}
},
});
var RecentLinkBox = Widget.extend({
template: 'website_links.RecentLink',
events: {
'click .btn_shorten_url_clipboard':'_toggleCopyButton',
'click .o_website_links_edit_code':'_editCode',
'click .o_website_links_ok_edit':function (e) {
e.preventDefault();
this._submitCode();
},
fetch_objects: function () {
return rpc.query({
model: this.obj,
method: 'search_read',
context: weContext.get(), // TODO use this._rpc
})
.then(function (result) {
return _.map(result, function (val) {
return {id: val.id, text:val.name};
});
'click .o_website_links_cancel_edit': function (e) {
e.preventDefault();
this._cancelEdit();
},
'submit #o_website_links_edit_code_form': function (e) {
e.preventDefault();
this._submitCode();
},
},
/**
* @override
* @param {Object} obj
*/
init: function (parent, link_obj) {
this._super(parent);
this.link_obj = link_obj;
this.animating_copy = false;
},
/**
* @override
* @param {Object} parent
* @param {Object} element
* @param {String} placeholder
*/
start: function (element, placeholder, parent) {
new ClipboardJS(this.$('.btn_shorten_url_clipboard').get(0));
return this._super.apply(this, arguments);
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* @private
* @param {String} query
*/
_toggleCopyButton: function () {
var self = this;
if (!this.animating_copy) {
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;
});
},
object_exists: function (query) {
return _.find(this.objects, function (val) {
return val.text.toLowerCase() === query.toLowerCase();
}) !== undefined;
},
on_change: function (e) {
if (e.added && _.isString(e.added.id)) {
this.create_object(e.added.id);
}
},
create_object: function (name) {
var self = this;
}
},
/**
* @private
*/
_remove: function () {
this.getParent().remove_link(this);
},
/**
* @private
* @param {String} message
*/
_notification: function (message) {
this.$('.notification').append('<strong>' + message + '</strong>');
},
/**
* @private
*/
_editCode: function () {
var init_code = 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='" + init_code + "'/><input type='text' id='new_code' value='" + init_code + "'/></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();
return rpc.query({
model: this.obj,
method: 'create',
args: [{name:name}],
context: weContext.get(), // TODO use this._rpc
})
.then(function (record) {
self.element.attr('value', record);
self.objects.push({'id': record, 'text': name});
});
},
});
var old_code = this.$('#o_website_links_edit_code_form #init_code').val();
this.$('#o_website_links_code').html(old_code);
var RecentLinkBox = Widget.extend({
template: 'website_links.RecentLink',
events: {
'click .btn_shorten_url_clipboard':'toggle_copy_button',
'click .o_website_links_edit_code':'edit_code',
'click .o_website_links_ok_edit':function (e) {
e.preventDefault();
this.submit_code();
},
'click .o_website_links_cancel_edit': function (e) {
e.preventDefault();
this.cancel_edit();
},
'submit #o_website_links_edit_code_form': function (e) {
e.preventDefault();
this.submit_code();
},
},
init: function (parent, link_obj) {
this._super(parent);
this.link_obj = link_obj;
this.animating_copy = false;
},
start: function () {
new ClipboardJS(this.$('.btn_shorten_url_clipboard').get(0));
return this._super.apply(this, arguments);
},
toggle_copy_button: function () {
var self = this;
this.$('#code-error').remove();
this.$('#o_website_links_code form').remove();
},
/**
* @private
*/
_submitCode: function () {
var self = this;
if (!this.animating_copy) {
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;
});
}
},
remove: function () {
this.getParent().remove_link(this);
},
notification: function (message) {
this.$('.notification').append('<strong>' + message + '</strong>');
},
edit_code: function () {
var init_code = this.$('#o_website_links_code').html();
var init_code = this.$('#o_website_links_edit_code_form #init_code').val();
var new_code = this.$('#o_website_links_edit_code_form #new_code').val();
this.$('#o_website_links_code').html("<form style='display:inline;' id='o_website_links_edit_code_form'><input type='hidden' id='init_code' value='" + init_code + "'/><input type='text' id='new_code' value='" + init_code + "'/></form>");
this.$('.o_website_links_edit_code').hide();
this.$('.copy-to-clipboard').hide();
this.$('.o_website_links_edit_tools').show();
},
cancel_edit: 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();
if (new_code === '') {
self.$('.o_website_links_code_error').html("The code cannot be left empty");
self.$('.o_website_links_code_error').show();
return;
}
var old_code = this.$('#o_website_links_edit_code_form #init_code').val();
this.$('#o_website_links_code').html(old_code);
function ShowNewCode(new_code) {
self.$('.o_website_links_code_error').html('');
self.$('.o_website_links_code_error').hide();
this.$('#code-error').remove();
this.$('#o_website_links_code form').remove();
},
submit_code: function () {
var self = this;
self.$('#o_website_links_code form').remove();
var init_code = this.$('#o_website_links_edit_code_form #init_code').val();
var new_code = this.$('#o_website_links_edit_code_form #new_code').val();
// Show new code
var host = self.$('#o_website_links_host').html();
self.$('#o_website_links_code').html(new_code);
if (new_code === '') {
self.$('.o_website_links_code_error').html("The code cannot be left empty");
self.$('.o_website_links_code_error').show();
return;
}
// Update button copy to clipboard
self.$('.btn_shorten_url_clipboard').attr('data-clipboard-text', host + new_code);
function show_new_code(new_code) {
self.$('.o_website_links_code_error').html('');
self.$('.o_website_links_code_error').hide();
// Show action again
self.$('.o_website_links_edit_code').show();
self.$('.copy-to-clipboard').show();
self.$('.o_website_links_edit_tools').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(new_code);
// Update button copy to clipboard
self.$('.btn_shorten_url_clipboard').attr('data-clipboard-text', host + new_code);
// Show action again
self.$('.o_website_links_edit_code').show();
self.$('.copy-to-clipboard').show();
self.$('.o_website_links_edit_tools').hide();
}
if (init_code === new_code) {
show_new_code(new_code);
}
else {
ajax.jsonRpc('/website_links/add_code', 'call', {'init_code':init_code, 'new_code':new_code})
.then(function (result) {
show_new_code(result[0].code);
})
.fail(function () {
self.$('.o_website_links_code_error').show();
self.$('.o_website_links_code_error').html("This code is already taken");
}) ;
}
},
});
var RecentLinks = Widget.extend({
init: function () {
this._super();
},
get_recent_links: function (filter) {
var self = this;
ajax.jsonRpc('/website_links/recent_links', 'call', {'filter':filter, 'limit':20})
if (init_code === new_code) {
ShowNewCode(new_code);
}
else {
ajax.jsonRpc('/website_links/add_code', 'call', {'init_code':init_code, 'new_code':new_code})
.then(function (result) {
_.each(result.reverse(), function (link) {
self.add_link(link);
});
self.update_notification();
ShowNewCode(result[0].code);
})
.fail(function () {
var message = _t("Unable to get recent links");
self.$el.append("<div class='alert alert-danger'>" + message + "</div>");
self.$('.o_website_links_code_error').show();
self.$('.o_website_links_code_error').html("This code is already taken");
}) ;
}
},
});
var RecentLinks = Widget.extend({
/**
* @override
*/
init: function () {
this._super();
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* @private
*/
_getRecentLinks: function (filter) {
var self = this;
ajax.jsonRpc('/website_links/recent_links', 'call', {'filter':filter, 'limit':20})
.then(function (result) {
_.each(result.reverse(), function (link) {
self._addLink(link);
});
},
add_link: function (link) {
var nb_links = this.getChildren().length;
var recent_link_box = new RecentLinkBox(this, link);
recent_link_box.prependTo(this.$el);
$('.link-tooltip').tooltip();
self._updateNotification();
})
.fail(function () {
var message = _t("Unable to get recent links");
self.$el.append("<div class='alert alert-danger'>" + message + "</div>");
});
},
/**
* @private
*/
_addLink: function (link) {
var nb_links = this.getChildren().length;
var recent_link_box = new RecentLinkBox(this, link);
recent_link_box.prependTo(this.$el);
$('.link-tooltip').tooltip();
if (nb_links === 0) {
this.update_notification();
}
},
remove_links: function () {
_.invoke(this.getChildren(), 'remove');
},
remove_link: function (link) {
link.destroy();
},
update_notification: 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();
}
},
});
if (nb_links === 0) {
this._updateNotification();
}
},
/**
* @private
*/
_removeLinks: function () {
$('#o_website_links_recent_links .link-row').each(function () {
this.remove();
});
},
/**
* @private
*/
_removeLink: function (link) {
link.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();
}
},
ajax.loadXML('/website_links/static/src/xml/recent_link.xml', qweb);
});
base.ready().done(function () {
sAnimations.registry.websiteLinks = sAnimations.Class.extend({
selector: '.o_website_links_create_tracked_url',
read_events: {
'click #filter-newest-links': '_onFilterNewestLinks',
'click #filter-most-clicked-links': '_onFilterMostClickedLinks',
'click #filter-recently-used-links': '_onFilterRecentlyUsedLinks',
'click #generated_tracked_link a': '_onGeneratedTrackedLink',
'keyup #url': '_onUrlKeyUp',
'click #btn_shorten_url': '_onBtnShortenUrl',
'submit #o_website_links_link_tracker_form': '_onSubmitForm'
},
/**
* @override
* @param {Object} parent
*/
start: function (parent) {
// UTMS selects widgets
var campaign_select = new SelectBox('utm.campaign');
campaign_select.start($("#campaign-select"), _t('e.g. Promotion of June, Winter Newsletter, ..'));
@@ -272,137 +370,162 @@ if (!$('.o_website_links_create_tracked_url').length) {
source_select.start($("#source-select"), _t('e.g. Search Engine, Website page, ..'));
// Recent Links Widgets
var recent_links = new RecentLinks();
recent_links.appendTo($("#o_website_links_recent_links"));
recent_links.get_recent_links('newest');
$('#filter-newest-links').click(function () {
recent_links.remove_links();
recent_links.get_recent_links('newest');
});
$('#filter-most-clicked-links').click(function () {
recent_links.remove_links();
recent_links.get_recent_links('most-clicked');
});
$('#filter-recently-used-links').click(function () {
recent_links.remove_links();
recent_links.get_recent_links('recently-used');
});
this.recent_links = new RecentLinks();
this.recent_links.appendTo($("#o_website_links_recent_links"));
this.recent_links._getRecentLinks('newest');
// Clipboard Library
new ClipboardJS($("#btn_shorten_url").get(0));
$("#generated_tracked_link a").click(function () {
$("#generated_tracked_link a").text("Copied").removeClass("btn-primary").addClass("btn-success");
setTimeout(function () {
$("#generated_tracked_link a").text("Copy").removeClass("btn-success").addClass("btn-primary");
}, '5000');
});
$('#url').on('keyup', function (e) {
if ($('#btn_shorten_url').hasClass('btn-copy') && e.which !== 13) {
$('#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();
}
});
var url_copy_animating = false;
$('#btn_shorten_url').click(function () {
if ($('#btn_shorten_url').hasClass('btn-copy')) {
if (!url_copy_animating) {
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();
url_copy_animating = false;
});
}
}
});
// Add the RecentLinkBox widget and send the form when the user generate the link
$("#o_website_links_link_tracker_form").submit(function (event) {
if ($('#btn_shorten_url').hasClass('btn-copy')) {
event.preventDefault();
return;
}
event.preventDefault();
event.stopPropagation();
// Get URL and UTMs
var campaign_id = $('#campaign-select').attr('value');
var medium_id = $('#channel-select').attr('value');
var source_id = $('#source-select').attr('value');
var params = {};
params.url = $("#url").val();
if (campaign_id !== '') { params.campaign_id = parseInt(campaign_id); }
if (medium_id !== '') { params.medium_id = parseInt(medium_id); }
if (source_id !== '') { params.source_id = parseInt(source_id); }
$('#btn_shorten_url').text(_t('Generating link...'));
ajax.jsonRpc("/website_links/new", 'call', 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');
recent_links.add_link(link);
// Clean URL and UTM selects
$('#campaign-select').select2('val', '');
$('#channel-select').select2('val', '');
$('#source-select').select2('val', '');
$('.o_website_links_utm_forms').hide();
}
});
});
this.url_copy_animating = false;
$(function () {
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="tooltip"]').tooltip();
});
});
},
exports.SelectBox = SelectBox;
exports.RecentLinkBox = RecentLinkBox;
exports.RecentLinks = RecentLinks;
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @override
*/
_onFilterNewestLinks: function () {
this.recent_links._removeLinks();
this.recent_links._getRecentLinks('newest');
},
/**
* @override
*/
_onFilterMostClickedLinks: function () {
this.recent_links._removeLinks();
this.recent_links._getRecentLinks('most-clicked');
},
/**
* @override
*/
_onFilterRecentlyUsedLinks: function () {
this.recent_links._removeLinks();
this.recent_links._getRecentLinks('recently-used');
},
/**
* @override
*/
_onGeneratedTrackedLink: function () {
$("#generated_tracked_link a").text("Copied").removeClass("btn-primary").addClass("btn-success");
setTimeout(function () {
$("#generated_tracked_link a").text("Copy").removeClass("btn-success").addClass("btn-primary");
}, '5000');
},
/**
* @override
* @param {Object} e
*/
_onUrlKeyUp: function (e) {
if ($('#btn_shorten_url').hasClass('btn-copy') && e.which !== 13) {
$('#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();
}
},
/**
* @override
*/
_onBtnShortenUrl: function () {
if ($('#btn_shorten_url').hasClass('btn-copy')) {
if (!this.url_copy_animating) {
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();
this.url_copy_animating = false;
});
}
}
},
/**
* Add the RecentLinkBox widget and send the form when the user generate the link
*
* @override
* @param {Object} ev
*/
_onSubmitForm: function (ev) {
if ($('#btn_shorten_url').hasClass('btn-copy')) {
ev.preventDefault();
return;
}
ev.preventDefault();
ev.stopPropagation();
// Get URL and UTMs
var campaign_id = $('#campaign-select').attr('value');
var medium_id = $('#channel-select').attr('value');
var source_id = $('#source-select').attr('value');
var params = {};
params.url = $("#url").val();
if (campaign_id !== '') { params.campaign_id = parseInt(campaign_id); }
if (medium_id !== '') { params.medium_id = parseInt(medium_id); }
if (source_id !== '') { params.source_id = parseInt(source_id); }
$('#btn_shorten_url').text(_t('Generating link...'));
ajax.jsonRpc("/website_links/new", 'call', 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');
this.recent_links._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();
}
});
},
});
exports.SelectBox = SelectBox;
exports.RecentLinkBox = RecentLinkBox;
exports.RecentLinks = RecentLinks;
return exports;
});
@@ -1,235 +1,199 @@
odoo.define('website_links.charts', function (require) {
'use strict';
require('web.dom_ready');
var rpc = require('web.rpc');
var sAnimations = require('website.content.snippets.animation');
var Widget = require('web.Widget');
var base = require('web_editor.base');
var weContext = require('web_editor.context');
var core = require('web.core');
var _t = core._t;
var exports = {};
if (!$('.o_website_links_chart').length) {
return $.Deferred().reject("DOM doesn't contain '.o_website_links_chart'");
}
var BarChart = Widget.extend({
/**
* @override
* @param {Object} $element
* @param {Object} begin_date
* @param {Object} end_date
* @param {Object} dates
*/
init: function ($element, begin_date, end_date, dates) {
this.$element = $element;
this.begin_date = begin_date;
this.end_date = end_date;
this.number_of_days = this.end_date.diff(this.begin_date, 'days') + 2;
this.dates = dates;
},
/**
* @override
* @param {Object} parent
*/
start: function (parent) {
var self = this;
var BarChart = Widget.extend({
init: function ($element, begin_date, end_date, dates) {
this.$element = $element;
this.begin_date = begin_date;
this.end_date = end_date;
this.number_of_days = this.end_date.diff(this.begin_date, 'days') + 2;
this.dates = dates;
},
start: function () {
var self = this;
// Accessor functions
function getDate(d) { return new Date(d[0]); }
function getNbClicks(d) { return d[1]; }
// Accessor functions
function getDate(d) { return new Date(d[0]); }
function getNbClicks(d) { return d[1]; }
// Prune tick values for visibility purpose
function getPrunedTickValues(ticks, nb_desired_ticks) {
var nb_values = ticks.length;
var keep_one_of = Math.max(1, Math.floor(nb_values / nb_desired_ticks));
// Prune tick values for visibility purpose
function getPrunedTickValues(ticks, nb_desired_ticks) {
var nb_values = ticks.length;
var keep_one_of = Math.max(1, Math.floor(nb_values / nb_desired_ticks));
return _.filter(ticks, function (d, i) {
return i % keep_one_of === 0;
});
}
// Fill data for each day (with 0 click for days without data)
var clicks_array = [];
var begin_date_copy = this.begin_date;
for (var i = 0 ; i < this.number_of_days ; i++) {
var date_key = begin_date_copy.format('YYYY-MM-DD');
clicks_array.push([date_key, (date_key in this.dates) ? this.dates[date_key] : 0]);
begin_date_copy.add(1, 'days');
}
// Set title
var nb_clicks = _.reduce(clicks_array, function (total, val) { return total + val[1] ; }, 0);
$(this.$element + ' .title').html(nb_clicks + _t(' clicks'));
// Fit data into the NVD3 scheme
var chart_data = [{}];
chart_data[0]['key'] = _t('# of clicks');
chart_data[0]['values'] = clicks_array;
nv.addGraph(function () {
var chart = nv.models.lineChart()
.x(function (d) { return getDate(d); })
.y(function (d) { return getNbClicks(d); })
.margin({top: 10, right: 60, bottom: 60, left: 60})
.showYAxis(true)
.showXAxis(true);
// Reduce the number of labels on the X axis for visibility
var tick_values = getPrunedTickValues(chart_data[0]['values'], 10);
chart.xAxis
.tickFormat(function (d) { return d3.time.format("%d/%m/%y")(new Date(d)); })
.tickValues(_.map(tick_values, function (d) { return getDate(d).getTime(); }))
.rotateLabels(55);
chart.yAxis
.tickFormat(d3.format("d"))
.ticks(Math.min(chart_data[0]['values'].length - 1, 10));
d3.select(self.$element + ' svg')
.datum(chart_data)
.call(chart);
return self.chart = chart;
return _.filter(ticks, function (d, i) {
return i % keep_one_of === 0;
});
},
});
}
var PieChart = Widget.extend({
init: function ($element, data) {
this.data = data;
this.$element = $element;
},
start: function () {
var self = this;
// Fill data for each day (with 0 click for days without data)
var clicks_array = [];
var begin_date_copy = this.begin_date;
for (var i = 0 ; i < this.number_of_days ; i++) {
var date_key = begin_date_copy.format('YYYY-MM-DD');
clicks_array.push([date_key, (date_key in this.dates) ? this.dates[date_key] : 0]);
begin_date_copy.add(1, 'days');
}
// Process country data to fit into the NVD3 scheme
var processed_data = [];
for (var i = 0 ; i < this.data.length ; i++) {
var country_name = this.data[i]['country_id'] ? this.data[i]['country_id'][1] : _t('Undefined');
processed_data.push({'label':country_name + ' (' + this.data[i]['country_id_count'] + ')', 'value':this.data[i]['country_id_count']});
}
// Set title
var nb_clicks = _.reduce(clicks_array, function (total, val) { return total + val[1] ; }, 0);
$(this.$element + ' .title').html(nb_clicks + _t(' clicks'));
// Set title
$(this.$element + ' .title').html(this.data.length + _t(' countries'));
// Fit data into the NVD3 scheme
var chart_data = [{}];
chart_data[0]['key'] = _t('# of clicks');
chart_data[0]['values'] = clicks_array;
nv.addGraph(function () {
var chart = nv.models.pieChart()
.x(function (d) { return d.label; })
.y(function (d) { return d.value; })
.showLabels(false);
nv.addGraph(function () {
var chart = nv.models.lineChart()
.x(function (d) { return getDate(d); })
.y(function (d) { return getNbClicks(d); })
.showYAxis(true)
.showXAxis(true);
d3.select(self.$element + ' svg')
.datum(processed_data)
.transition().duration(1200)
.call(chart);
// Reduce the number of labels on the X axis for visibility
var tick_values = getPrunedTickValues(chart_data[0]['values'], 10);
return self.chart = chart;
});
},
});
chart.xAxis
.tickFormat(function (d) { return d3.time.format("%d/%m/%y")(new Date(d)); })
.tickValues(_.map(tick_values, function (d) { return getDate(d).getTime(); }))
.rotateLabels(55);
base.ready().done(function () {
// Resize the chart when a tab is opened, because NVD3 automatically reduce the size
// of the chart to 5px width when the bootstrap tab is closed.
var charts = {};
$(".graph-tabs li a").click(function (e) {
e.preventDefault();
$(this).tab('show');
_.chain(charts).pluck('chart').invoke('update'); // Force NVD3 to redraw the chart
chart.yAxis
.tickFormat(d3.format("d"))
.ticks(chart_data[0]['values'].length - 1);
d3.select(self.$element + ' svg')
.datum(chart_data)
.call(chart);
return self.chart = chart;
});
},
});
var PieChart = Widget.extend({
/**
* @override
* @param {Object} $element
* @param {Object} data
*/
init: function ($element, data) {
this.data = data;
this.$element = $element;
},
/**
* @override
* @param {Object} parent
*/
start: function (parent) {
var self = this;
// Process country data to fit into the NVD3 scheme
var processed_data = [];
for (var i = 0 ; i < this.data.length ; i++) {
var country_name = this.data[i]['country_id'] ? this.data[i]['country_id'][1] : _t('Undefined');
processed_data.push({'label':country_name + ' (' + this.data[i]['country_id_count'] + ')', 'value':this.data[i]['country_id_count']});
}
// Set title
$(this.$element + ' .title').html(this.data.length + _t(' countries'));
nv.addGraph(function () {
var chart = nv.models.pieChart()
.x(function (d) { return d.label; })
.y(function (d) { return d.value; })
.showLabels(false);
d3.select(self.$element + ' svg')
.datum(processed_data)
.transition().duration(1200)
.call(chart);
return self.chart = chart;
});
},
});
sAnimations.registry.websiteLinksCharts = sAnimations.Class.extend({
selector: '.o_website_links_chart',
read_events: {
'click .graph-tabs li a': '_onResizeChart',
'click .copy-to-clipboard': '_onCopyToClipboard'
},
/**
* @override
* @param {Object} parent
*/
start: function (parent) {
this.charts = {};
// Get the code of the link
var link_id = $('#link_id').val();
var links_domain = ['link_id', '=', parseInt(link_id)];
this.links_domain = ['link_id', '=', parseInt(link_id)];
var total_clicks = function () {
return rpc.query({
model: 'link.tracker.click',
method: 'search_count',
args: [[links_domain]],
context: weContext.get(), // TODO use this._rpc
});
};
$.when(this._totalClicks(),
this._clicksByDay(),
this._clicksByCountry(),
this._lastWeekClicksByCountry(),
this._lastMonthClicksByCountry())
.done(function (_totalClicks, _clicksByDay, _clicksByCountry, _lastWeekClicksByCountry, _lastMonthClicksByCountry) {
var clicks_by_day = function () {
return rpc.query({
model: 'link.tracker.click',
method: 'read_group',
args: [[links_domain], ['create_date']],
kwargs: {groupby:'create_date:day'},
context: weContext.get(), // TODO use this._rpc
});
};
var clicks_by_country = function () {
return rpc.query({
model: 'link.tracker.click',
method: 'read_group',
args: [[links_domain], ['country_id']],
kwargs: {groupby:'country_id'},
context: weContext.get(), // TODO use this._rpc
});
};
var last_week_clicks_by_country = function () {
var interval = moment().subtract(7, 'days').format("YYYY-MM-DD");
return rpc.query({
model: 'link.tracker.click',
method: 'read_group',
args: [[links_domain, ['create_date', '>', interval]], ['country_id']],
kwargs: {groupby:'country_id'},
context: weContext.get(), // TODO use this._rpc
});
};
var last_month_clicks_by_country = function () {
var interval = moment().subtract(30, 'days').format("YYYY-MM-DD");
return rpc.query({
model: 'link.tracker.click',
method: 'read_group',
args: [[links_domain, ['create_date', '>', interval]], ['country_id']],
kwargs: {groupby: 'country_id'},
context: weContext.get(), // TODO use this._rpc
});
};
$.when(total_clicks(),
clicks_by_day(),
clicks_by_country(),
last_week_clicks_by_country(),
last_month_clicks_by_country())
.done(function (total_clicks, clicks_by_day, clicks_by_country, last_week_clicks_by_country, last_month_clicks_by_country) {
if (total_clicks) {
if (_totalClicks) {
this.charts = {};
var formatted_clicks_by_day = {};
var begin_date, end_date;
for (var i = 0 ; i < clicks_by_day.length ; i++) {
var date = moment(clicks_by_day[i]['create_date:day'], "DD MMMM YYYY");
for (var i = 0 ; i < _clicksByDay.length ; i++) {
var date = moment(_clicksByDay[i]['create_date:day'], "DD MMMM YYYY");
if (i === 0) { begin_date = date; }
if (i === clicks_by_day.length - 1) { end_date = date; }
formatted_clicks_by_day[date.format("YYYY-MM-DD")] = clicks_by_day[i]['create_date_count'];
if (i === _clicksByDay.length - 1) { end_date = date; }
formatted_clicks_by_day[date.format("YYYY-MM-DD")] = _clicksByDay[i]['create_date_count'];
}
// Process all time line chart data
var now = moment();
charts.all_time_bar = new BarChart('#all_time_clicks_chart', begin_date, now, formatted_clicks_by_day);
this.charts.all_time_bar = new BarChart('#all_time_clicks_chart', begin_date, now, formatted_clicks_by_day);
// Process month line chart data
begin_date = moment().subtract(30, 'days');
charts.last_month_bar = new BarChart('#last_month_clicks_chart', begin_date, now, formatted_clicks_by_day);
this.charts.last_month_bar = new BarChart('#last_month_clicks_chart', begin_date, now, formatted_clicks_by_day);
// Process week line chart data
begin_date = moment().subtract(7, 'days');
charts.last_week_bar = new BarChart('#last_week_clicks_chart', begin_date, now, formatted_clicks_by_day);
this.charts.last_week_bar = new BarChart('#last_week_clicks_chart', begin_date, now, formatted_clicks_by_day);
// Process pie charts
charts.all_time_pie = new PieChart('#all_time_countries_charts', clicks_by_country);
charts.last_month_pie = new PieChart('#last_month_countries_charts', last_month_clicks_by_country);
charts.last_week_pie = new PieChart('#last_week_countries_charts', last_week_clicks_by_country);
this.charts.all_time_pie = new PieChart('#all_time_countries_charts', _clicksByCountry);
this.charts.last_month_pie = new PieChart('#last_month_countries_charts', _lastMonthClicksByCountry);
this.charts.last_week_pie = new PieChart('#last_week_countries_charts', _lastWeekClicksByCountry);
var row_width = $('#all_time_countries_charts').parent().width();
var charts_svg = $('#all_time_countries_charts,last_month_countries_charts,last_week_countries_charts').find('svg');
charts_svg.css('height', Math.max(clicks_by_country.length * (row_width > 750 ? 1 : 2), 20) + 'em');
charts_svg.css('height', Math.max(_clicksByCountry.length * (row_width > 750 ? 1 : 2), 20) + 'em');
_.invoke(charts, 'start');
_.invoke(this.charts, 'start');
nv.utils.windowResize(function () {
_.chain(charts).pluck('chart').invoke('update');
_.chain(this.charts).pluck('chart').invoke('update');
});
}
else {
@@ -242,36 +206,119 @@ if (!$('.o_website_links_chart').length) {
// Copy to clipboard link
new ClipboardJS($('.copy-to-clipboard')[0]);
var animating_copy = false;
this.animating_copy = false;
},
$('.copy-to-clipboard').on('click', function (e) {
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
e.preventDefault();
if (!animating_copy) {
animating_copy = true;
$('.o_website_links_short_url').clone()
.css('position', 'absolute')
.css('left', '15px')
.css('bottom', '10px')
.css('z-index', 2)
.removeClass('.o_website_links_short_url')
.addClass('animated-link')
.appendTo($('.o_website_links_short_url'))
.animate({
opacity: 0,
bottom: "+=20",
}, 500, function () {
$('.animated-link').remove();
animating_copy = false;
});
}
/**
* @private
*/
_totalClicks: function () {
return this._rpc({
model: 'link.tracker.click',
method: 'search_count',
args: [[this.links_domain]],
});
});
},
/**
* @private
*/
_clicksByDay: function () {
return this._rpc({
model: 'link.tracker.click',
method: 'read_group',
args: [[this.links_domain], ['create_date']],
kwargs: {groupby:'create_date:day'},
});
},
/**
* @private
*/
_clicksByCountry: function () {
return this._rpc({
model: 'link.tracker.click',
method: 'read_group',
args: [[this.links_domain], ['country_id']],
kwargs: {groupby:'country_id'},
});
},
/**
* @private
*/
_lastWeekClicksByCountry: function () {
var interval = moment().subtract(7, 'days').format("YYYY-MM-DD");
return this._rpc({
model: 'link.tracker.click',
method: 'read_group',
args: [[this.links_domain, ['create_date', '>', interval]], ['country_id']],
kwargs: {groupby:'country_id'},
});
},
/**
* @private
*/
_lastMonthClicksByCountry: function () {
var interval = moment().subtract(30, 'days').format("YYYY-MM-DD");
return this._rpc({
model: 'link.tracker.click',
method: 'read_group',
args: [[this.links_domain, ['create_date', '>', interval]], ['country_id']],
kwargs: {groupby: 'country_id'},
});
},
exports.BarChart = BarChart;
exports.PieChart = PieChart;
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* Resize the chart when a tab is opened, because NVD3 automatically reduce the size
* of the chart to 5px width when the bootstrap tab is closed.
*
* @override
* @param {Object} e
*/
_onResizeChart: function (e) {
e.preventDefault();
$('.graph-tabs li a').tab('show');
_.chain(this.charts).pluck('chart').invoke('update'); // Force NVD3 to redraw the chart
},
/**
* @override
* @param {Object} e
*/
_onCopyToClipboard: function (e) {
e.preventDefault();
if (!this.animating_copy) {
this.animating_copy = true;
$('.o_website_links_short_url').clone()
.css('position', 'absolute')
.css('left', '15px')
.css('bottom', '10px')
.css('z-index', 2)
.removeClass('.o_website_links_short_url')
.addClass('animated-link')
.appendTo($('.o_website_links_short_url'))
.animate({
opacity: 0,
bottom: "+=20",
}, 500, function () {
$('.animated-link').remove();
this.animating_copy = false;
});
}
},
});
exports.BarChart = BarChart;
exports.PieChart = PieChart;
return exports;
});
@@ -1,91 +1,114 @@
odoo.define('website_links.code_editor', function (require) {
'use strict';
require('web.dom_ready');
var sAnimations = require('website.content.snippets.animation');
var ajax = require('web.ajax');
if (!$('.o_website_links_edit_code').length) {
return $.Deferred().reject("DOM doesn't contain '.o_website_links_edit_code'");
}
sAnimations.registry.websiteLinksCodeEditor = sAnimations.Class.extend({
selector: '.o_website_links_edit_code',
read_events: {
'click .o_website_links_edit_code': '_onEdit',
'click .o_website_links_cancel_edit': '_onCancel',
'submit #edit-code-form': '_onEditCodeForm',
'click .o_website_links_ok_edit': '_onEditCodeForm'
},
// Edit the short URL code
$('.o_website_links_edit_code').on('click', function (e) {
e.preventDefault();
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* @private
* @param {String} new_code
*/
_showNewCode: function (new_code) {
$('.o_website_links_code_error').html('');
$('.o_website_links_code_error').hide();
$('#o_website_links_code form').remove();
// Show new code
var host = $('#short-url-host').html();
$('#o_website_links_code').html(new_code);
// Update button copy to clipboard
$('.copy-to-clipboard').attr('data-clipboard-text', host + new_code);
// Show action again
$('.o_website_links_edit_code').show();
$('.copy-to-clipboard').show();
$('.o_website_links_edit_tools').hide();
},
/**
* @private
*/
_submitCode: function () {
var init_code = $('#edit-code-form #init_code').val();
var new_code = $('#edit-code-form #new_code').val();
var self = this;
if (new_code === '') {
self.$('.o_website_links_code_error').html("The code cannot be left empty");
self.$('.o_website_links_code_error').show();
return;
}
this._showNewCode(new_code);
if (init_code === new_code) {
this._showNewCode(new_code);
} else {
ajax.jsonRpc('/website_links/add_code', 'call', {'init_code':init_code, 'new_code':new_code})
.then(function (result) {
self._showNewCode(result[0].code);
})
.fail(function () {
$('.o_website_links_code_error').show();
$('.o_website_links_code_error').html("This code is already taken");
});
}
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @override
*/
_onEdit: function () {
var init_code = $('#o_website_links_code').html();
$('#o_website_links_code').html("<form style='display:inline;' id='edit-code-form'><input type='hidden' id='init_code' value='" + init_code + "'/><input type='text' id='new_code' value='" + init_code + "'/></form>");
$('.o_website_links_edit_code').hide();
$('.copy-to-clipboard').hide();
$('.o_website_links_edit_tools').show();
},
/**
* @override
* @param {Object} e
*/
_onCancel: function (e) {
e.preventDefault();
$('.o_website_links_edit_code').show();
$('.copy-to-clipboard').show();
$('.o_website_links_edit_tools').hide();
$('.o_website_links_code_error').hide();
$('.o_website_links_cancel_edit').on('click', function (e) {
e.preventDefault();
var old_code = $('#edit-code-form #init_code').val();
$('#o_website_links_code').html(old_code);
$('.o_website_links_edit_code').show();
$('.copy-to-clipboard').show();
$('.o_website_links_edit_tools').hide();
$('.o_website_links_code_error').hide();
$('#code-error').remove();
$('#o_website_links_code form').remove();
},
/**
* @override
* @param {Object} e
*/
_onEditCodeForm: function (e) {
e.preventDefault();
this._submitCode();
},
});
var old_code = $('#edit-code-form #init_code').val();
$('#o_website_links_code').html(old_code);
$('#code-error').remove();
$('#o_website_links_code form').remove();
});
function submit_code() {
var init_code = $('#edit-code-form #init_code').val();
var new_code = $('#edit-code-form #new_code').val();
if (new_code === '') {
self.$('.o_website_links_code_error').html("The code cannot be left empty");
self.$('.o_website_links_code_error').show();
return;
}
function show_new_code(new_code) {
$('.o_website_links_code_error').html('');
$('.o_website_links_code_error').hide();
$('#o_website_links_code form').remove();
// Show new code
var host = $('#short-url-host').html();
$('#o_website_links_code').html(new_code);
// Update button copy to clipboard
$('.copy-to-clipboard').attr('data-clipboard-text', host + new_code);
// Show action again
$('.o_website_links_edit_code').show();
$('.copy-to-clipboard').show();
$('.o_website_links_edit_tools').hide();
}
if (init_code === new_code) {
show_new_code(new_code);
}
else {
ajax.jsonRpc('/website_links/add_code', 'call', {'init_code':init_code, 'new_code':new_code})
.then(function (result) {
show_new_code(result[0].code);
})
.fail(function () {
$('.o_website_links_code_error').show();
$('.o_website_links_code_error').html("This code is already taken");
}) ;
}
}
$('#edit-code-form').submit(function (e) {
e.preventDefault();
submit_code();
});
$('.o_website_links_ok_edit').click(function (e) {
e.preventDefault();
submit_code();
});
});
});
@@ -3,10 +3,22 @@
* when the user click the link "Share this page" on top of the page.
*/
(function () {
'use strict';
odoo.define('website_links.website_links_menu', function (require) {
"use strict";
$(document).ready(function () {
$('#o_website_links_share_page').attr('href', '/r?u=' + encodeURIComponent(window.location.href));
});
})();
var sAnimations = require('website.content.snippets.animation');
sAnimations.registry.websiteLinksMenu = sAnimations.Class.extend({
selector: '.navbar',
/**
* @override
* @param {Object} parent
*/
start: function (parent) {
$('#o_website_links_share_page').attr('href', '/r?u=' + encodeURIComponent(window.location.href));
},
});
});
@@ -2,7 +2,7 @@
<templates id="template" xml:space="preserve">
<t t-name="website_links.RecentLink">
<div class="row mb16">
<div class="row mb16 link-row">
<div class="col-md-1 col-2 text-center">
<h4><t t-esc="widget.link_obj.count"/></h4>
<p class="text-muted" style="margin-top: -5px;">clicks</p>