diff --git a/addons/website_slides/controllers/main.py b/addons/website_slides/controllers/main.py index e7fd8c238b8..e314965f52b 100644 --- a/addons/website_slides/controllers/main.py +++ b/addons/website_slides/controllers/main.py @@ -644,6 +644,24 @@ class WebsiteSlides(WebsiteProfile): return {'error': 'join_done'} return success + @http.route('/slides/channel/resequence', type="json", website=True, auth="user") + def resequence_slides(self, channel_id, slides_data): + """" Reorder the slides within the channel by reassigning their 'sequence' field. + This method also handles slides that are put in a new category. """ + channel = request.env['slide.channel'].browse(int(channel_id)) + if not channel.can_publish: + return {'error': 'Only the publishers of the channel can edit it'} + + slides = request.env['slide.slide'].search([ + ('id', 'in', [int(key) for key in slides_data.keys()]), + ('channel_id', '=', channel.id) + ]) + + for slide in slides: + slide_key = str(slide.id) + slide.sequence = slides_data[slide_key]['sequence'] + slide.category_id = slides_data[slide_key]['category_id'] + @http.route(['/slides/prepare_preview'], type='json', auth='user', methods=['POST'], website=True) def prepare_preview(self, **data): Slide = request.env['slide.slide'] @@ -741,21 +759,6 @@ class WebsiteSlides(WebsiteProfile): 'can_create': can_create, } - #Not using the /web/dataset/resequence route as a slide can be dragged into another category at the same time - @http.route('/slides/resequence_slides', type="json", website=True, auth="user") - def resequence_slides(self, slides_data=None, **kw): - channel_user = None - for slide in slides_data: - s = request.env['slide.slide'].browse(slide['id']) - if not channel_user: - channel_user = s.channel_id.user_id - if request.env.user != channel_user: - return {'error': 'Only the responsible of the channel can edit it'} - s.write({ - 'sequence': slide['sequence'], - 'category_id': slide['category_id'] - }) - # -------------------------------------------------- # EMBED IN THIRD PARTY WEBSITES # -------------------------------------------------- diff --git a/addons/website_slides/static/src/js/slides_course_slides_list.js b/addons/website_slides/static/src/js/slides_course_slides_list.js index d5fb61bbc5c..17f0d0893aa 100644 --- a/addons/website_slides/static/src/js/slides_course_slides_list.js +++ b/addons/website_slides/static/src/js/slides_course_slides_list.js @@ -1,251 +1,127 @@ odoo.define('website_slides.slideslist', function (require) { - 'use strict'; - var sAnimations = require('website.content.snippets.animation'); - var Widget = require('web.Widget'); +'use strict'; - var SlideUpload = require('website_slides.upload_modal'); +var sAnimations = require('website.content.snippets.animation'); - var List = Widget.extend({ - init: function (el){ - this._super.apply(this,arguments); - this.draggedElement = undefined; - this.dropTarget = undefined; - this.slideCount = undefined; - this.slides = []; - this.categories = []; - }, - start: function (){ - this._super.apply(this,arguments); - this.slideCount = $('li.o_wslides_content_slide').length; - //Change links HREF to fullscreen mode for SEO - var links = $('.o_wslides_course_slide_link'); - for (var i = 0; i < links.length; i++){ - $(links[i]).attr('href', $(links[i]).attr('href') + "?fullscreen=1"); - } - this._bindEvents(); - }, - _bindEvents: function (){ - var self = this; - $('.slide-draggable').each(function (){ - self._addSlideDragAndDropHandlers($(this)); - }); - $('.section-draggable').each(function (){ - self._addSectionDragAndDropHandlers($(this)); - }); - $('.course-section').each(function (){ - self._addDropSlideOnSectionHandler($(this)); - }); - }, - _unbind: function (className){ - $("."+className).each(function (){ - $(this).unbind(); - }); - }, - _unbindAll: function (){ - this._unbind('slide-draggable'); - this._unbind('section-draggable'); - this._unbind('course-section'); - }, - _getSlides: function (){ - var self = this; - var slides = $('li.o_wsldies_content_slide'); - for (var i = 0; i < slides.length;i++){ - var slide = $(slides[i]); - self.slides.push({ - id: parseInt(slide.attr('slide_id')), - category_id: parseInt(slide.attr('category_id')), - sequence: i - }); - } - }, - _getCategories: function (){ - var self = this; - self.categories = []; - var categories = $('.course-section'); - for (var i = 0; i < categories.length;i++){ - var category = $(categories[i]); - self.categories.push(parseInt(category.attr('category_id'))); - } - }, - _addDropSlideOnSectionHandler: function (target){ - var self = this; - target.on('drop', function (ev){ - if (ev.preventDefault){ - ev.preventDefault(); - } - self.dropTarget = $(ev.currentTarget); - self.draggedElement[0].parentNode.removeChild(self.draggedElement[0]); - $('ul[category_id='+target.attr('category_id')+']').append(self.draggedElement); - self._addSlideDragAndDropHandlers(self.draggedElement); - self._reorderSlides(); - }); - target.on('dragover', function (ev){ - if (ev.preventDefault){ - ev.preventDefault(); - } - }); - }, - _addSlideDragAndDropHandlers: function (target){ - var self = this; - target.on('dragstart', function (ev){ - $('.section-draggable').removeClass('hold'); - self._unbind('section-draggable'); - ev.originalEvent.dataTransfer.effectAllowed = 'move'; - ev.originalEvent.dataTransfer.setData('text/html', this.outerHTML); - self.draggedElement = target; - self.draggedElement.addClass('hold'); - }); - target.on('dragover', function (ev){ - if ($(ev.currentTarget) !== self.draggedElement){ - if (ev.preventDefault){ - ev.preventDefault(); - } - target.addClass('slide-hovered'); - } - }); - target.on('dragleave', function (ev){ - if (ev.preventDefault){ - ev.preventDefault(); - } - target.removeClass('slide-hovered'); - }); - target.on('drop', function (ev){ - if (self.draggedElement.hasClass('slide-draggable') && target.hasClass('slide-draggable')){ - if (ev.preventDefault){ - ev.preventDefault(); - } - target.removeClass('slide-hovered'); - target.removeClass('hold'); - if (target !== self.draggedElement){ - self.dropTarget = $(ev.currentTarget); - self.draggedElement[0].parentNode.removeChild(self.draggedElement[0]); - var dropHTML = ev.originalEvent.dataTransfer.getData('text/html'); - target[0].insertAdjacentHTML('beforebegin',dropHTML); - self.draggedElement = $(target[0].previousSibling); - self._reorderSlides(); - } - self._unbindAll(); - self._bindEvents(); - } - }); - target.on('dragend', function (ev){ - if (ev.preventDefault){ - ev.preventDefault(); - } - target.removeClass('slide-hovered'); - target.removeClass('hold'); - }); - }, - _addSectionDragAndDropHandlers: function (target){ - var self = this; - target.on('dragstart', function (ev){ - self._unbind('slide-draggable'); - self._unbind('course-section'); - ev.originalEvent.dataTransfer.effectAllowed = 'move'; - ev.originalEvent.dataTransfer.setData('text/html', this.outerHTML); - self.draggedElement = target; - self.draggedElement.addClass('hold'); - }); - target.on('dragover', function (ev){ - if (target.hasClass('section-draggable') && self.draggedElement.hasClass('section-draggable')){ - if (ev.preventDefault){ - ev.preventDefault(); - } - target.addClass('slide-hovered'); - } - }); - target.on('dragleave', function (ev){ - if (ev.preventDefault){ - ev.preventDefault(); - } - target.removeClass('slide-hovered'); - }); - target.on('drop', function (ev){ - if (ev.preventDefault){ - ev.preventDefault(); - } - if (self.draggedElement.hasClass('section-draggable') && target.hasClass('section-draggable')){ - target.removeClass('slide-hovered'); - target.removeClass('hold'); - self.dropTarget = $(ev.currentTarget); - if (target !== self.draggedElement && $(ev.currentTarget).hasClass('section-draggable')){ - self.draggedElement[0].parentNode.removeChild(self.draggedElement[0]); - var dropHTML = ev.originalEvent.dataTransfer.getData('text/html'); - target[0].insertAdjacentHTML('beforebegin',dropHTML); - self.draggedElement = $(target[0].previousSibling); - self._reorderCategories(); - self._reorderSlides(); - self._rebindUploadButton(self.draggedElement.attr('category_id')); - } - self._unbindAll(); - self._bindEvents(); - } - }); - target.on('dragend', function (ev){ - if (ev.preventDefault){ - ev.preventDefault(); - } - target.removeClass('slide-hovered'); - target.removeClass('hold'); - }); - }, - _reorderCategories: function (){ - var self = this; - self._getCategories(); - self._rpc({ - route: '/web/dataset/resequence', - params: { - model: "slide.category", - ids: self.categories - } - }).then(function (){ - self._resetCategoriesIndex(); - }); - }, - _resetCategoriesIndex: function (){ - var categoriesIndexes = $('.section-index'); - for (var i = 0; i < categoriesIndexes.length; i++){ - $(categoriesIndexes[i]).text(i+1); - } - }, - _reorderSlides: function (){ - var self = this; - // In case the slide was transfered to another section - if (self.draggedElement.hasClass('slide-draggable')){ - self.draggedElement.attr('category_id', parseInt(self.dropTarget.attr('category_id'))); - } - self.slides = []; - self._getSlides(); - self._rpc({ - route: "/slides/resequence_slides", - params: { - slides_data: self.slides - } - }).then(function (){ - }); - }, - _rebindUploadButton: function (categoryID){ - var self = this; - this.$('.oe_slide_js_upload[data-category-id='+categoryID+']').click(function (ev){ - ev.preventDefault(); - var data = $(ev.currentTarget).data(); - var dialog = new SlideUpload.SlideUploadDialog(self, data); - dialog.appendTo(document.body); - dialog.open(); - }); - } - }); +sAnimations.registry.websiteSlidesCourseSlidesList = sAnimations.Class.extend({ + selector: '.o_wslides_slides_list', + xmlDependencies: ['/website_slides/static/src/xml/website_slides_upload.xml'], + + start: function () { + this._super.apply(this,arguments); + + this.channelId = this.$el.data('channelId'); + + this._updateHref(); + this._bindSortable(); + }, + + //-------------------------------------------------------------------------- + // Private + //--------------------------------------------------------------------------, + + /** + * Bind the sortable jQuery widget to both + * - course sections + * - course slides + * + * @private + */ + _bindSortable: function () { + this.$('ul.o_wslides_slides_list_container').sortable({ + handle: '.fa-arrows', + stop: this._reorderCategories.bind(this) + }); + + this.$('.o_wslides_slides_list_container ul').sortable({ + handle: '.fa-arrows', + connectWith: '.o_wslides_slides_list_container ul', + stop: this._reorderSlides.bind(this), + items: '.o_wslides_slides_list_slide' + }); + }, + + _getCategories: function (){ + var categories = []; + this.$('.o_wslides_slide_list_category_container').each(function (){ + categories.push(parseInt($(this).attr('category_id'))); + }); + + return categories; + }, + + /** + * Returns a slides dict in the form: + * {slide_id: {'sequence': slide_sequence, 'category_id': slide.category_id.id}} + * + * @private + */ + _getSlides: function (){ + var slides = {}; + this.$('li.o_wslides_slides_list_slide').each(function (index){ + var $slide = $(this); + slides[$slide.attr('slide_id')] = { + category_id: parseInt( + $slide.closest('.o_wslides_slide_list_category').attr('category_id') + ), + sequence: index + }; + }); + + return slides; + }, + + _reorderCategories: function (){ + var self = this; + self._rpc({ + route: '/web/dataset/resequence', + params: { + model: "slide.category", + ids: self._getCategories() + } + }).then(function (){ + self._resetCategoriesIndex(); + }); + }, + + _reorderSlides: function (){ + this._rpc({ + route: "/slides/channel/resequence", + params: { + channel_id: this.channelId, + slides_data: this._getSlides() + } + }); + }, + + /** + * Used to reset the categories numbering (1, 2, 3, ...) in the UI + */ + _resetCategoriesIndex: function (){ + this.$('.section-index').each(function (index){ + $(this).text(index + 1); + }); + }, + + /** + * Change links href to fullscreen mode for SEO. + * + * Specifications demand that links are generated (xml) without the "fullscreen" + * parameter for SEO purposes. + * + * This method then adds the parameter as soon as the page is loaded. + * + * @private + */ + _updateHref: function () { + this.$(".o_wslides_slides_list_slide_link").each(function (){ + var href = $(this).attr('href'); + var operator = href.indexOf('?') !== -1 ? '&' : '?'; + $(this).attr('href', href + operator + "fullscreen=1"); + }); + } +}); + +return sAnimations.registry.websiteSlidesCourseSlidesList; - sAnimations.registry.websiteSlidesCourseSlidesList = Widget.extend({ - selector: '.oe_js_course_slides_list', - xmlDependencies: ['/website_slides/static/src/xml/website_slides_upload.xml'], - init: function (el){ - this._super.apply(this, arguments); - }, - start: function (){ - this._super.apply(this, arguments); - var list = new List(this); - list.appendTo(".oe_js_course_slides_list"); - } - }); }); \ No newline at end of file diff --git a/addons/website_slides/static/src/js/slides_slide_archive.js b/addons/website_slides/static/src/js/slides_slide_archive.js index 5be5a1b384e..a5d8747fdbc 100644 --- a/addons/website_slides/static/src/js/slides_slide_archive.js +++ b/addons/website_slides/static/src/js/slides_slide_archive.js @@ -47,7 +47,7 @@ var SlideArchiveDialog = Dialog.extend({ slide_id: this.slideId }, }).then(function () { - self.$slideTarget.closest('.o_wslides_content_slide').remove(); + self.$slideTarget.closest('.o_wslides_slides_list_slide').remove(); self.close(); }); } diff --git a/addons/website_slides/static/src/js/slides_upload.js b/addons/website_slides/static/src/js/slides_upload.js index d5abc73017b..9dca5c09774 100644 --- a/addons/website_slides/static/src/js/slides_upload.js +++ b/addons/website_slides/static/src/js/slides_upload.js @@ -311,25 +311,6 @@ var SlideUploadDialog = Dialog.extend({ return values; }, - _reorderSlidesSequence: function (){ - var self = this; - var slidesElement = $('li.o_wslides_content_slide'); - var slides = []; - for (var i = 0; i < slidesElement.length;i++){ - slides.push({ - id: parseInt($(slidesElement[i]).attr('slide_id')), - category_id: parseInt($(slidesElement[i]).attr('category_id')), - sequence: i - }); - } - self._rpc({ - route: '/slides/resequence_slides', - params: { - slides_data: slides - } - }).then(function (){ - }); - }, /** * Init the data relative to the support slide type to upload * @@ -539,12 +520,6 @@ var SlideUploadDialog = Dialog.extend({ self.set('state', oldType); self._alertDisplay(data.error); } else { - //Quick and really dirty fix for reordering issues - if (data.channel_type === 'training' && self.categoryID){ - var categoryElement = $('ul[category_id='+self.categoryID+']'); - $('