summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorjpr-odoo <jpr@openerp.com>2017-11-01 15:15:04 +0530
committerYannick Tivisse <yti@odoo.com>2018-02-09 06:59:56 +0100
commitb7aa439826df6b3e442b3f60bb593ff28efc8679 (patch)
tree953d340f839717c5de254ca90cb3d3cde9b44d0d /addons
parentdfdc06fe4332b3de97a3b1f8f554ce6adc3b948d (diff)
[ADD] web: Add a new widget to attach documents on a record
Purpose ======= Add the possibility to easily attach a document on a record. That could be used for to attach receipts on expense for example. Specification ============= Add a new widget (AttachDocument) to allow attach document from mobile/web directly on record form After attaching document it will call action given on widget, that action will be a method name on given model
Diffstat (limited to 'addons')
-rw-r--r--addons/web/static/src/js/views/basic/basic_renderer.js2
-rw-r--r--addons/web/static/src/js/views/form/form_renderer.js3
-rw-r--r--addons/web/static/src/js/widgets/attach_document.js135
-rw-r--r--addons/web/static/src/xml/base.xml16
-rw-r--r--addons/web/static/tests/views/form_tests.js22
-rw-r--r--addons/web/views/webclient_templates.xml1
6 files changed, 178 insertions, 1 deletions
diff --git a/addons/web/static/src/js/views/basic/basic_renderer.js b/addons/web/static/src/js/views/basic/basic_renderer.js
index d9c0f1a570b..f0d41f31f49 100644
--- a/addons/web/static/src/js/views/basic/basic_renderer.js
+++ b/addons/web/static/src/js/views/basic/basic_renderer.js
@@ -594,7 +594,7 @@ var BasicRenderer = AbstractRenderer.extend({
*/
_renderWidget: function (record, node) {
var Widget = widgetRegistry.get(node.attrs.name);
- var widget = new Widget(this, record);
+ var widget = new Widget(this, record, node);
// Prepare widget rendering and save the related deferred
var def = widget._widgetRenderAndInsert(function () {});
diff --git a/addons/web/static/src/js/views/form/form_renderer.js b/addons/web/static/src/js/views/form/form_renderer.js
index b289663fb19..b28d25c5b90 100644
--- a/addons/web/static/src/js/views/form/form_renderer.js
+++ b/addons/web/static/src/js/views/form/form_renderer.js
@@ -370,6 +370,9 @@ var FormRenderer = BasicRenderer.extend({
if (child.tag === 'button') {
$buttons.append(self._renderHeaderButton(child));
}
+ if (child.tag === 'widget') {
+ $buttons.append(self._renderTagWidget(child));
+ }
});
return $buttons;
},
diff --git a/addons/web/static/src/js/widgets/attach_document.js b/addons/web/static/src/js/widgets/attach_document.js
new file mode 100644
index 00000000000..041b021d60b
--- /dev/null
+++ b/addons/web/static/src/js/widgets/attach_document.js
@@ -0,0 +1,135 @@
+odoo.define('web.AttachDocument', function (require) {
+"use static";
+
+var core = require('web.core');
+var framework = require('web.framework');
+var widgetRegistry = require('web.widget_registry');
+var Widget = require('web.Widget');
+
+var _t = core._t;
+
+var AttachDocument = Widget.extend({
+ template: 'AttachDocument',
+ events: {
+ 'click span.o_attach_document': '_onClickAttachDocument',
+ 'change input.o_input_file': '_onFileChanged',
+ },
+ /**
+ * @constructor
+ * @param {Widget} parent
+ * @param {Object} record
+ * @param {Object} nodeInfo
+ */
+ init: function (parent, record, nodeInfo) {
+ this._super.apply(this, arguments);
+ this.res_id = record.res_id;
+ this.res_model = record.model;
+ this.state = record;
+ this.node = nodeInfo;
+ this.fileuploadID = _.uniqueId('o_fileupload');
+ },
+ /**
+ * @override
+ */
+ start: function () {
+ $(window).on(this.fileuploadID, this._onFileLoaded.bind(this));
+ return this._super.apply(this, arguments);
+ },
+ /**
+ * @override
+ */
+ destroy: function () {
+ $(window).off(this.fileuploadID);
+ this._super.apply(this, arguments);
+ },
+
+ //--------------------------------------------------------------------------
+ // private
+ //--------------------------------------------------------------------------
+
+ /**
+ * Helper function to display a warning that some fields have an invalid
+ * value. This is used when a save operation cannot be completed.
+ *
+ * @private
+ * @param {string[]} invalidFields - list of field names
+ */
+ _notifyInvalidFields: function (invalidFields) {
+ var fields = this.state.fields;
+ var warnings = invalidFields.map(function (fieldName) {
+ var fieldStr = fields[fieldName].string;
+ return _.str.sprintf('<li>%s</li>', _.escape(fieldStr));
+ });
+ warnings.unshift('<ul>');
+ warnings.push('</ul>');
+ this.do_warn(_t("The following fields are invalid:"), warnings.join(''));
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Opens File Explorer dialog if all fields are valid and record is saved
+ *
+ * @private
+ * @param {Event} ev
+ */
+ _onClickAttachDocument: function (ev) {
+ var fieldNames = this.getParent().canBeSaved(this.state.id);
+ if (fieldNames.length) {
+ return this._notifyInvalidFields(fieldNames);
+ }
+ // We want to save record on widget click and then open File Selection Explorer
+ // but due to this security restriction give warning to save record first.
+ // https://stackoverflow.com/questions/29728705/trigger-click-on-input-file-on-asynchronous-ajax-done/29873845#29873845
+ if (!this.res_id) {
+ return this.do_warn(_t('Warning : You have to save first before attaching a file.'));
+ }
+ this.$('input.o_input_file').trigger('click');
+ },
+ /**
+ * Submits file
+ *
+ * @private
+ * @param {Event} ev
+ */
+ _onFileChanged: function (ev) {
+ ev.stopPropagation();
+ this.$('form.o_form_binary_form').trigger('submit');
+ framework.blockUI();
+ },
+ /**
+ * Call action given as node attribute after file submission
+ *
+ * @private
+ */
+ _onFileLoaded: function () {
+ var self = this,
+ def = $.Deferred();
+
+ if (self.node.attrs.action) {
+ // the first argument isn't a file but the jQuery.Event
+ var files = Array.prototype.slice.call(arguments, 1);
+ self._rpc({
+ model: self.res_model,
+ method: self.node.attrs.action,
+ args: [self.res_id],
+ kwargs: {
+ 'attachment_ids': _.map(files, function (file) {return file.id;}),
+ }
+ }).then( function () {
+ def.resolve();
+ });
+ } else {
+ def.resolve();
+ }
+ return $.when(def).then(function () {
+ self.trigger_up('reload');
+ framework.unblockUI();
+ });
+ },
+
+});
+widgetRegistry.add('attach_document', AttachDocument);
+});
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index 196346d4d9c..ce432fea823 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -1351,4 +1351,20 @@
</div>
</t>
+<t t-name="AttachDocument">
+ <button class="btn btn-sm btn-default o_attachment_button">
+ <span class="o_attach_document"><t t-esc="widget.node.attrs.string"/></span>
+ <span class="hide">
+ <t t-call="HiddenInputFile">
+ <t t-set="fileupload_id" t-value="widget.fileuploadID"/>
+ <t t-set="fileupload_action" t-translation="off">/web/binary/upload_attachment</t>
+ <t t-set="multi_upload" t-value="true"/>
+ <input type="hidden" name="model" t-att-value="widget.res_model"/>
+ <input type="hidden" name="id" t-att-value="widget.res_id"/>
+ <input type="hidden" name="session_id" t-att-value="widget.getSession().session_id"/>
+ </t>
+ </span>
+ </button>
+</t>
+
</templates>
diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js
index 6d8909ff2c3..37420e0f076 100644
--- a/addons/web/static/tests/views/form_tests.js
+++ b/addons/web/static/tests/views/form_tests.js
@@ -6227,6 +6227,28 @@ QUnit.module('Views', {
delete widgetRegistry.map.test;
});
+ QUnit.test('support header button as widgets on form statusbar', function (assert) {
+ assert.expect(2);
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form string="Partners">' +
+ '<header>' +
+ '<widget name="attach_document" string="Attach document"/>' +
+ '</header>' +
+ '</form>',
+ });
+
+ assert.strictEqual(form.$('button.o_attachment_button').length, 1,
+ "should have 1 attach_document widget in the statusbar");
+ assert.strictEqual(form.$('span.o_attach_document').text().trim(), 'Attach document',
+ "widget should have been instantiated");
+
+ form.destroy();
+ });
+
QUnit.test('bounce edit button in readonly mode', function (assert) {
assert.expect(3);
diff --git a/addons/web/views/webclient_templates.xml b/addons/web/views/webclient_templates.xml
index 2742871c790..35ded8170cf 100644
--- a/addons/web/views/webclient_templates.xml
+++ b/addons/web/views/webclient_templates.xml
@@ -240,6 +240,7 @@
<script type="text/javascript" src="/web/static/src/js/views/calendar/calendar_quick_create.js"></script>
<script type="text/javascript" src="/web/static/src/js/views/calendar/calendar_renderer.js"></script>
<script type="text/javascript" src="/web/static/src/js/views/calendar/calendar_view.js"></script>
+ <script type="text/javascript" src="/web/static/src/js/widgets/attach_document.js"></script>
<script type="text/javascript" src="/web/static/src/js/report/utils.js"/>
<script type="text/javascript" src="/web/static/src/js/report/client_action.js"/>