From da95ff210d93da512809d9f917f3e62264d01fe6 Mon Sep 17 00:00:00 2001 From: qsm-odoo Date: Fri, 13 Sep 2019 11:57:41 +0000 Subject: [FIX] web_editor: allow better usability to crop all image zones Before this commit, when rotating an image so that it overflew the cropper canvas, it was not possible to unzoom on some part of the image. Now, with the new set of options used by this commit, the cropping zone and the image can be moved independently allowing to do everything. Part of https://github.com/odoo/odoo/pull/36880 task-2059480 --- addons/web_editor/static/src/js/wysiwyg/widgets/crop_dialog.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'addons/web_editor/static/src') diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/crop_dialog.js b/addons/web_editor/static/src/js/wysiwyg/widgets/crop_dialog.js index 19623d05f5e..3c8e653f366 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/crop_dialog.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/crop_dialog.js @@ -116,8 +116,9 @@ var CropImageDialog = Dialog.extend({ } } this.$cropperImage.cropper({ - viewMode: 1, - autoCropArea: 1, + viewMode: 2, + dragMode: 'move', + autoCropArea: 1.0, aspectRatio: ratio, data: _.pick(data, 'x', 'y', 'width', 'height', 'rotate', 'scaleX', 'scaleY') }); -- cgit v1.2.3 From aa9db571e30787da8e5d486de7d0a86828dd4e79 Mon Sep 17 00:00:00 2001 From: qsm-odoo Date: Fri, 13 Sep 2019 14:44:20 +0000 Subject: [REF] web_editor: update the cropper library Just after we first added the library in Odoo (in april 2018), the library was released in its last and deprecated version (4.0.0). At the same time, the author indeed split its 'cropper' library into 2 parts: 'cropperjs' which is the core of the original library without jquery and 'jquery-cropper' which is a jquery wrapper of the 'cropperjs' library. This commit updates our code to use the latest version of those two libraries. Note: the commit also removes the lazy loading of the library which is useless and maybe breaking since it comes with the editor assets which are themself lazy loaded. Note 2: we may want to remove the jquery wrapper in another update and simply use the standard JS library. Part of https://github.com/odoo/odoo/pull/36880 task-2059480 closes odoo/odoo#36880 Signed-off-by: Quentin Smetz (qsm) --- addons/web_editor/static/src/js/wysiwyg/widgets/crop_dialog.js | 6 ------ 1 file changed, 6 deletions(-) (limited to 'addons/web_editor/static/src') diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/crop_dialog.js b/addons/web_editor/static/src/js/wysiwyg/widgets/crop_dialog.js index 3c8e653f366..9f827410221 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/crop_dialog.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/crop_dialog.js @@ -14,12 +14,6 @@ var CropImageDialog = Dialog.extend({ xmlDependencies: Dialog.prototype.xmlDependencies.concat( ['/web_editor/static/src/xml/wysiwyg.xml'] ), - jsLibs: [ - '/web_editor/static/lib/cropper/js/cropper.js', - ], - cssLibs: [ - '/web_editor/static/lib/cropper/css/cropper.css', - ], events: _.extend({}, Dialog.prototype.events, { 'click .o_crop_options [data-event]': '_onCropOptionClick', }), -- cgit v1.2.3 From 57f92e2a8b8e6991031eed136681fce08cfd2a44 Mon Sep 17 00:00:00 2001 From: qsm-odoo Date: Tue, 17 Sep 2019 11:15:42 +0000 Subject: [FIX] website_blog, *: restore blog/post cover edition * web_editor, website Editing the cover images or sizes was not working anymore. When it worked, it was thanks to the 'o_dirty' class appearing magically on a cover part... and that magic seems to be gone. This commit fixes the problem by adding the 'o_dirty' class on all elements whose content is changed, not only the editable ones (this is the case for the blog cover: it is a non editable element whose bg image can be changed). Note: this also fixes the edition of multiple covers (of different blogs or posts) at the same time (this could be backported in 12.0 if needed). closes odoo/odoo#36999 Signed-off-by: Quentin Smetz (qsm) --- addons/web_editor/static/src/js/editor/rte.js | 20 +++++++++++++++++--- .../static/src/js/wysiwyg/wysiwyg_snippets.js | 2 -- 2 files changed, 17 insertions(+), 5 deletions(-) (limited to 'addons/web_editor/static/src') diff --git a/addons/web_editor/static/src/js/editor/rte.js b/addons/web_editor/static/src/js/editor/rte.js index bfd7994b161..eecee43a5c6 100644 --- a/addons/web_editor/static/src/js/editor/rte.js +++ b/addons/web_editor/static/src/js/editor/rte.js @@ -323,11 +323,20 @@ var RTEWidget = Widget.extend({ }); // start element observation - $(document).on('content_changed', '.o_editable', function (ev) { + $(document).on('content_changed', function (ev) { self.trigger_up('rte_change', {target: ev.target}); + + // Add the dirty flag to the element that changed by either adding + // it on the highest editable ancestor or, if there is no editable + // ancestor, on the element itself (that element may not be editable + // but if it received a content_changed event, it should be marked + // as dirty to allow for custom savings). if (!ev.__isDirtyHandled) { - $(this).addClass('o_dirty'); ev.__isDirtyHandled = true; + + var el = ev.target; + var dirty = el.closest('.o_editable') || el; + dirty.classList.add('o_dirty'); } }); @@ -586,11 +595,16 @@ var RTEWidget = Widget.extend({ * page element) */ _saveElement: function ($el, context, withLang) { + var viewID = $el.data('oe-id'); + if (!viewID) { + return Promise.resolve(); + } + return this._rpc({ model: 'ir.ui.view', method: 'save', args: [ - $el.data('oe-id'), + viewID, this._getEscapedElement($el).prop('outerHTML'), $el.data('oe-xpath') || null, ], diff --git a/addons/web_editor/static/src/js/wysiwyg/wysiwyg_snippets.js b/addons/web_editor/static/src/js/wysiwyg/wysiwyg_snippets.js index 4b095029432..df6d243ffc6 100644 --- a/addons/web_editor/static/src/js/wysiwyg/wysiwyg_snippets.js +++ b/addons/web_editor/static/src/js/wysiwyg/wysiwyg_snippets.js @@ -20,8 +20,6 @@ Wysiwyg.include({ await this.editor.prependTo(this.$editor[0].ownerDocument.body); this.options.toolbarHandler.append(this.editor.$el); this.$el.on('content_changed', function (e) { - var $editable = $(e.target).closest('[data-oe-model], .o_editable'); - $editable.addClass('o_dirty'); self.trigger_up('wysiwyg_change'); }); } else { -- cgit v1.2.3 From 17237ff31c15984ad6cf891e2a54d726ed09b58a Mon Sep 17 00:00:00 2001 From: Kishan Gajjar Date: Tue, 11 Jun 2019 07:08:59 +0000 Subject: [IMP] website, *: allow to set background video to snippets * web_editor This commit adds support to set background videos to all the snippets that already support setting background images (except on parallax background for now). task-1920630 closes odoo/odoo#36261 Signed-off-by: Quentin Smetz (qsm) Co-authored-by: Varun Raval Co-authored-by: qsm-odoo --- .../static/src/js/editor/snippets.options.js | 101 ++++++++++++++++----- .../static/src/js/wysiwyg/widgets/media.js | 27 +++--- .../static/src/js/wysiwyg/widgets/media_dialog.js | 2 +- addons/web_editor/static/src/xml/wysiwyg.xml | 2 +- 4 files changed, 95 insertions(+), 37 deletions(-) (limited to 'addons/web_editor/static/src') diff --git a/addons/web_editor/static/src/js/editor/snippets.options.js b/addons/web_editor/static/src/js/editor/snippets.options.js index f124d1841f0..5b493dfef0d 100644 --- a/addons/web_editor/static/src/js/editor/snippets.options.js +++ b/addons/web_editor/static/src/js/editor/snippets.options.js @@ -838,23 +838,18 @@ registry.background = SnippetOption.extend({ * @see this.selectClass for parameters */ chooseImage: function (previewMode, value, $opt) { - // Put fake image in the DOM, edit it and use it as background-image - var $image = $('', {class: 'd-none', src: value === 'true' ? '' : value}).appendTo(this.$target); + var options = this._getMediaDialogOptions(); + var media = this._getEditableMedia(); - var $editable = this.$target.closest('.o_editable'); - var _editor = new weWidgets.MediaDialog(this, { - 'onlyImages': true, - 'firstFilters': ['background'], - 'res_model': $editable.data('oe-model'), - 'res_id': $editable.data('oe-id'), - }, $image[0]).open(); - - _editor.on('save', this, function () { - this._setCustomBackground($image.attr('src')); + var _editor = new weWidgets.MediaDialog(this, options, media).open(); + _editor.on('save', this, data => { + this._onSaveMediaDialog(data); this.$target.trigger('content_changed'); }); - _editor.on('closed', this, function () { - $image.remove(); + _editor.on('closed', this, () => { + if (media.classList.contains('o_we_fake_image')) { + media.parentNode.removeChild(media); + } }); }, @@ -871,16 +866,7 @@ registry.background = SnippetOption.extend({ return; } this.$target.off('.background-option') - .on('background-color-event.background-option', (function (e, previewMode) { - e.stopPropagation(); - if (e.currentTarget !== e.target) { - return; - } - if (previewMode === false) { - this.__customImageSrc = undefined; - } - this.background(previewMode); - }).bind(this)); + .on('background-color-event.background-option', this._onBackgroundColorUpdate.bind(this)); }, /** * @override @@ -896,6 +882,37 @@ registry.background = SnippetOption.extend({ // Private //-------------------------------------------------------------------------- + /** + * Returns a media element the media dialog will be able to edit to use + * the result as the snippet's background somehow. + * + * @private + * @returns {HTMLElement} + */ + _getEditableMedia: function () { + var $image = $('', { + class: 'd-none o_we_fake_image', + }).appendTo(this.$target); + return $image[0]; + }, + /** + * Returns the options to be given to the MediaDialog instance when choosing + * a snippet's background. + * + * @private + * @returns {Object} + */ + _getMediaDialogOptions: function () { + var $editable = this.$target.closest('.o_editable'); + return { + noDocuments: true, + noIcons: true, + noVideos: true, + firstFilters: ['background'], + res_model: $editable.data('oe-model'), + res_id: $editable.data('oe-id'), + }; + }, /** * Returns the src value from a css value related to a background image * (e.g. "url('blabla')" => "blabla" / "none" => ""). @@ -941,6 +958,42 @@ registry.background = SnippetOption.extend({ this._setActive(); this.$target.trigger('snippet-option-change', [this]); }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * Called on background-color update (useful to remove the background to be + * able to see the chosen color). + * + * @private + * @param {Event} ev + * @param {boolean|string} previewMode + * @returns {boolean} true if the color has been applied (removing the + * background) + */ + _onBackgroundColorUpdate: function (ev, previewMode) { + ev.stopPropagation(); + if (ev.currentTarget !== ev.target) { + return false; + } + if (previewMode === false) { + this.__customImageSrc = undefined; + } + this.background(previewMode); + return true; + }, + /** + * Called on media dialog save (when choosing a snippet's background) -> + * sets the resulting media as the snippet's background somehow. + * + * @private + * @param {Object} data + */ + _onSaveMediaDialog: function (data) { + this._setCustomBackground(data.src); + }, }); /** diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/media.js b/addons/web_editor/static/src/js/wysiwyg/widgets/media.js index cbb39ea6173..a6a9fb675fd 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/media.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/media.js @@ -1009,8 +1009,9 @@ var VideoWidget = MediaWidget.extend({ /** * @constructor */ - init: function (parent, media) { + init: function (parent, media, options) { this._super.apply(this, arguments); + this.isForBgVideo = !!options.isForBgVideo; this._onVideoCodeInput = _.debounce(this._onVideoCodeInput, 1000); }, /** @@ -1021,7 +1022,7 @@ var VideoWidget = MediaWidget.extend({ if (this.media) { var $media = $(this.media); - var src = $media.data('oe-expression') || $media.data('src') || ''; + var src = $media.data('oe-expression') || $media.data('src') || ($media.is('iframe') ? $media.attr('src') : '') || ''; this.$('textarea#o_video_text').val(src); this.$('input#o_video_autoplay').prop('checked', src.indexOf('autoplay=1') >= 0); @@ -1047,6 +1048,9 @@ var VideoWidget = MediaWidget.extend({ */ save: function () { this._updateVideo(); + if (this.isForBgVideo) { + return Promise.resolve({bgVideoSrc: this.$content.attr('src')}); + } if (this.$('.o_video_dialog_iframe').is('iframe')) { this.$media = $( '
' + @@ -1200,13 +1204,13 @@ var VideoWidget = MediaWidget.extend({ var url = embedMatch ? embedMatch[1] : code; var query = this._createVideoNode(url, { - autoplay: this.$('input#o_video_autoplay').is(':checked'), - hide_controls: this.$('input#o_video_hide_controls').is(':checked'), - loop: this.$('input#o_video_loop').is(':checked'), - hide_fullscreen: this.$('input#o_video_hide_fullscreen').is(':checked'), - hide_yt_logo: this.$('input#o_video_hide_yt_logo').is(':checked'), - hide_dm_logo: this.$('input#o_video_hide_dm_logo').is(':checked'), - hide_dm_share: this.$('input#o_video_hide_dm_share').is(':checked'), + 'autoplay': this.isForBgVideo || this.$('input#o_video_autoplay').is(':checked'), + 'hide_controls': this.isForBgVideo || this.$('input#o_video_hide_controls').is(':checked'), + 'loop': this.isForBgVideo || this.$('input#o_video_loop').is(':checked'), + 'hide_fullscreen': this.isForBgVideo || this.$('input#o_video_hide_fullscreen').is(':checked'), + 'hide_yt_logo': this.isForBgVideo || this.$('input#o_video_hide_yt_logo').is(':checked'), + 'hide_dm_logo': this.isForBgVideo || this.$('input#o_video_hide_dm_logo').is(':checked'), + 'hide_dm_share': this.isForBgVideo || this.$('input#o_video_hide_dm_share').is(':checked'), }); var $optBox = this.$('.o_video_dialog_options'); @@ -1222,8 +1226,9 @@ var VideoWidget = MediaWidget.extend({ // Individually show / hide options base on the video provider $optBox.find('div.o_' + query.type + '_option').removeClass('d-none'); - // Hide the entire options box if no options are available - $optBox.toggleClass('d-none', $optBox.find('div:not(.d-none)').length === 0); + // Hide the entire options box if no options are available or if the + // dialog is opened for a background-video + $optBox.toggleClass('d-none', this.isForBgVideo || $optBox.find('div:not(.d-none)').length === 0); if (query.type === 'yt') { // Youtube only: If 'hide controls' is checked, hide 'fullscreen' diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js b/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js index 84dd8e7f650..6d1f2b642c7 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/media_dialog.js @@ -76,7 +76,7 @@ var MediaDialog = Dialog.extend({ this.activeWidget = this.imageWidget; } else if (this.documentWidget && $media.is('a.o_image')) { this.activeWidget = this.documentWidget; - } else if (this.videoWidget && $media.hasClass('media_iframe_video')) { + } else if (this.videoWidget && $media.is('.media_iframe_video, .o_bg_video_iframe')) { this.activeWidget = this.videoWidget; } else if (this.iconWidget && $media.is('span, i')) { this.activeWidget = this.iconWidget; diff --git a/addons/web_editor/static/src/xml/wysiwyg.xml b/addons/web_editor/static/src/xml/wysiwyg.xml index b9b29a8984e..bcf3a480a93 100644 --- a/addons/web_editor/static/src/xml/wysiwyg.xml +++ b/addons/web_editor/static/src/xml/wysiwyg.xml @@ -383,7 +383,7 @@