From 0cc196376bb0f0c78e1e8c2fa4153344cccc7d39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20=C3=89vrard?= Date: Fri, 16 Aug 2013 13:35:39 +0200 Subject: [PATCH] Add binary field support review1010002 --- src/common.js | 10 +++ src/model.js | 41 ++++++++++- src/rpc.js | 21 +++++- src/view.js | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 263 insertions(+), 3 deletions(-) diff --git a/src/common.js b/src/common.js index 19ce29e5cb..1227fc5fea 100644 --- a/src/common.js +++ b/src/common.js @@ -72,6 +72,16 @@ return text; }; + Sao.common.humanize = function(size) { + var sizes = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB']; + for (var i =0, len = sizes.length; i < len; i++) { + if (size < 1000) { + return size.toPrecision(4) + ' ' + sizes[i]; + } + size /= 1000; + } + }; + Sao.common.EvalEnvironment = function(parent_, eval_type) { if (eval_type === undefined) eval_type = 'eval'; diff --git a/src/model.js b/src/model.js index 83e5bdb3e1..06f3b4fd37 100644 --- a/src/model.js +++ b/src/model.js @@ -406,7 +406,7 @@ n++; } } - var context = this.get_context(); + var context = jQuery.extend({}, this.get_context()); var fnames = []; if (loading == 'eager') { for (fname in this.model.fields) { @@ -436,7 +436,15 @@ fnames_to_fetch.push('rec_name'); } fnames_to_fetch.push('_timestamp'); - // TODO size of binary + for (fname in this.model.fields) { + if (!this.model.fields.hasOwnProperty(fname)) { + continue; + } + if ((this.model.fields[fname].description.type == 'binary') && + ~fnames_to_fetch.indexOf(fname, fnames_to_fetch)) { + context[this.model.name + '.' + fname] = 'size'; + } + } prm = this.model.execute('read', [Object.keys(id2record), fnames_to_fetch], context); var succeed = function(values) { @@ -842,6 +850,8 @@ return Sao.field.One2Many; case 'many2many': return Sao.field.Many2Many; + case 'binary': + return Sao.field.Binary; default: return Sao.field.Char; } @@ -1609,4 +1619,31 @@ return this.get_eval(record); } }); + + Sao.field.Binary = Sao.class_(Sao.field.Field, { + _default: null, + get_size: function(record) { + var data = record._values[this.name] || 0; + if (data instanceof Uint8Array) { + return data.length; + } + return data; + }, + get_data: function(record) { + var prm = jQuery.when(); + var data = record._values[this.name] || 0; + if (!(data instanceof Uint8Array)) { + if (record.id < 0) { + return prm; + } + var context = record.get_context(); + prm = record.model.execute('read', [[record.id], [this.name]], + context); + prm.done(function(data) { + return data[0][this.name]; + }.bind(this)); + return prm; + } + } + }); }()); diff --git a/src/rpc.js b/src/rpc.js index 75247eb2f3..122858ea01 100644 --- a/src/rpc.js +++ b/src/rpc.js @@ -81,7 +81,18 @@ case 'time': throw new Error('Time support not implemented'); case 'buffer': - throw new Error('Buffer support not implemented'); + // javascript's atob does not understand linefeed + // characters + var byte_string = atob(value.base64.replace(/\s/g, '')); + // javascript decodes base64 string as a "DOMString", we + // need to convert it to an array of bytes + var array_buffer = new ArrayBuffer(byte_string.length); + var uint_array = new Uint8Array(array_buffer); + for (var j=0; j < byte_string.length; j++) { + uint_array[j] = byte_string.charCodeAt(j); + } + value = uint_array; + break; case 'Decimal': value = new Sao.Decimal(value.decimal); break; @@ -137,6 +148,14 @@ if (parent) { parent[index] = value; } + } else if (value instanceof Uint8Array) { + value = { + '__class__': 'buffer', + 'base64': btoa(String.fromCharCode.apply(null, value)) + }; + if (parent) { + parent[index] = value; + } } else { for (var p in value) { Sao.rpc.prepareObject(value[p], p, value); diff --git a/src/view.js b/src/view.js index 41b96a1bf2..04174ae404 100644 --- a/src/view.js +++ b/src/view.js @@ -960,6 +960,8 @@ return Sao.View.Form.One2Many; case 'many2many': return Sao.View.Form.Many2Many; + case 'binary': + return Sao.View.Form.Binary; } }; @@ -1974,4 +1976,196 @@ } } }); + + Sao.View.Form.Binary = Sao.class_(Sao.View.Form.Widget, { + class_: 'form-binary', + blob_url: '', + init: function(field_name, model, attributes) { + Sao.View.Form.Binary._super.init.call(this, field_name, model, + attributes); + this.filename = attributes.filename || null; + + this.el = jQuery('
', { + 'class': this.class_ + }); + + if (this.filename && attributes.filename_visible) { + this.text = jQuery('', { + type: 'input' + }); + this.text.change(this.focus_out.bind(this)); + this.text.on('keyup', this.key_press.bind(this)); + this.el.append(this.text); + } + this.size = jQuery('', { + type: 'input' + }); + this.el.append(this.size); + + this.but_new = jQuery('