diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/mail/static/src/components/drop_zone | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/mail/static/src/components/drop_zone')
3 files changed, 180 insertions, 0 deletions
diff --git a/addons/mail/static/src/components/drop_zone/drop_zone.js b/addons/mail/static/src/components/drop_zone/drop_zone.js new file mode 100644 index 00000000..dcbb7019 --- /dev/null +++ b/addons/mail/static/src/components/drop_zone/drop_zone.js @@ -0,0 +1,139 @@ +odoo.define('mail/static/src/components/drop_zone/drop_zone.js', function (require) { +'use strict'; + +const useShouldUpdateBasedOnProps = require('mail/static/src/component_hooks/use_should_update_based_on_props/use_should_update_based_on_props.js'); + +const { Component, useState } = owl; + +class DropZone extends Component { + + /** + * @override + */ + constructor(...args) { + super(...args); + useShouldUpdateBasedOnProps(); + this.state = useState({ + /** + * Determine whether the user is dragging files over the dropzone. + * Useful to provide visual feedback in that case. + */ + isDraggingInside: false, + }); + /** + * Counts how many drag enter/leave happened on self and children. This + * ensures the drop effect stays active when dragging over a child. + */ + this._dragCount = 0; + } + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * Returns whether the given node is self or a children of self. + * + * @param {Node} node + * @returns {boolean} + */ + contains(node) { + return this.el.contains(node); + } + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * Making sure that dragging content is external files. + * Ignoring other content dragging like text. + * + * @private + * @param {DataTransfer} dataTransfer + * @returns {boolean} + */ + _isDragSourceExternalFile(dataTransfer) { + const dragDataType = dataTransfer.types; + if (dragDataType.constructor === window.DOMStringList) { + return dragDataType.contains('Files'); + } + if (dragDataType.constructor === Array) { + return dragDataType.includes('Files'); + } + return false; + } + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * Shows a visual drop effect when dragging inside the dropzone. + * + * @private + * @param {DragEvent} ev + */ + _onDragenter(ev) { + ev.preventDefault(); + if (this._dragCount === 0) { + this.state.isDraggingInside = true; + } + this._dragCount++; + } + + /** + * Hides the visual drop effect when dragging outside the dropzone. + * + * @private + * @param {DragEvent} ev + */ + _onDragleave(ev) { + this._dragCount--; + if (this._dragCount === 0) { + this.state.isDraggingInside = false; + } + } + + /** + * Prevents default (from the template) in order to receive the drop event. + * The drop effect cursor works only when set on dragover. + * + * @private + * @param {DragEvent} ev + */ + _onDragover(ev) { + ev.preventDefault(); + ev.dataTransfer.dropEffect = 'copy'; + } + + /** + * Triggers the `o-dropzone-files-dropped` event when new files are dropped + * on the dropzone, and then removes the visual drop effect. + * + * The parents should handle this event to process the files as they wish, + * such as uploading them. + * + * @private + * @param {DragEvent} ev + */ + _onDrop(ev) { + ev.preventDefault(); + if (this._isDragSourceExternalFile(ev.dataTransfer)) { + this.trigger('o-dropzone-files-dropped', { + files: ev.dataTransfer.files, + }); + } + this.state.isDraggingInside = false; + } + +} + +Object.assign(DropZone, { + props: {}, + template: 'mail.DropZone', +}); + +return DropZone; + +}); diff --git a/addons/mail/static/src/components/drop_zone/drop_zone.scss b/addons/mail/static/src/components/drop_zone/drop_zone.scss new file mode 100644 index 00000000..202e4ceb --- /dev/null +++ b/addons/mail/static/src/components/drop_zone/drop_zone.scss @@ -0,0 +1,29 @@ +// ------------------------------------------------------------------ +// Layout +// ------------------------------------------------------------------ + +.o_DropZone { + display: flex; + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + z-index: 1; + align-items: center; + justify-content: center; +} + +// ------------------------------------------------------------------ +// Style +// ------------------------------------------------------------------ + +.o_DropZone { + color: $o-enterprise-primary-color; + background: rgba(255, 255, 255, 0.9); + border: 2px dashed $o-enterprise-primary-color; + + &.o-dragging-inside { + border-width: 5px; + } +} diff --git a/addons/mail/static/src/components/drop_zone/drop_zone.xml b/addons/mail/static/src/components/drop_zone/drop_zone.xml new file mode 100644 index 00000000..b3db940f --- /dev/null +++ b/addons/mail/static/src/components/drop_zone/drop_zone.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<templates xml:space="preserve"> + + <t t-name="mail.DropZone" owl="1"> + <div class="o_DropZone" t-att-class="{ 'o-dragging-inside': state.isDraggingInside }" t-on-dragenter="_onDragenter" t-on-dragleave="_onDragleave" t-on-dragover="_onDragover" t-on-drop="_onDrop"> + <h4> + Drag Files Here <i class="fa fa-download"/> + </h4> + </div> + </t> + +</templates> |
