Browse Source

Merge pull request #907 from hbrunn/10.0-web_drop_target

[ADD] web_drop_target
pull/970/merge
Pedro M. Baeza 6 years ago
committed by GitHub
parent
commit
a98a46ee86
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 76
      web_drop_target/README.rst
  2. 3
      web_drop_target/__init__.py
  3. 18
      web_drop_target/__manifest__.py
  4. BIN
      web_drop_target/static/description/icon.png
  5. 1
      web_drop_target/static/lib/base64js.min.js
  6. 0
      web_drop_target/static/src/css/web_drop_target.css
  7. 132
      web_drop_target/static/src/js/web_drop_target.js
  8. 12
      web_drop_target/views/templates.xml
  9. 4
      web_widget_timepicker/README.rst
  10. 26
      web_widget_x2many_2d_matrix/README.rst

76
web_drop_target/README.rst

@ -0,0 +1,76 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
===================
Drop target support
===================
This module extends the functionality of the web client to support dropping local files into the web client.
By default, an attachment will be created when dropping a file on a form.
Further, 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.
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://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/162/10.0
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
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/web/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.
Credits
=======
Images
------
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.
Libraries
---------
* `base64js <https://raw.githubusercontent.com/beatgammit/base64-js>`_.
Contributors
------------
* Holger Brunn <hbrunn@therp.nl>
Do not contact contributors directly about help with questions or problems concerning this addon, but use the `community mailing list <mailto:community@mail.odoo.com>`_ or the `appropriate specialized mailinglist <https://odoo-community.org/groups>`_ for help, and the bug tracker linked in `Bug Tracker`_ above for technical issues.
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
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.
To contribute to this module, please visit https://odoo-community.org.

3
web_drop_target/__init__.py

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Therp BV <https://therp.nl>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

18
web_drop_target/__manifest__.py

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Therp BV <https://therp.nl>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
"name": "Drop target support",
"version": "10.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": [
'views/templates.xml',
],
}

BIN
web_drop_target/static/description/icon.png

After

Width: 128  |  Height: 128  |  Size: 9.2 KiB

1
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;i<t.length;i++)o(t[i]);return o}return r}()({"/":[function(r,e,n){"use strict";n.byteLength=c;n.toByteArray=v;n.fromByteArray=s;var t=[];var o=[];var f=typeof Uint8Array!=="undefined"?Uint8Array:Array;var i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(var a=0,u=i.length;a<u;++a){t[a]=i[a];o[i.charCodeAt(a)]=a}o["-".charCodeAt(0)]=62;o["_".charCodeAt(0)]=63;function d(r){var e=r.length;if(e%4>0){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<n;e+=4){t=o[r.charCodeAt(e)]<<18|o[r.charCodeAt(e+1)]<<12|o[r.charCodeAt(e+2)]<<6|o[r.charCodeAt(e+3)];a[c++]=t>>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;f<n;f+=3){t=(r[f]<<16&16711680)+(r[f+1]<<8&65280)+(r[f+2]&255);o.push(l(t))}return o.join("")}function s(r){var e;var n=r.length;var o=n%3;var f="";var i=[];var a=16383;for(var u=0,d=n-o;u<d;u+=a){i.push(h(r,u,u+a>d?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("")}},{}]},{},[])("/")});

0
web_drop_target/static/src/css/web_drop_target.css

132
web_drop_target/static/src/js/web_drop_target.js

@ -0,0 +1,132 @@
//-*- coding: utf-8 -*-
//Copyright 2018 Therp BV <https://therp.nl>
//License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
/*global Uint8Array base64js*/
odoo.define('web_drop_target', function(require) {
var Model = require('web.Model'),
FormView = require('web.FormView');
// 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
var DropTargetMixin = {
// add the mime types you want to support here, leave empty for
// all types. For more control, override _get_drop_item in your class
_drop_allowed_types: [],
// a class being applied when the user drags something we can handle
_drag_over_class: 'o_drag_over',
start: function() {
var result = this._super.apply(this, arguments);
this.$el.on('drop.widget_events', this.proxy('_on_drop'));
this.$el.on('dragenter.widget_events', this.proxy('_on_dragenter'));
this.$el.on('dragover.widget_events', this.proxy('_on_dragenter'));
this.$el.on('dragleave.widget_events', this.proxy('_on_dragleave'));
return result;
},
_on_drop: function(e) {
var drop_item = this._get_drop_item(e);
if(!drop_item) {
return;
}
jQuery(e.delegateTarget).removeClass(this._drag_over_class);
var reader = new FileReader();
reader.onloadend = this.proxy(
_.partial(this._handle_file_drop, drop_item.getAsFile())
);
reader.readAsArrayBuffer(drop_item.getAsFile());
e.preventDefault();
},
_on_dragenter: function(e) {
if(this._get_drop_item(e)) {
e.preventDefault();
jQuery(e.delegateTarget).addClass(this._drag_over_class);
return false;
}
},
_on_dragleave: function(e) {
jQuery(e.delegateTarget).removeClass(this._drag_over_class);
},
_get_drop_item: function(e) {
var self = this,
dataTransfer = e.originalEvent.dataTransfer,
drop_item = null;
_.each(dataTransfer.items, function(item) {
if(
_.contains(self._drop_allowed_types, item.type) ||
_.isEmpty(self._drop_allowed_types)
) {
drop_item = item;
}
});
return drop_item;
},
// eslint-disable-next-line no-unused-vars
_handle_file_drop: function(drop_file, e) {
// 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
},
_handle_file_drop_attach: function(
drop_file, e, res_model, res_id, extra_data
) {
// helper to upload an attachment and update the sidebar
var self = this;
return new Model('ir.attachment').call(
'create',
[
_.extend({
name: drop_file.name,
datas: base64js.fromByteArray(
new Uint8Array(e.target.result)
),
datas_fname: drop_file.name,
res_model: res_model,
res_id: res_id,
}, extra_data || {})
]
)
.then(function() {
// try to find a sidebar and update it if we found one
var p = self;
while(p && !p.sidebar) {
p = p.getParent ? p.getParent() : null;
}
if(p) {
var sidebar = p.sidebar;
sidebar.do_attachement_update(
sidebar.dataset, sidebar.model_id
);
}
});
}
};
// and here we apply the mixin to form views, allowing any files and
// adding them as attachment
FormView.include(_.extend(DropTargetMixin, {
_get_drop_file: function() {
// disable drag&drop when we're on an unsaved record
if(!this.datarecord.id) {
return null;
}
return this._super.apply(this, arguments);
},
_handle_file_drop: function(drop_file, e) {
return this._handle_file_drop_attach(
drop_file, e, this.dataset.model, this.datarecord.id
);
}
}));
return {
'DropTargetMixin': DropTargetMixin,
};
});

12
web_drop_target/views/templates.xml

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<template id="assets_backend" name="web_drop_target assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/web_drop_target/static/lib/base64js.min.js"></script>
<script type="text/javascript" src="/web_drop_target/static/src/js/web_drop_target.js"></script>
<link rel="stylesheet" href="/web_drop_target/static/src/css/web_drop_target.css"/>
</xpath>
</template>
</data>
</openerp>

4
web_widget_timepicker/README.rst

@ -54,7 +54,7 @@ See the available options at `jquery-timepicker <https://github.com//jonthornton
Credits Credits
======= =======
* The module uses the `jquery-timepicker <https://github.com//jonthornton//jquery-timepicker#timepicker-plugin-for-jquery>`_. plugin by Jon Thornton. This software is made available under the open source MIT License. © 2014 Jon Thornton and contributors
* The module uses the `jquery-timepicker plugin <https://github.com//jonthornton//jquery-timepicker#timepicker-plugin-for-jquery>`_ by Jon Thornton. This software is made available under the open source MIT License. © 2014 Jon Thornton and contributors
* Odoo Community Association (OCA) * Odoo Community Association (OCA)
@ -79,4 +79,4 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and mission is to support the collaborative development of Odoo features and
promote its widespread use. promote its widespread use.
To contribute to this module, please visit https://odoo-community.org.
To contribute to this module, please visit https://odoo-community.org.

26
web_widget_x2many_2d_matrix/README.rst

@ -9,12 +9,14 @@
This module allows to show an x2many field with 3-tuples This module allows to show an x2many field with 3-tuples
($x_value, $y_value, $value) in a table ($x_value, $y_value, $value) in a table
========= =========== ===========
\ $x_value1 $x_value2
========= =========== ===========
$y_value1 $value(1/1) $value(2/1)
$y_value2 $value(1/2) $value(2/2)
========= =========== ===========
+-----------+-------------+-------------+
| | $x_value1 | $x_value2 |
+-----------+-------------+-------------+
| $y_value1 | $value(1/1) | $value(2/1) |
+-----------+-------------+-------------+
| $y_value2 | $value(1/2) | $value(2/2) |
+-----------+-------------+-------------+
where `value(n/n)` is editable. where `value(n/n)` is editable.
@ -145,12 +147,12 @@ Known issues / Roadmap
* If you pass values with an onchange, you need to overwrite the model's method * If you pass values with an onchange, you need to overwrite the model's method
`onchange` for making the widget work:: `onchange` for making the widget work::
@api.multi
def onchange(self, values, field_name, field_onchange):
if "one2many_field" in field_onchange:
for sub in [<field_list>]:
field_onchange.setdefault("one2many_field." + sub, u"")
return super(model, self).onchange(values, field_name, field_onchange)
@api.multi
def onchange(self, values, field_name, field_onchange):
if "one2many_field" in field_onchange:
for sub in [<field_list>]:
field_onchange.setdefault("one2many_field." + sub, u"")
return super(model, self).onchange(values, field_name, field_onchange)
Bug Tracker Bug Tracker
=========== ===========

Loading…
Cancel
Save