From f8632ec6f3485912aed850a4f59934061baa1cc7 Mon Sep 17 00:00:00 2001 From: Samuel Degueldre Date: Mon, 9 Dec 2019 06:51:17 +0000 Subject: [PATCH] [IMP] web_editor: add an image-picker UserValueWidget This commit introduces a new web_editor UserValueWidget on the we-imagepicker tag, this widget allows the user to pick an image or a video using the MediaDialog, and calls the containing snippet option's method (specified via data-attribute) with the url of the chosen picture or video as widgetValue. Videos are disabled by default and can be accessed through the use of the data-allow-videos="selector" data attribute, any $target that matches the selector will have videos available in the media dialog. Part of odoo/odoo#41561 task-2155808 --- .../static/src/js/editor/snippets.options.js | 99 +++++++++++++ .../static/src/js/wysiwyg/widgets/media.js | 136 +++++++++--------- .../static/src/scss/wysiwyg_snippets.scss | 11 +- 3 files changed, 173 insertions(+), 73 deletions(-) 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 9e46a728c51..39e6e0c2f11 100644 --- a/addons/web_editor/static/src/js/editor/snippets.options.js +++ b/addons/web_editor/static/src/js/editor/snippets.options.js @@ -1069,6 +1069,104 @@ const ColorpickerUserValueWidget = SelectUserValueWidget.extend({ }, }); +const ImagepickerUserValueWidget = UserValueWidget.extend({ + tagName: 'we-imagepicker', + events: { + 'click .o_we_edit_image': '_onEditImage', + 'click .o_we_remove_image': '_onRemoveImage', + }, + + /** + * @override + */ + start: async function () { + await this._super(...arguments); + const allowedSelector = this.el.dataset.allowVideos; + this.firstFilters = (this.el.dataset.firstFilters || '').split(',').filter(s => s !== ''); + this.allowVideos = allowedSelector ? this.$target.is(allowedSelector) : false; + + this.editImageButton = document.createElement('we-button'); + this.editImageButton.classList.add('o_we_edit_image', 'fa', 'fa-fw', 'fa-edit'); + + this.removeImageButton = document.createElement('we-button'); + this.removeImageButton.classList.add('o_we_remove_image', 'fa', 'fa-fw', 'fa-times'); + this.removeImageButton.title = _t("Remove"); + + this.containerEl.appendChild(this.editImageButton); + this.containerEl.appendChild(this.removeImageButton); + }, + /** + * @override + */ + getMethodsParams: function (methodName) { + return _.extend({isVideo: this.isVideo}, this._super(...arguments)); + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @override + */ + _updateUI: async function () { + await this._super(...arguments); + this.removeImageButton.classList.toggle('d-none', !this.isActive()); + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * Called when the edit background button is clicked. + * + * @private + */ + _onEditImage: function (ev) { + // Need a dummy element for the media dialog to modify. + const dummyEl = document.createElement(this.isVideo ? 'iframe' : 'img'); + dummyEl.src = this._value; + if (this.isVideo) { + // Allows the mediaDialog to select the video tab immediately. + dummyEl.classList.add('media_iframe_video'); + } + const $editable = this.$target.closest('.o_editable'); + const mediaDialog = new weWidgets.MediaDialog(this, { + noIcons: true, + noDocuments: true, + noVideos: !this.allowVideos, + isForBgVideo: true, + res_model: $editable.data('oe-model'), + res_id: $editable.data('oe-id'), + firstFilters: this.firstFilters, + }, dummyEl).open(); + mediaDialog.on('save', this, data => { + if (data.bgVideoSrc) { + this._value = data.bgVideoSrc; + this.isVideo = true; + } else { + // Accessing the value directly through dummyEl.src converts the url to absolute + // using getAttribute allows us to keep the url as it was inserted in the DOM + // which can be useful to compare it to values stored in db. + this._value = dummyEl.getAttribute('src'); + this.isVideo = false; + } + this._notifyValueChange(false); + }); + }, + /** + * Called when the remove background button is clicked. + * + * @private + */ + _onRemoveImage: function (ev) { + this._value = ''; + this.isVideo = false; + this._notifyValueChange(false); + }, +}); + const DatetimePickerUserValueWidget = InputUserValueWidget.extend({ events: { // Explicitely not consider all InputUserValueWidget events 'blur input': '_onInputBlur', @@ -1200,6 +1298,7 @@ const userValueWidgetsRegistry = { 'we-multi': MultiUserValueWidget, 'we-colorpicker': ColorpickerUserValueWidget, 'we-datetimepicker': DatetimePickerUserValueWidget, + 'we-imagepicker': ImagepickerUserValueWidget, }; /** 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 5b1f7338683..011989f16e0 100644 --- a/addons/web_editor/static/src/js/wysiwyg/widgets/media.js +++ b/addons/web_editor/static/src/js/wysiwyg/widgets/media.js @@ -1102,82 +1102,19 @@ var VideoWidget = MediaWidget.extend({ */ _createVideoNode: function (url, options) { options = options || {}; - - // Video url patterns(youtube, instagram, vimeo, dailymotion, youku, ...) - var ytRegExp = /^(?:(?:https?:)?\/\/)?(?:www\.)?(?:youtu\.be\/|youtube(-nocookie)?\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((?:\w|-){11})(?:\S+)?$/; - var ytMatch = url.match(ytRegExp); - - var insRegExp = /(.*)instagram.com\/p\/(.[a-zA-Z0-9]*)/; - var insMatch = url.match(insRegExp); - - var vinRegExp = /\/\/vine.co\/v\/(.[a-zA-Z0-9]*)/; - var vinMatch = url.match(vinRegExp); - - var vimRegExp = /\/\/(player.)?vimeo.com\/([a-z]*\/)*([0-9]{6,11})[?]?.*/; - var vimMatch = url.match(vimRegExp); - - var dmRegExp = /.+dailymotion.com\/(video|hub|embed)\/([^_]+)[^#]*(#video=([^_&]+))?/; - var dmMatch = url.match(dmRegExp); - - var ykuRegExp = /(.*).youku\.com\/(v_show\/id_|embed\/)(.+)/; - var ykuMatch = url.match(ykuRegExp); - - var $video = $('