diff --git a/setup/web_drop_target/odoo/addons/web_drop_target b/setup/web_drop_target/odoo/addons/web_drop_target new file mode 120000 index 000000000..58aaa3635 --- /dev/null +++ b/setup/web_drop_target/odoo/addons/web_drop_target @@ -0,0 +1 @@ +../../../../web_drop_target \ No newline at end of file diff --git a/setup/web_drop_target/setup.py b/setup/web_drop_target/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/web_drop_target/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/web_drop_target/README.rst b/web_drop_target/README.rst new file mode 100644 index 000000000..befcca661 --- /dev/null +++ b/web_drop_target/README.rst @@ -0,0 +1,107 @@ +=================== +Drop target support +=================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github + :target: https://github.com/OCA/web/tree/14.0/web_drop_target + :alt: OCA/web +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/web-14-0/web-14-0-web_drop_target + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/162/14.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module is meant as a base drag&drop module supporting other actions after some file is dropped so that other modules can add more features. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To use this module, you need to: + +#. drag a file from your local computer onto an Odoo form view +#. it should become an attachment of the currently opened record + +.. image:: https://raw.githubusercontent.com/web_drop_target/static/description/screenshot.png + :alt: Screenshot + +Development +=========== + +**Libraries** + +* `base64js `_. + +Known issues / Roadmap +====================== + +* dropping on list or kanban views would be nice too +* handle multiple files +* add an upload progress meter for huge files +* trigger custom events about different stages of the drop operation for other addons to hook in +* Install document module to display attachments in the sidebar + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Therp BV + +Contributors +~~~~~~~~~~~~ + +* Holger Brunn +* Pablo Fuentes +* Akim Juillerat +* Enric Tobella +* Lois Rilo +* `Tecnativa `__: + + * Alexandre D. Díaz + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/web `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/web_drop_target/__init__.py b/web_drop_target/__init__.py new file mode 100644 index 000000000..f7c59d20c --- /dev/null +++ b/web_drop_target/__init__.py @@ -0,0 +1,2 @@ +# Copyright 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). diff --git a/web_drop_target/__manifest__.py b/web_drop_target/__manifest__.py new file mode 100644 index 000000000..009dfa047 --- /dev/null +++ b/web_drop_target/__manifest__.py @@ -0,0 +1,21 @@ +# Copyright 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +{ + "name": "Drop target support", + "version": "15.0.1.0.0", + "author": "Therp BV,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/web", + "license": "AGPL-3", + "category": "Usability", + "summary": "Allows to drag files into Odoo", + "depends": ["web"], + "data": [], + "assets": { + "web.assets_backend": [ + "web_drop_target/static/lib/base64js.min.js", + "web_drop_target/static/src/js/web_drop_target.js", + "web_drop_target/static/src/scss/web_drop_target.scss", + ], + "web.assets_qweb": ["web_drop_target/static/src/xml/widgets.xml"], + }, +} diff --git a/web_drop_target/i18n/de.po b/web_drop_target/i18n/de.po new file mode 100644 index 000000000..3457580b7 --- /dev/null +++ b/web_drop_target/i18n/de.po @@ -0,0 +1,31 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_drop_target +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-10-13 20:46+0000\n" +"Last-Translator: Corneliuus \n" +"Language-Team: none\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: web_drop_target +#. openerp-web +#: code:addons/web_drop_target/static/src/xml/widgets.xml:0 +#, python-format +msgid "Drop your files here" +msgstr "Legen Sie Ihre Dateien hier ab" + +#. module: web_drop_target +#. openerp-web +#: code:addons/web_drop_target/static/src/xml/widgets.xml:0 +#, python-format +msgid "Please save the record before dropping a file" +msgstr "Bitte speichern Sie den Datensatz, bevor Sie eine Datei ablegen" diff --git a/web_drop_target/i18n/es.po b/web_drop_target/i18n/es.po new file mode 100644 index 000000000..4b164cc75 --- /dev/null +++ b/web_drop_target/i18n/es.po @@ -0,0 +1,31 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_drop_target +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-02-17 14:45+0000\n" +"Last-Translator: claudiagn \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: web_drop_target +#. openerp-web +#: code:addons/web_drop_target/static/src/xml/widgets.xml:0 +#, python-format +msgid "Drop your files here" +msgstr "Suelta tus archivos aquí" + +#. module: web_drop_target +#. openerp-web +#: code:addons/web_drop_target/static/src/xml/widgets.xml:0 +#, python-format +msgid "Please save the record before dropping a file" +msgstr "Guarde el registro antes de soltar un archivo" diff --git a/web_drop_target/i18n/fr.po b/web_drop_target/i18n/fr.po new file mode 100644 index 000000000..01535ce28 --- /dev/null +++ b/web_drop_target/i18n/fr.po @@ -0,0 +1,32 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_drop_target +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-07-10 14:31+0000\n" +"PO-Revision-Date: 2020-07-22 12:19+0000\n" +"Last-Translator: c2cdidier \n" +"Language-Team: \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 3.10\n" + +#. module: web_drop_target +#. openerp-web +#: code:addons/web_drop_target/static/src/xml/widgets.xml:0 +#, python-format +msgid "Drop your files here" +msgstr "Déposez les fichiers ici" + +#. module: web_drop_target +#. openerp-web +#: code:addons/web_drop_target/static/src/xml/widgets.xml:0 +#, python-format +msgid "Please save the record before dropping a file" +msgstr "Veuillez sauver la donnée avant de supprimer le fichier" diff --git a/web_drop_target/i18n/it.po b/web_drop_target/i18n/it.po new file mode 100644 index 000000000..f1f2c91ae --- /dev/null +++ b/web_drop_target/i18n/it.po @@ -0,0 +1,31 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_drop_target +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-02-04 18:44+0000\n" +"Last-Translator: Alessandro Fiorino \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: web_drop_target +#. openerp-web +#: code:addons/web_drop_target/static/src/xml/widgets.xml:0 +#, python-format +msgid "Drop your files here" +msgstr "Lascia i tuoi file qui" + +#. module: web_drop_target +#. openerp-web +#: code:addons/web_drop_target/static/src/xml/widgets.xml:0 +#, python-format +msgid "Please save the record before dropping a file" +msgstr "Prego salvare il record prima di lasciare un file" diff --git a/web_drop_target/i18n/nl.po b/web_drop_target/i18n/nl.po new file mode 100644 index 000000000..5cad5549e --- /dev/null +++ b/web_drop_target/i18n/nl.po @@ -0,0 +1,31 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_drop_target +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-04-22 15:47+0000\n" +"Last-Translator: Bosd \n" +"Language-Team: none\n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: web_drop_target +#. openerp-web +#: code:addons/web_drop_target/static/src/xml/widgets.xml:0 +#, python-format +msgid "Drop your files here" +msgstr "Sleep uw bestanden hierheen" + +#. module: web_drop_target +#. openerp-web +#: code:addons/web_drop_target/static/src/xml/widgets.xml:0 +#, python-format +msgid "Please save the record before dropping a file" +msgstr "Sla eerst het record op voordat je hier een bestand plaatst" diff --git a/web_drop_target/i18n/web_drop_target.pot b/web_drop_target/i18n/web_drop_target.pot new file mode 100644 index 000000000..e24b18f3f --- /dev/null +++ b/web_drop_target/i18n/web_drop_target.pot @@ -0,0 +1,28 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_drop_target +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: web_drop_target +#. openerp-web +#: code:addons/web_drop_target/static/src/xml/widgets.xml:0 +#, python-format +msgid "Drop your files here" +msgstr "" + +#. module: web_drop_target +#. openerp-web +#: code:addons/web_drop_target/static/src/xml/widgets.xml:0 +#, python-format +msgid "Please save the record before dropping a file" +msgstr "" diff --git a/web_drop_target/readme/CONTRIBUTORS.rst b/web_drop_target/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..dd61eccfb --- /dev/null +++ b/web_drop_target/readme/CONTRIBUTORS.rst @@ -0,0 +1,8 @@ +* Holger Brunn +* Pablo Fuentes +* Akim Juillerat +* Enric Tobella +* Lois Rilo +* `Tecnativa `__: + + * Alexandre D. Díaz diff --git a/web_drop_target/readme/DESCRIPTION.rst b/web_drop_target/readme/DESCRIPTION.rst new file mode 100644 index 000000000..4b4a6145d --- /dev/null +++ b/web_drop_target/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module is meant as a base drag&drop module supporting other actions after some file is dropped so that other modules can add more features. diff --git a/web_drop_target/readme/DEVELOP.rst b/web_drop_target/readme/DEVELOP.rst new file mode 100644 index 000000000..b91df8e2d --- /dev/null +++ b/web_drop_target/readme/DEVELOP.rst @@ -0,0 +1,3 @@ +**Libraries** + +* `base64js `_. diff --git a/web_drop_target/readme/ROADMAP.rst b/web_drop_target/readme/ROADMAP.rst new file mode 100644 index 000000000..486912d63 --- /dev/null +++ b/web_drop_target/readme/ROADMAP.rst @@ -0,0 +1,5 @@ +* dropping on list or kanban views would be nice too +* handle multiple files +* add an upload progress meter for huge files +* trigger custom events about different stages of the drop operation for other addons to hook in +* Install document module to display attachments in the sidebar diff --git a/web_drop_target/readme/USAGE.rst b/web_drop_target/readme/USAGE.rst new file mode 100644 index 000000000..9db80f992 --- /dev/null +++ b/web_drop_target/readme/USAGE.rst @@ -0,0 +1,7 @@ +To use this module, you need to: + +#. drag a file from your local computer onto an Odoo form view +#. it should become an attachment of the currently opened record + +.. image:: /web_drop_target/static/description/screenshot.png + :alt: Screenshot diff --git a/web_drop_target/static/description/icon.png b/web_drop_target/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/web_drop_target/static/description/icon.png differ diff --git a/web_drop_target/static/description/index.html b/web_drop_target/static/description/index.html new file mode 100644 index 000000000..ef35cc733 --- /dev/null +++ b/web_drop_target/static/description/index.html @@ -0,0 +1,456 @@ + + + + + + +Drop target support + + + +
+

Drop target support

+ + +

Beta License: AGPL-3 OCA/web Translate me on Weblate Try me on Runbot

+

This module is meant as a base drag&drop module supporting other actions after some file is dropped so that other modules can add more features.

+

Table of contents

+ +
+

Usage

+

To use this module, you need to:

+
    +
  1. drag a file from your local computer onto an Odoo form view
  2. +
  3. it should become an attachment of the currently opened record
  4. +
+Screenshot +
+
+

Development

+

Libraries

+ +
+
+

Known issues / Roadmap

+
    +
  • dropping on list or kanban views would be nice too
  • +
  • handle multiple files
  • +
  • add an upload progress meter for huge files
  • +
  • trigger custom events about different stages of the drop operation for other addons to hook in
  • +
  • Install document module to display attachments in the sidebar
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Therp BV
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/web project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/web_drop_target/static/description/screenshot.png b/web_drop_target/static/description/screenshot.png new file mode 100644 index 000000000..88dc4dced Binary files /dev/null and b/web_drop_target/static/description/screenshot.png differ diff --git a/web_drop_target/static/lib/base64js.min.js b/web_drop_target/static/lib/base64js.min.js new file mode 100644 index 000000000..8b055fb56 --- /dev/null +++ b/web_drop_target/static/lib/base64js.min.js @@ -0,0 +1 @@ +(function(r){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=r()}else if(typeof define==="function"&&define.amd){define([],r)}else{var e;if(typeof window!=="undefined"){e=window}else if(typeof global!=="undefined"){e=global}else if(typeof self!=="undefined"){e=self}else{e=this}e.base64js=r()}})(function(){var r,e,n;return function(){function r(e,n,t){function o(i,a){if(!n[i]){if(!e[i]){var u=typeof require=="function"&&require;if(!a&&u)return u(i,!0);if(f)return f(i,!0);var d=new Error("Cannot find module '"+i+"'");throw d.code="MODULE_NOT_FOUND",d}var c=n[i]={exports:{}};e[i][0].call(c.exports,function(r){var n=e[i][1][r];return o(n?n:r)},c,c.exports,r,e,n,t)}return n[i].exports}var f=typeof require=="function"&&require;for(var i=0;i0){throw new Error("Invalid string. Length must be a multiple of 4")}return r[e-2]==="="?2:r[e-1]==="="?1:0}function c(r){return r.length*3/4-d(r)}function v(r){var e,n,t,i,a;var u=r.length;i=d(r);a=new f(u*3/4-i);n=i>0?u-4:u;var c=0;for(e=0;e>16&255;a[c++]=t>>8&255;a[c++]=t&255}if(i===2){t=o[r.charCodeAt(e)]<<2|o[r.charCodeAt(e+1)]>>4;a[c++]=t&255}else if(i===1){t=o[r.charCodeAt(e)]<<10|o[r.charCodeAt(e+1)]<<4|o[r.charCodeAt(e+2)]>>2;a[c++]=t>>8&255;a[c++]=t&255}return a}function l(r){return t[r>>18&63]+t[r>>12&63]+t[r>>6&63]+t[r&63]}function h(r,e,n){var t;var o=[];for(var f=e;fd?d:u+a))}if(o===1){e=r[n-1];f+=t[e>>2];f+=t[e<<4&63];f+="=="}else if(o===2){e=(r[n-2]<<8)+r[n-1];f+=t[e>>10];f+=t[e>>4&63];f+=t[e<<2&63];f+="="}i.push(f);return i.join("")}},{}]},{},[])("/")}); diff --git a/web_drop_target/static/src/js/web_drop_target.js b/web_drop_target/static/src/js/web_drop_target.js new file mode 100644 index 000000000..a23d95473 --- /dev/null +++ b/web_drop_target/static/src/js/web_drop_target.js @@ -0,0 +1,341 @@ +/* global Uint8Array, base64js */ +// Copyright 2018 Therp BV +// Copyright 2021 Tecnativa - Alexandre D. Díaz +// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +odoo.define("web_drop_target", function (require) { + "use strict"; + const AbstractAction = require("web.AbstractAction"); + const FormController = require("web.FormController"); + const core = require("web.core"); + const qweb = core.qweb; + + // This is the main contribution of this addon: A mixin you can use + // To make some widget a drop target. Read on how to use this yourself + const DropTargetMixin = { + // Add the mime types you want to support here, leave empty for + // All types. For more control, override _get_drop_items in your class + _drop_allowed_types: [], + // Determine the zone where can drop files, if not defined, we use the element + _drop_zone_selector: undefined, + + /** + * @override + */ + start: function () { + const $body = $("body"); + this._dropZoneNS = _.uniqueId("o_dz_"); // For event namespace used when multiple chat window is open + $body.on( + "dragleave." + this._dropZoneNS, + this._onBodyFileDragLeave.bind(this) + ); + $body.on( + "dragover." + this._dropZoneNS, + this._onBodyFileDragover.bind(this) + ); + $body.on("drop." + this._dropZoneNS, this._onBodyFileDrop.bind(this)); + return this._super.apply(this, arguments).then((result) => { + _.defer(this._add_overlay.bind(this)); + return result; + }); + }, + + /** + * @override + */ + destroy: function () { + this._super.apply(this, arguments); + const $body = $("body"); + $body.off("dragleave." + this._dropZoneNS); + $body.off("dragover." + this._dropZoneNS); + $body.off("drop." + this._dropZoneNS); + this._remove_overlay(); + }, + /** + * @override + Necessary for creation of attachment + */ + _updateAndDisable: function () { + return this._super.apply(this, arguments).then((result) => { + this._update_overlay(); + return result; + }); + }, + /** + * @override + Necessary for change of views and Next and Previous buttons + */ + _update: function () { + return this._super.apply(this, arguments).then((result) => { + this._update_overlay(); + return result; + }); + }, + _update_overlay: function () { + this._remove_overlay(); + _.defer(this._add_overlay.bind(this)); + }, + /** + * TODO: Change the name to follow the standard in new versions + * + * @private + * @returns {Number} + */ + _get_record_id: function () { + // Implement when including this mixin. Return the record ID. + console.log("'_get_record_id': Not Implemented"); + return false; + }, + + /** + * TODO: Change the name to follow the standard in new versions + * + * @private + */ + _add_overlay: function () { + if (!this._drop_overlay || this._drop_overlay.length === 0) { + if (this._drop_zone_selector) + this.$drop_zone = this.$(this._drop_zone_selector).last(); + else this.$drop_zone = this.$el; + // Element that represents the zone where you can drop files + // TODO: This name is preserved for not breaking the compatibility with other modules, + // but should be changed in new versions to follow the standard ($name) + this._drop_overlay = $( + qweb.render("web_drop_target.drop_overlay", { + id: this._get_record_id(), + }) + ); + this.$drop_zone.append(this._drop_overlay); + + this._drop_overlay.on("drop", this._on_drop.bind(this)); + } + }, + + /** + * TODO: Change the name to follow the standard in new versions + * + * @private + */ + _remove_overlay: function () { + if (this._drop_overlay && this._drop_overlay.length) { + this._drop_overlay.off("drop"); + this._drop_overlay.remove(); + this._drop_overlay = null; + } + }, + + /** ******************** + * HANDLE EVENTS + **********************/ + + /** + * @private + * @param {MouseEvent} ev + */ + _onBodyFileDragLeave: function (ev) { + // On every dragenter chain created with parent child element + // That's why dragleave is fired every time when a child elemnt is hovered + // so here we hide dropzone based on mouse position + if ( + ev.originalEvent.clientX <= 0 || + ev.originalEvent.clientY <= 0 || + ev.originalEvent.clientX >= window.innerWidth || + ev.originalEvent.clientY >= window.innerHeight + ) { + this._drop_overlay.addClass("d-none"); + } + }, + + /** + * @private + * @param {MouseEvent} ev + */ + _onBodyFileDragover: function (ev) { + ev.preventDefault(); + const abstractAction = this.findAncestor(function (ancestor) { + return ancestor instanceof AbstractAction; + }); + const controller = abstractAction.currentDialogController; + if ( + _.isEmpty(this._get_drop_items(ev)) && + this._checkDragOver() && + (controller == undefined || controller.jsID === this.controllerID) + ) { + const drop_zone_offset = this.$drop_zone.offset(); + const overlay_css = { + top: drop_zone_offset.top, + left: drop_zone_offset.left, + width: this.$drop_zone.width(), + height: this.$drop_zone.height(), + }; + if (!this._get_record_id()) { + overlay_css.background = "#FF000020"; + } + this._drop_overlay.css(overlay_css); + this._drop_overlay.removeClass("d-none"); + } + }, + + _checkDragOver: function () { + return true; + }, + + /** + * @private + * @param {MouseEvent} ev + */ + _onBodyFileDrop: function (ev) { + ev.preventDefault(); + this._drop_overlay.addClass("d-none"); + }, + + /** + * TODO: Change the name to follow the standard in new versions + * + * @private + * @param {MouseEvent} ev + */ + _on_drop: function (ev) { + if (!this._drop_overlay || this._drop_overlay.length === 0) { + return; + } + ev.preventDefault(); + const drop_items = this._get_drop_items(ev); + if (_.isEmpty(drop_items)) { + return; + } + this._handle_drop_items(drop_items, ev); + }, + + /** + * TODO: Change the name to follow the standard in new versions + * + * @private + * @param {MouseEvent} ev + */ + _get_drop_items: function (ev) { + let drop_items = []; + if (this._get_record_id()) { + const dataTransfer = ev.originalEvent.dataTransfer; + drop_items = _.filter( + dataTransfer.files, + (item) => + _.isEmpty(this._drop_allowed_types) || + _.contains(this._drop_allowed_types, item.type) + ); + } + return drop_items; + }, + + /** + * TODO: Change the name to follow the standard in new versions + * + * @private + * @param {Array} drop_items + * @param {MouseEvent} ev + */ + // eslint-disable-next-line no-unused-vars + _handle_drop_items: function (drop_items, ev) { + // Do something here, for example call the helper function below + // e is the on_load_end handler for the FileReader above, + // so e.target.result contains an ArrayBuffer of the data + }, + + /** + * TODO: Change the name to follow the standard in new versions + * + * @private + * @param {Object} file + * @param {FileReader} reader + * @param {String} res_model + * @param {Number} res_id + * @param {Object} extra_data + */ + _create_attachment: function (file, reader, res_model, res_id, extra_data) { + // Helper to upload an attachment and update the sidebar + var self = this; + return this._rpc({ + model: "ir.attachment", + method: "create", + args: [ + _.extend( + { + name: file.name, + datas: base64js.fromByteArray( + new Uint8Array(reader.result) + ), + res_model: res_model, + res_id: res_id, + }, + extra_data + ), + ], + }).then(() => { + // Find the chatter among the children, there should be only + // one + self.trigger_up("reload", { + keepChanges: true, + onSuccess: this._update_overlay.bind(this), + }); + }); + }, + + /** + * TODO: Change the name to follow the standard in new versions + * + * @private + * @param {ErrorEvent} ev + */ + _file_reader_error_handler: function (ev) { + console.error(ev); + }, + + /** + * TODO: Change the name to follow the standard in new versions + * + * @private + * @param {Object} item + */ + _handle_file_drop_attach: function (item) { + if (!item || !(item instanceof Blob)) { + return; + } + const res_model = this.renderer.state.model; + const res_id = this.renderer.state.res_id; + const reader = new FileReader(); + reader.onloadend = this._create_attachment.bind( + this, + item, + reader, + res_model, + res_id, + undefined + ); + reader.onerror = this._file_reader_error_handler.bind(this); + reader.readAsArrayBuffer(item); + }, + }; + + // And here we apply the mixin to form views, allowing any files and + // adding them as attachment + FormController.include( + _.extend({}, DropTargetMixin, { + // Using multi-selector to ensure that is displayed in forms without "sheet" + // NOTE: Only the inner element would be selected + _drop_zone_selector: ".o_form_sheet_bg,.o_form_view", + _handle_drop_items: function (drop_items) { + _.each(drop_items, this._handle_file_drop_attach, this); + }, + _get_record_id: function () { + return this.renderer.state.res_id; + }, + _checkDragOver: function () { + return this.renderer._chatterContainerComponent; + }, + }) + ); + + return { + DropTargetMixin: DropTargetMixin, + }; +}); diff --git a/web_drop_target/static/src/scss/web_drop_target.scss b/web_drop_target/static/src/scss/web_drop_target.scss new file mode 100644 index 000000000..564f1f3e1 --- /dev/null +++ b/web_drop_target/static/src/scss/web_drop_target.scss @@ -0,0 +1,17 @@ +.o_drag_over { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(255, 255, 255, 0.6); + border: 2px dashed $o-brand-primary; + z-index: 2; + .o_drag_over_content { + position: relative; + top: 50%; + transform: translate(0%, -50%); + width: 100%; + text-align: center; + } +} diff --git a/web_drop_target/static/src/xml/widgets.xml b/web_drop_target/static/src/xml/widgets.xml new file mode 100644 index 000000000..3abb76851 --- /dev/null +++ b/web_drop_target/static/src/xml/widgets.xml @@ -0,0 +1,20 @@ + +