From c64c646d62a658c94f2d81eea9a2797a4ce024ea Mon Sep 17 00:00:00 2001 From: Andrea Ulliana Date: Fri, 19 Oct 2018 10:19:34 +0000 Subject: [PATCH] [REF] website_slides: reorganize javascript --- addons/website_slides/static/src/js/slides.js | 76 ++- .../static/src/js/slides_embed.js | 115 ++-- .../static/src/js/slides_like.js | 136 ++-- .../static/src/js/slides_share.js | 217 ++++--- .../static/src/js/slides_upload.js | 586 ++++++++++-------- 5 files changed, 655 insertions(+), 475 deletions(-) diff --git a/addons/website_slides/static/src/js/slides.js b/addons/website_slides/static/src/js/slides.js index 0377394c452..bea4146bfe6 100644 --- a/addons/website_slides/static/src/js/slides.js +++ b/addons/website_slides/static/src/js/slides.js @@ -2,34 +2,56 @@ odoo.define('website_slides.slides', function (require) { "use strict"; - var time = require('web.time'); - require('root.widget'); +var time = require('web.time'); +require('root.widget'); +var sAnimations = require('website.content.snippets.animation'); - (function () { - $("timeago.timeago").each(function (index, el) { - var datetime = $(el).attr('datetime'), - datetime_obj = time.str_to_datetime(datetime), - // if presentation 7 days, 24 hours, 60 min, 60 second, 1000 millis old(one week) - // then return fix formate string else timeago - display_str = ""; - if (datetime_obj && new Date().getTime() - datetime_obj.getTime() > 7 * 24 * 60 * 60 * 1000) { - display_str = moment(datetime_obj).format('ll'); - } else { - display_str = moment(datetime_obj).fromNow(); - } - $(el).text(display_str); - }); +var page_widgets = {}; - // To prevent showing channel settings alert box once user closed it. - $('.o_slides_hide_channel_settings').on('click', function(ev) { - var channel_id = $(this).data("channelId"); - ev.preventDefault(); - document.cookie = "slides_channel_" + channel_id + " = closed"; - return true; - }); - })(); +sAnimations.registry.websiteSlides = sAnimations.Class.extend({ + selector: 'main', + read_events: { + 'each timeago.timeago': '_onTimeAgo', + 'click .o_slides_hide_channel_settings': '_onHideChannelSettings', + }, - return { - page_widgets: {}, - } + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * @override + * @param {Object} index + * @param {Object} el + */ + _onTimeAgo: function (index, el) { + var datetime = $(el).attr('datetime'), + datetime_obj = time.str_to_datetime(datetime), + // if presentation 7 days, 24 hours, 60 min, 60 second, 1000 millis old(one week) + // then return fix formate string else timeago + display_str = ""; + if (datetime_obj && new Date().getTime() - datetime_obj.getTime() > 7 * 24 * 60 * 60 * 1000) { + display_str = moment(datetime_obj).format('ll'); + } else { + display_str = moment(datetime_obj).fromNow(); + } + $(el).text(display_str); + }, + /** + * To prevent showing channel settings alert box once user closed it. + * + * @override + * @param {Object} ev + */ + _onHideChannelSettings: function (ev) { + var channel_id = $(this).data("channelId"); + ev.preventDefault(); + document.cookie = "slides_channel_" + channel_id + " = closed"; + return true; + }, +}); + +return { + page_widgets: page_widgets, +}; }); diff --git a/addons/website_slides/static/src/js/slides_embed.js b/addons/website_slides/static/src/js/slides_embed.js index 2ba46a1990d..dcb72d7765c 100644 --- a/addons/website_slides/static/src/js/slides_embed.js +++ b/addons/website_slides/static/src/js/slides_embed.js @@ -1,50 +1,77 @@ /*global $, _, PDFSlidesViewer*/ odoo.define('website_slides.slides_embed', function (require) { - "use strict"; - - var time = require('web.time'); - var Widget = require('web.Widget'); - require('website_slides.slides'); - - (function () { - /* - * Embedded Code Widget - */ - var SlideSocialEmbed = Widget.extend({ - events: { - 'change input' : 'change_page', - }, - init: function(parent, max_page){ - this._super(parent); - this.max_page = max_page || false; - }, - change_page: function(ev){ - ev.preventDefault(); - var input = this.$('input'); - var page = parseInt(input.val()); - if (this.max_page && !(page > 0 && page <= this.max_page)) { - page = 1; - } - this.update_embedded_code(page); - }, - update_embedded_code: function(page){ - var embed_input = this.$('.slide_embed_code'); - var new_code = embed_input.val().replace(/(page=).*?([^\d]+)/, '$1' + page + '$2'); - embed_input.val(new_code); - }, - }); +"use strict"; - $('iframe.o_wslides_iframe_viewer').ready(function() { - // TODO : make it work. For now, once the iframe is loaded, the value of #page_count is - // still now set (the pdf is still loading) - var $iframe = $(this); - var max_page = $iframe.contents().find('#page_count').val(); - slides.page_widgets['social_embed'] = new SlideSocialEmbed($iframe, max_page).setElement($('.oe_slide_js_embed_code_widget')); - }); - - })(); - +var Widget = require('web.Widget'); +require('website_slides.slides'); +var sAnimations = require('website.content.snippets.animation'); + +// Embedded Code Widget +var SlideSocialEmbed = Widget.extend({ + events: { + 'change input' : '_changePage', + }, + /** + * @override + * @param {Object} parent + * @param {Number} max_page + */ + init: function (parent, max_page){ + this._super(parent); + this.max_page = max_page || false; + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @private + * @param {Object} ev + */ + _changePage: function (ev){ + ev.preventDefault(); + var input = this.$('input'); + var page = parseInt(input.val()); + if (this.max_page && !(page > 0 && page <= this.max_page)) { + page = 1; + } + this._updateEmbeddedCode(page); + }, + /** + * @private + * @param {Number} page + */ + _updateEmbeddedCode: function (page){ + var embed_input = this.$('.slide_embed_code'); + var new_code = embed_input.val().replace(/(page=).*?([^\d]+)/, '$1' + page + '$2'); + embed_input.val(new_code); + }, }); + +sAnimations.registry.websiteSlidesEmbed = sAnimations.Class.extend({ + selector: 'main', + read_events: { + 'ready iframe.o_wslides_iframe_viewer': '_onIframeViewer', + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * @override + */ + _onIframeViewer: function () { + // TODO : make it work. For now, once the iframe is loaded, the value of #page_count is + // still now set (the pdf is still loading) + var $iframe = $(this); + var max_page = $iframe.contents().find('#page_count').val(); + new SlideSocialEmbed($iframe, max_page).setElement($('.oe_slide_js_embed_code_widget')); + }, +}); +}); + /** This file is a minimal version of the PDFViewer widget. It is NOT use in the website_slides module, but it is @@ -250,5 +277,3 @@ $(document).ready(function () { }); } }); - - diff --git a/addons/website_slides/static/src/js/slides_like.js b/addons/website_slides/static/src/js/slides_like.js index d9c0da2afa2..3f3033c6098 100644 --- a/addons/website_slides/static/src/js/slides_like.js +++ b/addons/website_slides/static/src/js/slides_like.js @@ -1,63 +1,85 @@ /*global $, _, PDFJS */ odoo.define('website_slides.slides_like', function (require) { - "use strict"; - - var ajax = require('web.ajax'); - var core = require('web.core'); - var Widget = require('web.Widget'); - var local_storage = require('web.local_storage'); - var slides = require('website_slides.slides'); - - var _t = core._t; - - (function () { +"use strict"; + +var ajax = require('web.ajax'); +var core = require('web.core'); +var Widget = require('web.Widget'); +var local_storage = require('web.local_storage'); +var sAnimations = require('website.content.snippets.animation'); +var slides = require('website_slides.slides'); + +var _t = core._t; + +// Like/Dislike Buttons Widget +var LikeButton = Widget.extend({ + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @private + * @param {Object} $el + */ + setElement: function ($el){ + this._super.apply(this, arguments); + this.$el.on('click', this, _.bind(this._applyAction, this)); + }, + /** + * @private + * @param {Object} ev + */ + _applyAction: function (ev){ + var button = $(ev.currentTarget); + var slide_id = button.data('slide-id'); + var user_id = button.data('user-id'); + var is_public = button.data('public-user'); + var href = button.data('href'); + if (is_public){ + this._popoverAlert(button, _.str.sprintf(_t('Please login to vote this slide'), (document.URL))); + } else { + var target = button.find('.fa'); + if (local_storage.getItem('slide_vote_' + slide_id) !== user_id.toString()) { + ajax.jsonRpc(href, 'call', {slide_id: slide_id}).then(function (data) { + target.text(data); + local_storage.setItem('slide_vote_' + slide_id, user_id); + }); + } else { + this._popoverAlert(button, _t('You have already voted for this slide')); + } + } + }, + /** + * @private + * @param {Object} $el + * @param {String} message + */ + _popoverAlert: function ($el, message){ + $el.popover({ + trigger: 'focus', + placement: 'bottom', + container: 'body', + html: true, + content: function () { + return message; + } + }).popover('show'); + }, +}); + +sAnimations.registry.websiteSlidesLike = sAnimations.Class.extend({ + selector: 'main', + + /** + * @override + * @param {Object} parent + */ + start: function (parent) { var widget_parent = $('body'); - - /* - * Like/Dislike Buttons Widget - */ - var LikeButton = Widget.extend({ - setElement: function($el){ - this._super.apply(this, arguments); - this.$el.on('click', this, _.bind(this.apply_action, this)); - }, - apply_action: function(ev){ - var button = $(ev.currentTarget); - var slide_id = button.data('slide-id'); - var user_id = button.data('user-id'); - var is_public = button.data('public-user'); - var href = button.data('href'); - if(is_public){ - this.popover_alert(button, _.str.sprintf(_t('Please login to vote this slide'), (document.URL))); - }else{ - var target = button.find('.fa'); - if (local_storage.getItem('slide_vote_' + slide_id) !== user_id.toString()) { - ajax.jsonRpc(href, 'call', {slide_id: slide_id}).then(function (data) { - target.text(data); - local_storage.setItem('slide_vote_' + slide_id, user_id); - }); - } else { - this.popover_alert(button, _t('You have already voted for this slide')); - } - } - }, - popover_alert: function($el, message){ - $el.popover({ - trigger: 'focus', - placement: 'bottom', - container: 'body', - html: true, - content: function(){ - return message; - } - }).popover('show'); - }, - }); - slides.page_widgets['likeButton'] = new LikeButton(widget_parent).setElement($('.oe_slide_js_like')); slides.page_widgets['dislikeButton'] = new LikeButton(widget_parent).setElement($('.oe_slide_js_unlike')); - - })(); - + return this._super.apply(this, arguments); + }, +}); }); - \ No newline at end of file diff --git a/addons/website_slides/static/src/js/slides_share.js b/addons/website_slides/static/src/js/slides_share.js index 72e810f16f6..e1ef6118cfe 100644 --- a/addons/website_slides/static/src/js/slides_share.js +++ b/addons/website_slides/static/src/js/slides_share.js @@ -1,43 +1,56 @@ odoo.define('website_slides.slides_share', function (require) { - "use strict"; - var ajax = require('web.ajax'); - var Widget = require('web.Widget'); - var slides = require('website_slides.slides'); +"use strict"; +var ajax = require('web.ajax'); +var Widget = require('web.Widget'); +var sAnimations = require('website.content.snippets.animation'); +var slides = require('website_slides.slides'); - (function () { +// Send by email Widget +var ShareMail = Widget.extend({ + events: { + 'click button': '_sendMail', + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @private + */ + _sendMail: function () { + var self = this; + var input = this.$('input'); + var slide_id = this.$('button').data('slide-id'); + if (input.val() && input[0].checkValidity()){ + this.$el.removeClass('o_has_error').find('.form-control, .custom-select').removeClass('is-invalid'); + ajax.jsonRpc('/slides/slide/send_share_email', 'call', { + slide_id: slide_id, + email: input.val(), + }).then(function () { + self.$el.html($('')); + }); + } else { + this.$el.addClass('o_has_error').find('.form-control, .custom-select').addClass('is-invalid'); + input.focus(); + } + }, +}); + +sAnimations.registry.websiteSlidesShare = sAnimations.Class.extend({ + selector: 'main', + read_events: { + 'click a.o_slides_social_share': '_onSlidesSocialShare' + }, + + /** + * @override + * @param {Object} parent + */ + start: function (parent) { var widget_parent = $('body'); - - /* - * Send by email Widget - */ - var ShareMail = Widget.extend({ - events: { - 'click button' : 'send_mail', - }, - send_mail: function(){ - var self = this; - var input = this.$('input'); - var slide_id = this.$('button').data('slide-id'); - if(input.val() && input[0].checkValidity()){ - this.$el.removeClass('o_has_error').find('.form-control, .custom-select').removeClass('is-invalid'); - ajax.jsonRpc('/slides/slide/send_share_email', 'call', { - slide_id: slide_id, - email: input.val(), - }).then(function () { - self.$el.html($('')); - }); - }else{ - this.$el.addClass('o_has_error').find('.form-control, .custom-select').addClass('is-invalid'); - input.focus(); - } - }, - }); - slides.page_widgets['share_mail'] = new ShareMail(widget_parent).setElement($('.oe_slide_js_share_email')); - /* - * Social Sharing Statistics Widget - */ if ($('div#statistic').length) { var slide_url = $("div#statistic").attr('slide-url'); var social_urls = { @@ -45,66 +58,84 @@ odoo.define('website_slides.slides_share', function (require) { 'twitter': 'https://cdn.api.twitter.com/1/urls/count.json?url=', 'facebook': 'https://graph.facebook.com/?id=', 'gplus': 'https://clients6.google.com/rpc' - } - - var update_statistics = function(social_site, slide_url) { - if (social_site == 'gplus') { - $.ajax({ - url: social_urls['gplus'], - type: "POST", - dataType: 'json', - contentType: 'application/json', - data: JSON.stringify([{ - "method": "pos.plusones.get", - "id": "p", - "params": { - "nolog": true, - "id": slide_url, - "source": "widget", - "userId": "@viewer", - "groupId": "@self" - }, - // TDE NOTE: should there be a key here ? - "jsonrpc": "2.0", - "apiVersion": "v1" - }]), - success: function(data) { - $('#google-badge').text(data[0].result.metadata.globalCounts.count || 0); - $('#total-share').text(parseInt($('#total-share').text()) + parseInt($('#google-badge').text())); - }, - }); - } else { - $.ajax({ - url: social_urls[social_site] + slide_url, - dataType: 'jsonp', - success: function(data) { - var shareCount = (social_site === 'facebook' ? data.shares : data.count) || 0; - $('#' + social_site + '-badge').text(shareCount); - $('#total-share').text(parseInt($('#total-share').text()) + parseInt($('#' + social_site+ '-badge').text())); - }, - }); - } }; + } - $.each(social_urls, function(key, value) { - update_statistics(key, slide_url); + $.each(social_urls, function (key, value) { + this._updateStatistics(key, slide_url); + }); + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @private + * @param {string} social_site + * @param {string} slide_url + */ + _updateStatistics: function (social_site, slide_url) { + if (social_site === 'gplus') { + $.ajax({ + url: this.social_urls['gplus'], + type: "POST", + dataType: 'json', + contentType: 'application/json', + data: JSON.stringify([{ + "method": "pos.plusones.get", + "id": "p", + "params": { + "nolog": true, + "id": slide_url, + "source": "widget", + "userId": "@viewer", + "groupId": "@self" + }, + // TDE NOTE: should there be a key here ? + "jsonrpc": "2.0", + "apiVersion": "v1" + }]), + success: function (data) { + $('#google-badge').text(data[0].result.metadata.globalCounts.count || 0); + $('#total-share').text(parseInt($('#total-share').text()) + parseInt($('#google-badge').text())); + }, }); - - $("a.o_slides_social_share").on('click', function(ev) { - ev.preventDefault(); - var key = $(ev.currentTarget).attr('social-key'); - var popUpURL = $(ev.currentTarget).attr('href'); - var popUp = window.open( - popUpURL, - 'Share Dialog', - 'width=626,height=436'); - $(window).on('focus', function() { - if (popUp.closed) { - update_statistics(key, slide_url); - $(window).off('focus'); - } - }); + } else { + $.ajax({ + url: this.social_urls[social_site] + slide_url, + dataType: 'jsonp', + success: function (data) { + var shareCount = (social_site === 'facebook' ? data.shares : data.count) || 0; + $('#' + social_site + '-badge').text(shareCount); + $('#total-share').text(parseInt($('#total-share').text()) + parseInt($('#' + social_site+ '-badge').text())); + }, }); } - })(); -}) \ No newline at end of file + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * @override + * @param {Object} ev + */ + _onSlidesSocialShare: function (ev) { + ev.preventDefault(); + var key = $(ev.currentTarget).attr('social-key'); + var popUpURL = $(ev.currentTarget).attr('href'); + var popUp = window.open( + popUpURL, + 'Share Dialog', + 'width=626,height=436'); + $(window).on('focus', function () { + if (popUp.closed) { + this._updateStatistics(key, this.slide_url); + $(window).off('focus'); + } + }); + }, +}); +}); diff --git a/addons/website_slides/static/src/js/slides_upload.js b/addons/website_slides/static/src/js/slides_upload.js index aa638882930..382caf451e2 100644 --- a/addons/website_slides/static/src/js/slides_upload.js +++ b/addons/website_slides/static/src/js/slides_upload.js @@ -1,81 +1,311 @@ odoo.define('website_slides.upload', function (require) { "use strict"; +var sAnimations = require('website.content.snippets.animation'); var ajax = require('web.ajax'); var core = require('web.core'); var Widget = require('web.Widget'); -require('web.dom_ready'); -var weContext = require("web_editor.context"); var slides = require('website_slides.slides'); -var qweb = core.qweb; var _t = core._t; -if (!$('.oe_slide_js_upload').length) { - return $.Deferred().reject("DOM doesn't contain '.oe_slide_js_upload'"); -} - -ajax.loadXML('/website_slides/static/src/xml/website_slides.xml', qweb); - var SlideDialog = Widget.extend({ template: 'website.slide.upload', events: { 'hidden.bs.modal': 'destroy', - 'click button.save': 'save', - 'click button[data-dismiss="modal"]': 'cancel', - 'change input#upload': 'slide_upload', - 'change input#url': 'slide_url', + 'click button.save': '_save', + 'click button[data-dismiss="modal"]': '_cancel', + 'change input#upload': '_slideUpload', + 'change input#url': '_slideUrl', 'click .list-group-item': function (ev) { this.$('.list-group-item').removeClass('active'); $(ev.target).closest('li').addClass('active'); } }, + + /** + * @override + * @param {Object} el + * @param {number} channel_id + */ init: function (el, channel_id) { this._super(el, channel_id); this.channel_id = parseInt(channel_id, 10); this.file = {}; this.index_content = ""; }, - start: function () { + /** + * @override + * @param {Object} parent + */ + start: function (parent) { this.$el.modal({ backdrop: 'static' }); - this.set_category_id(); - this.set_tag_ids(); + this._setCategoryId(); + this._setTagIds(); }, - slide_url: function (ev) { - var self = this, - value = { - 'url': $(ev.target).val(), - 'channel_id': self.channel_id - }; - this.$('.alert-warning').remove(); - this.is_valid_url = false; - this.$('.save').button('loading'); - ajax.jsonRpc('/slides/dialog_preview/', 'call', value).then(function (data) { - self.$('.save').button('reset'); - if (data.error) { - self.display_alert(data.error); - } else { - self.$("#slide-image").attr("src", data.url_src); - self.$('#name').val(data.title); - self.$('#description').val(data.description); - self.is_valid_url = true; - } - }); - }, - check_unique_slide: function (file_name) { + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @private + * @param {string} file_name + */ + _checkUniqueSlide: function (file_name) { var self = this; - return ajax.jsonRpc('/web/dataset/call_kw', 'call', { + return this._rpc({ model: 'slide.slide', method: 'search_count', args: [[['channel_id', '=', self.channel_id], ['name', '=', file_name]]], - kwargs: { - context: weContext.get(), // TODO use this._rpc - } }); }, - slide_upload: function (ev) { + /** + * @private + */ + _resetFile: function () { + var control = this.$('#upload'); + control.replaceWith(control = control.clone(true)); + this.file.name = false; + }, + /** + * @private + * @param {string} message + */ + _displayAlert: function (message) { + this.$('.alert-warning').remove(); + $('').insertBefore(this.$('form')); + }, + + /** + * Wrapper for select2 load data from server at once and store it. + * + * @private + * @param {String} Placeholder for element. + * @param {bool} true for multiple selection box, false for single selection + * @param {Function} Function to fetch data from remote location should return $.deferred object + * resolved data should be array of object with id and name. eg. [{'id': id, 'name': 'text'}, ...] + * @returns {Object} select2 wrapper object + */ + _select2Wrapper: function (tag, multi, fetch_fnc) { + return { + width: '100%', + placeholder: tag, + allowClear: true, + formatNoMatches: false, + multiple: multi, + selection_data: false, + fetch_rpc_fnc : fetch_fnc, + formatSelection: function (data) { + if (data.tag) { + data.text = data.tag; + } + return data.text; + }, + createSearchChoice: function (term, data) { + var added_tags = $(this.opts.element).select2('data'); + if (_.filter(_.union(added_tags, data), function (tag) { + return tag.text.toLowerCase().localeCompare(term.toLowerCase()) === 0; + }).length === 0) { + return { + id: _.uniqueId('tag_'), + create: true, + tag: term, + text: _.str.sprintf(_t("Create new tag '%s'"), term), + }; + } + }, + fill_data: function (query, data) { + var that = this, + tags = {results: []}; + _.each(data, function (obj) { + if (that.matcher(query.term, obj.name)) { + tags.results.push({id: obj.id, text: obj.name }); + } + }); + query.callback(tags); + }, + query: function (query) { + var that = this; + // fetch data only once and store it + if (!this.selection_data) { + this.fetch_rpc_fnc().then(function (data) { + that.fill_data(query, data); + that.selection_data = data; + }); + } else { + this.fill_data(query, this.selection_data); + } + } + }; + }, + /** + * Category management from select2 + * + * @private + */ + _setCategoryId: function () { + var self = this; + $('#category_id').select2(this._select2Wrapper(_t('Category'), false, + function () { + return this._rpc({ + model: 'slide.category', + method: 'search_read', + args: [], + kwargs: { + fields: ['name'], + domain: [['channel_id', '=', self.channel_id]], + } + }); + })); + }, + /** + * @private + */ + _getCategoryId: function () { + var value = $('#category_id').select2('data'); + if (value && value.create) { + return [0, {'name': value.text}]; + } + return [value ? value.id : null]; + }, + /** + * Tags management from select2 + * + * @private + */ + _setTagIds: function () { + $('#tag_ids').select2(this._select2Wrapper(_t('Tags'), true, function () { + return this._rpc({ + model: 'slide.tag', + method: 'search_read', + args: [], + kwargs: { + fields: ['name'], + } + }); + })); + }, + /** + * @private + */ + _getTagIds: function () { + var res = []; + _.each($('#tag_ids').select2('data'), + function (val) { + if (val.create) { + res.push([0, 0, {'name': val.text}]); + } else { + res.push([4, val.id]); + } + }); + return res; + }, + /** + * @private + */ + // TODO: Remove this part, as now SVG support in image resize tools is included + //Python PIL does not support SVG, so converting SVG to PNG + _svgToPng: function () { + var img = this.$el.find("img#slide-image")[0]; + var canvas = document.createElement("canvas"); + canvas.width = img.width; + canvas.height = img.height; + canvas.getContext("2d").drawImage(img, 0, 0); + return canvas.toDataURL("image/png").split(',')[1]; + }, + /** + * Values and save + * + * @private + */ + _getValue: function () { + var canvas = this.$('#data_canvas')[0], + values = { + 'channel_id': this.channel_id || '', + 'name': this.$('#name').val(), + 'url': this.$('#url').val(), + 'description': this.$('#description').val(), + 'tag_ids': this._getTagIds(), + 'category_id': this._getCategoryId() + }; + if (this.file.type === 'application/pdf') { + _.extend(values, { + 'image': canvas.toDataURL().split(',')[1], + 'index_content': this.index_content, + 'slide_type': canvas.height > canvas.width ? 'document' : 'presentation', + 'mime_type': this.file.type, + 'datas': this.file.data + }); + } + if (/^image\/.*/.test(this.file.type)) { + _.extend(values, { + 'slide_type': 'infographic', + 'mime_type': this.file.type === 'image/svg+xml' ? 'image/png' : this.file.type, + 'datas': this.file.type === 'image/svg+xml' ? this._svgToPng() : this.file.data + }); + } + return values; + }, + /** + * @private + */ + _validate: function () { + this.$('.form-group').removeClass('o_has_error').find('.form-control, .custom-select').removeClass('is-invalid'); + if (!this.$('#name').val()) { + this.$('#name').closest('.form-group').addClass('o_has_error').find('.form-control, .custom-select').addClass('is-invalid'); + return false; + } + var url = this.$('#url').val() ? this.is_valid_url : false; + if (!(this.file.name || url)) { + this.$('#url').closest('.form-group').addClass('o_has_error').find('.form-control, .custom-select').addClass('is-invalid'); + return false; + } + return true; + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * @override + * @param {Object} ev + */ + _save: function (ev) { + var self = this; + if (this._validate()) { + var values = this._getValue(); + if ($(ev.target).data('published')) { + values.website_published = true; + } + this.$('.oe_slides_upload_loading').show(); + this.$('.modal-footer, .modal-body').hide(); + ajax.jsonRpc("/slides/add_slide", 'call', values).then(function (data) { + if (data.error) { + self._displayAlert(data.error); + self.$('.oe_slides_upload_loading').hide(); + self.$('.modal-footer, .modal-body').show(); + + } else { + window.location = data.url; + } + }); + } + }, + /** + * @override + */ + _cancel: function () { + this.trigger("cancel"); + }, + /** + * @override + * @param {Object} ev + */ + _slideUpload: function (ev) { var self = this, file = ev.target.files[0], is_image = /^image\/.*/.test(file.type), @@ -83,13 +313,13 @@ var SlideDialog = Widget.extend({ this.file.name = file.name; this.file.type = file.type; if (!(is_image || this.file.type === 'application/pdf')) { - this.display_alert(_t("Invalid file type. Please select pdf or image file")); - this.reset_file(); + this._displayAlert(_t("Invalid file type. Please select pdf or image file")); + this._resetFile(); return; } if (file.size / 1024 / 1024 > 25) { - this.display_alert(_t("File is too big. File size cannot exceed 25MB")); - this.reset_file(); + this._displayAlert(_t("File is too big. File size cannot exceed 25MB")); + this._resetFile(); return; } this.$('.alert-warning').remove(); @@ -113,8 +343,8 @@ var SlideDialog = Widget.extend({ ArrayReader.onload = function (evt) { var buffer = evt.target.result; var passwordNeeded = function () { - self.display_alert(_t("You can not upload password protected file.")); - self.reset_file(); + self._displayAlert(_t("You can not upload password protected file.")); + self._resetFile(); self.$('.save').button('reset'); }; PDFJS.getDocument(new Uint8Array(buffer), null, passwordNeeded).then(function getPdf(pdf) { @@ -169,222 +399,72 @@ var SlideDialog = Widget.extend({ var input = file.name; var input_val = input.substr(0, input.lastIndexOf('.')) || input; - this.check_unique_slide(input_val).then(function (exist) { + this._checkUniqueSlide(input_val).then(function (exist) { if (exist) { var message = _t("Channel contains the given title, please change before Save or Publish."); - self.display_alert(message); + self._displayAlert(message); } self.$('#name').val(input_val); }); }, - reset_file: function () { - var control = this.$('#upload'); - control.replaceWith(control = control.clone(true)); - this.file.name = false; - }, - display_alert: function (message) { + /** + * @override + * @param {Object} ev + */ + _slideUrl: function (ev) { + var self = this, + value = { + 'url': $(ev.target).val(), + 'channel_id': self.channel_id + }; this.$('.alert-warning').remove(); - $('').insertBefore(this.$('form')); + this.is_valid_url = false; + this.$('.save').button('loading'); + ajax.jsonRpc('/slides/dialog_preview/', 'call', value).then(function (data) { + self.$('.save').button('reset'); + if (data.error) { + self._displayAlert(data.error); + } else { + self.$("#slide-image").attr("src", data.url_src); + self.$('#name').val(data.title); + self.$('#description').val(data.description); + self.is_valid_url = true; + } + }); + }, + +}); + +sAnimations.registry.websiteSlidesUpload = sAnimations.Class.extend({ + selector: '.oe_slide_js_upload', + xmlDependencies: ['/website_slides/static/src/xml/website_slides.xml'], + read_events: { + 'click .oe_slide_js_upload': '_bindEventButton', }, /** - Wrapper for select2 load data from server at once and store it. + * @override + * @param {Object} parent + */ + start: function (parent) { + // Automatically open the upload dialog if requested from query string + if ($.deparam.querystring().enable_slide_upload !== undefined) { + $('.oe_slide_js_upload').click(); + } + }, - @param {String} Placeholder for element. - @param {bool} true for multiple selection box, false for single selection - @param {Function} Function to fetch data from remote location should return $.deferred object - resolved data should be array of object with id and name. eg. [{'id': id, 'name': 'text'}, ...] - @returns {Object} select2 wrapper object - */ - select2_wrapper: function (tag, multi, fetch_fnc) { - return { - width: '100%', - placeholder: tag, - allowClear: true, - formatNoMatches: false, - multiple: multi, - selection_data: false, - fetch_rpc_fnc : fetch_fnc, - formatSelection: function (data) { - if (data.tag) { - data.text = data.tag; - } - return data.text; - }, - createSearchChoice: function (term, data) { - var added_tags = $(this.opts.element).select2('data'); - if (_.filter(_.union(added_tags, data), function (tag) { - return tag.text.toLowerCase().localeCompare(term.toLowerCase()) === 0; - }).length === 0) { - return { - id: _.uniqueId('tag_'), - create: true, - tag: term, - text: _.str.sprintf(_t("Create new tag '%s'"), term), - }; - } - }, - fill_data: function (query, data) { - var that = this, - tags = {results: []}; - _.each(data, function (obj) { - if (that.matcher(query.term, obj.name)) { - tags.results.push({id: obj.id, text: obj.name }); - } - }); - query.callback(tags); - }, - query: function (query) { - var that = this; - // fetch data only once and store it - if (!this.selection_data) { - this.fetch_rpc_fnc().then(function (data) { - that.fill_data(query, data); - that.selection_data = data; - }); - } else { - this.fill_data(query, this.selection_data); - } - } - }; - }, - // Category management from select2 - set_category_id: function () { - var self = this; - $('#category_id').select2(this.select2_wrapper(_t('Category'), false, - function () { - return ajax.jsonRpc("/web/dataset/call_kw", 'call', { - model: 'slide.category', - method: 'search_read', - args: [], - kwargs: { - fields: ['name'], - domain: [['channel_id', '=', self.channel_id]], - context: weContext.get(), // TODO use this._rpc - } - }); - })); - }, - get_category_id: function () { - var value = $('#category_id').select2('data'); - if (value && value.create) { - return [0, {'name': value.text}]; - } - return [value ? value.id : null]; - }, - // Tags management from select2 - set_tag_ids: function () { - $('#tag_ids').select2(this.select2_wrapper(_t('Tags'), true, function () { - return ajax.jsonRpc("/web/dataset/call_kw", 'call', { - model: 'slide.tag', - method: 'search_read', - args: [], - kwargs: { - fields: ['name'], - context: weContext.get(), // TODO use this._rpc - } - }); - })); - }, - get_tag_ids: function () { - var res = []; - _.each($('#tag_ids').select2('data'), - function (val) { - if (val.create) { - res.push([0, 0, {'name': val.text}]); - } else { - res.push([4, val.id]); - } - }); - return res; - }, - // TODO: Remove this part, as now SVG support in image resize tools is included - //Python PIL does not support SVG, so converting SVG to PNG - svg_to_png: function () { - var img = this.$el.find("img#slide-image")[0]; - var canvas = document.createElement("canvas"); - canvas.width = img.width; - canvas.height = img.height; - canvas.getContext("2d").drawImage(img, 0, 0); - return canvas.toDataURL("image/png").split(',')[1]; - }, - // Values and save - get_value: function () { - var canvas = this.$('#data_canvas')[0], - values = { - 'channel_id': this.channel_id || '', - 'name': this.$('#name').val(), - 'url': this.$('#url').val(), - 'description': this.$('#description').val(), - 'tag_ids': this.get_tag_ids(), - 'category_id': this.get_category_id() - }; - if (this.file.type === 'application/pdf') { - _.extend(values, { - 'image': canvas.toDataURL().split(',')[1], - 'index_content': this.index_content, - 'slide_type': canvas.height > canvas.width ? 'document' : 'presentation', - 'mime_type': this.file.type, - 'datas': this.file.data - }); - } - if (/^image\/.*/.test(this.file.type)) { - _.extend(values, { - 'slide_type': 'infographic', - 'mime_type': this.file.type === 'image/svg+xml' ? 'image/png' : this.file.type, - 'datas': this.file.type === 'image/svg+xml' ? this.svg_to_png() : this.file.data - }); - } - return values; - }, - validate: function () { - this.$('.form-group').removeClass('o_has_error').find('.form-control, .custom-select').removeClass('is-invalid'); - if (!this.$('#name').val()) { - this.$('#name').closest('.form-group').addClass('o_has_error').find('.form-control, .custom-select').addClass('is-invalid'); - return false; - } - var url = this.$('#url').val() ? this.is_valid_url : false; - if (!(this.file.name || url)) { - this.$('#url').closest('.form-group').addClass('o_has_error').find('.form-control, .custom-select').addClass('is-invalid'); - return false; - } - return true; - }, - save: function (ev) { - var self = this; - if (this.validate()) { - var values = this.get_value(); - if ($(ev.target).data('published')) { - values.website_published = true; - } - this.$('.oe_slides_upload_loading').show(); - this.$('.modal-footer, .modal-body').hide(); - ajax.jsonRpc("/slides/add_slide", 'call', values).then(function (data) { - if (data.error) { - self.display_alert(data.error); - self.$('.oe_slides_upload_loading').hide(); - self.$('.modal-footer, .modal-body').show(); + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- - } else { - window.location = data.url; - } - }); - } + /** + * @override + */ + _bindEventButton: function () { + var channel_id = $(this).attr('channel_id'); + slides.page_widgets['upload_dialog'] = new SlideDialog(this, channel_id).appendTo(document.body); }, - cancel: function () { - this.trigger("cancel"); - } -}); - -// bind the event to the button -$('.oe_slide_js_upload').on('click', function () { - var channel_id = $(this).attr('channel_id'); - slides.page_widgets['upload_dialog'] = new SlideDialog(this, channel_id).appendTo(document.body); -}); - -// automatically open the upload dialog if requested from query string -if ($.deparam.querystring().enable_slide_upload !== undefined) { - $('.oe_slide_js_upload').click(); -} + +}); });