diff options
| author | Laurent Stukkens (LTU) <ltu@odoo.com> | 2020-07-02 16:08:10 +0000 |
|---|---|---|
| committer | Laurent Stukkens (LTU) <ltu@odoo.com> | 2020-07-08 12:13:33 +0000 |
| commit | 6df67a28c2f113572acd4a3db19ab6b1bd37e7da (patch) | |
| tree | 91bd842dbfbed5cb96a7b706adcc9893e241ed3e /addons/web_editor/static/src/js/editor | |
| parent | ec7986cba3953dc6dfe16f0b1e0bdd13dac2b347 (diff) | |
[REF] web_editor,web: reuse the autoscroll on drag feature
Prior to this commit, the autoscroll on drag feature was accessible and only
used in the web_editor application.
After this commit, the autoscroll on drag feature will be available in the
web application and has been refactored in order to allow its usage
in other application (as for the sign application).
task-2280965
closes odoo/odoo#54072
Related: odoo/enterprise#11656
Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
Diffstat (limited to 'addons/web_editor/static/src/js/editor')
| -rw-r--r-- | addons/web_editor/static/src/js/editor/snippets.editor.js | 419 |
1 files changed, 132 insertions, 287 deletions
diff --git a/addons/web_editor/static/src/js/editor/snippets.editor.js b/addons/web_editor/static/src/js/editor/snippets.editor.js index 76b19dc62ed..d198af532b7 100644 --- a/addons/web_editor/static/src/js/editor/snippets.editor.js +++ b/addons/web_editor/static/src/js/editor/snippets.editor.js @@ -10,6 +10,7 @@ var Widget = require('web.Widget'); var options = require('web_editor.snippets.options'); var Wysiwyg = require('web_editor.wysiwyg'); const {ColorPaletteWidget} = require('web_editor.ColorPalette'); +const SmoothScrollOnDrag = require('web/static/src/js/core/smooth_scroll_on_drag.js'); var _t = core._t; @@ -20,169 +21,6 @@ var globalSelector = { }; /** - * Component that provides smooth scroll behaviour on drag. - * - * Do not forget to call unsetDraggable to ensure proper resource clearing. - * @see {@link unsetDraggable}. - */ -const SmoothOnDragComponent = Class.extend({ - /** - * @constructor - * @param {jQuery} $element The element the smooth drag has to be set on - * @param {Object} jQueryDraggableOptions The configuration to be passed to - * the jQuery draggable function - */ - init($element, jQueryDraggableOptions) { - this.$element = $element; - this.$scrollTarget = $('html'); - this.autoScrollHandler = null; - this.cursorAt = jQueryDraggableOptions.cursorAt || {left: 0, top: 0}; - this.draggableOffset = 0; - this.mainNavBarHeight = $('.o_main_navbar').innerHeight(); - this.scrollOffsetThreshold = 150; - this.scrollStep = 20; - this.scrollStepDirection = 1; - this.scrollStepDirectionEnum = {up: -1, down: 1}; - this.scrollDecelerator = 0; - this.scrollTimer = 5; - this.visibleBottomOffset = 0; - this.visibleTopOffset = 0; - - jQueryDraggableOptions.scroll = false; - const draggableOptions = Object.assign({}, jQueryDraggableOptions, { - start: (ev, ui) => this._onSmoothDragStart(ev, ui, jQueryDraggableOptions.start), - drag: (ev, ui) => this._onSmoothDrag(ev, ui, jQueryDraggableOptions.drag), - stop: (ev, ui) => this._onSmoothDragStop(ev, ui, jQueryDraggableOptions.stop), - }); - this.$element.draggable(draggableOptions); - }, - - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- - - /** - * Ensures correct clearing of resources. - */ - unsetDraggable() { - this._stopSmoothScroll(); - }, - - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - - /** - * Starts the scroll process using the options. - * The options will be updated dynamically when the handler _onSmoothDrag - * will be called. The interval will be cleared when the handler - * _onSmoothDragStop will be called. - * - * @private - */ - _startSmoothScroll() { - this._stopSmoothScroll(); - this.autoScrollHandler = setInterval( - () => { - this.$scrollTarget.scrollTop( - this.$scrollTarget.scrollTop() + - this.scrollStepDirection * - this.scrollStep * - (1 - this.scrollDecelerator) - ); - }, - this.scrollTimer - ); - }, - /** - * Stops the scroll process if any is running. - * - * @private - */ - _stopSmoothScroll() { - clearInterval(this.autoScrollHandler); - }, - /** - * Updates the options depending on the offset position of the draggable - * helper. In the same time options are used by an interval to trigger - * scroll behaviour. - * @see {@link _startSmoothScroll} for interval implementation details. - * - * @private - * @param {number} dragTopOffset The offset position of the draggable helper - */ - _updatePositionOptions(dragTopOffset) { - this.draggableOffset = this.cursorAt.top + dragTopOffset; - this.visibleBottomOffset = this.$scrollTarget.scrollTop() + - this.$scrollTarget.get(0).clientHeight - this.draggableOffset; - this.visibleTopOffset = this.draggableOffset - this.$scrollTarget.scrollTop(); - if (this.visibleTopOffset <= this.scrollOffsetThreshold + this.mainNavBarHeight) { - this.scrollDecelerator = this.visibleTopOffset / - (this.scrollOffsetThreshold + this.mainNavBarHeight); - this.scrollStepDirection = this.scrollStepDirectionEnum.up; - } else if (this.visibleBottomOffset <= this.scrollOffsetThreshold) { - this.scrollDecelerator = this.visibleBottomOffset / - this.scrollOffsetThreshold; - this.scrollStepDirection = this.scrollStepDirectionEnum.down; - } else { - this.scrollDecelerator = 1; - } - }, - - //-------------------------------------------------------------------------- - // Handlers - //-------------------------------------------------------------------------- - - /** - * Called when dragging the element. - * Updates the position options and call the provided callback if any. - * - * @private - * @param {Object} ev The jQuery drag handler event parameter. - * @param {Object} ui The jQuery drag handler ui parameter. - * @param {Function} onDragCallback The jQuery drag callback. - */ - _onSmoothDrag(ev, ui, onDragCallback) { - this._updatePositionOptions(ui.offset.top); - if (typeof onDragCallback === 'function') { - onDragCallback.call(ui.helper, ev, ui); - } - }, - /** - * Called when starting to drag the element. - * Updates the position params, starts smooth scrolling process and call the - * provided callback if any. - * - * @private - * @param {Object} ev The jQuery drag handler event parameter. - * @param {Object} ui The jQuery drag handler ui parameter. - * @param {Function} onDragStartCallBack The jQuery drag callback. - */ - _onSmoothDragStart(ev, ui, onDragStartCallBack) { - this._updatePositionOptions(ui.offset.top); - this._startSmoothScroll(); - if (typeof onDragStartCallBack === 'function') { - onDragStartCallBack.call(ui.helper, ev, ui); - } - }, - /** - * Called when stopping to drag the element. - * Stops the smooth scrolling process and call the provided callback if any. - * - * @private - * @param {Object} ev The jQuery drag handler event parameter. - * @param {Object} ui The jQuery drag handler ui parameter. - * @param {Function} onDragEndCallBack The jQuery drag callback. - */ - _onSmoothDragStop(ev, ui, onDragEndCallBack) { - this._stopSmoothScroll(); - if (typeof onDragEndCallBack === 'function') { - onDragEndCallBack.call(ui.helper, ev, ui); - } - }, -}); - -/** * Management of the overlay and option list for a snippet. */ var SnippetEditor = Widget.extend({ @@ -235,32 +73,39 @@ var SnippetEditor = Widget.extend({ // Initialize move/clone/remove buttons if (this.isTargetMovable) { this.dropped = false; - this.draggableComponent = new SmoothOnDragComponent(this.$el, { - appendTo: this.$body, - cursor: 'move', - cursorAt: { - left: 10, - top: 10 - }, - greedy: true, - handle: '.o_move_handle', - helper: () => { - var $clone = this.$el.clone().css({width: '24px', height: '24px', border: 0}); - $clone.appendTo(this.$body).removeClass('d-none'); - return $clone; + const smoothScrollOptions = { + offsetElements: { + $top: $('#top'), + $left: $('#oe_snippets'), }, - scroll: false, - start: this._onDragAndDropStart.bind(this), - stop: (...args) => { - // Delay our stop handler so that some summernote handlers - // which occur on mouseup (and are themself delayed) are - // executed first (this prevents the library to crash - // because our stop handler may change the DOM). - setTimeout(() => { - this._onDragAndDropStop(...args); - }, 0); + jQueryDraggableOptions: { + appendTo: this.$body, + cursor: 'move', + cursorAt: { + left: 10, + top: 10 + }, + greedy: true, + handle: '.o_move_handle', + helper: () => { + var $clone = this.$el.clone().css({width: '24px', height: '24px', border: 0}); + $clone.appendTo(this.$body).removeClass('d-none'); + return $clone; + }, + scroll: false, + start: this._onDragAndDropStart.bind(this), + stop: (...args) => { + // Delay our stop handler so that some summernote handlers + // which occur on mouseup (and are themself delayed) are + // executed first (this prevents the library to crash + // because our stop handler may change the DOM). + setTimeout(() => { + this._onDragAndDropStop(...args); + }, 0); + }, }, - }); + }; + this.draggableComponent = new SmoothScrollOnDrag(this, this.$el, $('html'), smoothScrollOptions); } else { this.$('.o_overlay_move_options').addClass('d-none'); $customize.find('.oe_snippet_clone').addClass('d-none'); @@ -304,9 +149,6 @@ var SnippetEditor = Widget.extend({ */ destroy: function () { this._super(...arguments); - if (this.draggableComponent) { - this.draggableComponent.unsetDraggable(); - } this.$target.removeData('snippet-editor'); this.$target.off('.snippet_editor'); }, @@ -1186,9 +1028,6 @@ var SnippetsMenu = Widget.extend({ */ destroy: function () { this._super.apply(this, arguments); - if (this.draggableComponent) { - this.draggableComponent.unsetDraggable(); - } if (this.$window) { this.$snippetEditorArea.remove(); this.$window.off('.snippets_menu'); @@ -1929,117 +1768,124 @@ var SnippetsMenu = Widget.extend({ var $tumb = $snippets.find('.oe_snippet_thumbnail_img:first'); var $toInsert, dropped, $snippet; - this.draggableComponent = new SmoothOnDragComponent($snippets, { - appendTo: this.$body, - cursor: 'move', - distance: 0, - greedy: true, - handle: '.oe_snippet_thumbnail', - helper: function () { - const dragSnip = this.cloneNode(true); - dragSnip.querySelectorAll('.o_delete_btn, .o_image_ribbon').forEach( - el => el.remove() - ); - return dragSnip; + const smoothScrollOptions = { + offsetElements: { + $top: $('#top'), + $left: $('#oe_snippets'), }, - scroll: false, - start: function () { - dropped = false; - $snippet = $(this); - var $baseBody = $snippet.find('.oe_snippet_body'); - var $selectorSiblings = $(); - var $selectorChildren = $(); - var temp = self.templateOptions; - for (var k in temp) { - if ($baseBody.is(temp[k].base_selector) && !$baseBody.is(temp[k].base_exclude)) { - if (temp[k]['drop-near']) { - $selectorSiblings = $selectorSiblings.add(temp[k]['drop-near'].all()); - } - if (temp[k]['drop-in']) { - $selectorChildren = $selectorChildren.add(temp[k]['drop-in'].all()); + jQueryDraggableOptions: { + appendTo: this.$body, + cursor: 'move', + distance: 0, + greedy: true, + handle: '.oe_snippet_thumbnail', + helper: function () { + const dragSnip = this.cloneNode(true); + dragSnip.querySelectorAll('.o_delete_btn, .o_image_ribbon').forEach( + el => el.remove() + ); + return dragSnip; + }, + scroll: false, + start: function () { + dropped = false; + $snippet = $(this); + var $baseBody = $snippet.find('.oe_snippet_body'); + var $selectorSiblings = $(); + var $selectorChildren = $(); + var temp = self.templateOptions; + for (var k in temp) { + if ($baseBody.is(temp[k].base_selector) && !$baseBody.is(temp[k].base_exclude)) { + if (temp[k]['drop-near']) { + $selectorSiblings = $selectorSiblings.add(temp[k]['drop-near'].all()); + } + if (temp[k]['drop-in']) { + $selectorChildren = $selectorChildren.add(temp[k]['drop-in'].all()); + } } } - } - $toInsert = $baseBody.clone(); + $toInsert = $baseBody.clone(); - if (!$selectorSiblings.length && !$selectorChildren.length) { - console.warn($snippet.find('.oe_snippet_thumbnail_title').text() + " have not insert action: data-drop-near or data-drop-in"); - return; - } + if (!$selectorSiblings.length && !$selectorChildren.length) { + console.warn($snippet.find('.oe_snippet_thumbnail_title').text() + " have not insert action: data-drop-near or data-drop-in"); + return; + } - self._activateSnippet(false); - self._activateInsertionZones($selectorSiblings, $selectorChildren); + self._activateSnippet(false); + self._activateInsertionZones($selectorSiblings, $selectorChildren); - self.getEditableArea().find('.oe_drop_zone').droppable({ - over: function () { - if (!dropped) { + self.getEditableArea().find('.oe_drop_zone').droppable({ + over: function () { + if (!dropped) { + dropped = true; + $(this).first().after($toInsert).addClass('d-none'); + $toInsert.removeClass('oe_snippet_body'); + } + }, + out: function () { + var prev = $toInsert.prev(); + if (this === prev[0]) { + dropped = false; + $toInsert.detach(); + $(this).removeClass('d-none'); + $toInsert.addClass('oe_snippet_body'); + } + }, + }); + }, + stop: function (ev, ui) { + $toInsert.removeClass('oe_snippet_body'); + + if (!dropped && ui.position.top > 3 && ui.position.left + 50 > self.$el.outerWidth()) { + var $el = $.nearest({x: ui.position.left, y: ui.position.top}, '.oe_drop_zone', {container: document.body}).first(); + if ($el.length) { + $el.after($toInsert); dropped = true; - $(this).first().after($toInsert).addClass('d-none'); - $toInsert.removeClass('oe_snippet_body'); } - }, - out: function () { - var prev = $toInsert.prev(); - if (this === prev[0]) { - dropped = false; - $toInsert.detach(); - $(this).removeClass('d-none'); - $toInsert.addClass('oe_snippet_body'); - } - }, - }); - }, - stop: function (ev, ui) { - $toInsert.removeClass('oe_snippet_body'); - - if (!dropped && ui.position.top > 3 && ui.position.left + 50 > self.$el.outerWidth()) { - var $el = $.nearest({x: ui.position.left, y: ui.position.top}, '.oe_drop_zone', {container: document.body}).first(); - if ($el.length) { - $el.after($toInsert); - dropped = true; } - } - self.getEditableArea().find('.oe_drop_zone').droppable('destroy').remove(); + self.getEditableArea().find('.oe_drop_zone').droppable('destroy').remove(); - if (dropped) { - var prev = $toInsert.first()[0].previousSibling; - var next = $toInsert.last()[0].nextSibling; + if (dropped) { + var prev = $toInsert.first()[0].previousSibling; + var next = $toInsert.last()[0].nextSibling; - if (prev) { - $toInsert.detach(); - self.trigger_up('request_history_undo_record', {$target: $(prev)}); - $toInsert.insertAfter(prev); - } else if (next) { - $toInsert.detach(); - self.trigger_up('request_history_undo_record', {$target: $(next)}); - $toInsert.insertBefore(next); - } else { - var $parent = $toInsert.parent(); - $toInsert.detach(); - self.trigger_up('request_history_undo_record', {$target: $parent}); - $parent.prepend($toInsert); - } + if (prev) { + $toInsert.detach(); + self.trigger_up('request_history_undo_record', {$target: $(prev)}); + $toInsert.insertAfter(prev); + } else if (next) { + $toInsert.detach(); + self.trigger_up('request_history_undo_record', {$target: $(next)}); + $toInsert.insertBefore(next); + } else { + var $parent = $toInsert.parent(); + $toInsert.detach(); + self.trigger_up('request_history_undo_record', {$target: $parent}); + $parent.prepend($toInsert); + } - var $target = $toInsert; + var $target = $toInsert; - _.defer(function () { - self.trigger_up('snippet_dropped', {$target: $target}); - self._disableUndroppableSnippets(); + _.defer(function () { + self.trigger_up('snippet_dropped', {$target: $target}); + self._disableUndroppableSnippets(); - self._callForEachChildSnippet($target, function (editor, $snippet) { - return editor.buildSnippet(); - }).then(function () { - $target.trigger('content_changed'); - return self._updateInvisibleDOM(); + self._callForEachChildSnippet($target, function (editor, $snippet) { + return editor.buildSnippet(); + }).then(function () { + $target.trigger('content_changed'); + return self._updateInvisibleDOM(); + }); }); - }); - } else { - $toInsert.remove(); - } + } else { + $toInsert.remove(); + } + }, }, - }); + }; + this.draggableComponent = new SmoothScrollOnDrag(this, $snippets, $('html'), smoothScrollOptions); }, /** * Adds the 'o_default_snippet_text' class on nodes which contain only @@ -2439,7 +2285,6 @@ var SnippetsMenu = Widget.extend({ return { Class: SnippetsMenu, Editor: SnippetEditor, - SmoothOnDragComponent: SmoothOnDragComponent, globalSelector: globalSelector, }; }); |
