/* This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. */
(function() {
'use strict';
Sao.View = Sao.class_(Object, {
init: function(screen, xml) {
this.screen = screen;
this.view_type = null;
this.el = null;
this.view_id = null;
this.fields = {};
var attributes = xml.children()[0].attributes;
this.attributes = {};
for (var i = 0, len = attributes.length; i < len; i++) {
var attribute = attributes[i];
this.attributes[attribute.name] = attribute.value;
}
screen.set_on_write(this.attributes.on_write);
},
set_value: function() {
},
get_fields: function() {
return Object.keys(this.fields);
},
get_buttons: function() {
return [];
}
});
Sao.View.idpath2path = function(tree, idpath) {
var path = [];
var child_path;
if (!idpath) {
return [];
}
for (var i = 0, len = tree.rows.length; i < len; i++) {
if (tree.rows[i].record.id == idpath[0]) {
path.push(i);
child_path = Sao.View.idpath2path(tree.rows[i],
idpath.slice(1, idpath.length));
path = path.concat(child_path);
break;
}
}
return path;
};
Sao.View.parse = function(screen, xml, children_field) {
switch (xml.children().prop('tagName')) {
case 'tree':
return new Sao.View.Tree(screen, xml, children_field);
case 'form':
return new Sao.View.Form(screen, xml);
case 'graph':
return new Sao.View.Graph(screen, xml);
case 'calendar':
return new Sao.View.Calendar(screen, xml);
}
};
Sao.View.tree_column_get = function(type) {
switch (type) {
case 'char':
case 'text':
case 'binary':
return Sao.View.Tree.CharColumn;
case 'many2one':
return Sao.View.Tree.Many2OneColumn;
case 'one2one':
return Sao.View.Tree.One2OneColumn;
case 'date':
return Sao.View.Tree.DateColumn;
case 'time':
return Sao.View.Tree.TimeColumn;
case 'timedelta':
return Sao.View.Tree.TimeDeltaColumn;
case 'one2many':
return Sao.View.Tree.One2ManyColumn;
case 'many2many':
return Sao.View.Tree.Many2ManyColumn;
case 'selection':
return Sao.View.Tree.SelectionColumn;
case 'reference':
return Sao.View.Tree.ReferenceColumn;
case 'float':
case 'numeric':
return Sao.View.Tree.FloatColumn;
case 'integer':
case 'biginteger':
return Sao.View.Tree.IntegerColumn;
case 'boolean':
return Sao.View.Tree.BooleanColumn;
case 'image':
return Sao.View.Tree.ImageColumn;
case 'url':
case 'email':
case 'callto':
case 'sip':
return Sao.View.Tree.URLColumn;
case 'progressbar':
return Sao.View.Tree.ProgressBar;
}
};
Sao.View.Tree = Sao.class_(Sao.View, {
init: function(screen, xml, children_field) {
Sao.View.Tree._super.init.call(this, screen, xml);
this.view_type = 'tree';
this.selection_mode = (screen.attributes.selection_mode ||
Sao.common.SELECTION_SINGLE);
this.el = jQuery('
', {
'class': 'col-md-12'
}).appendTo(jQuery('
', {
'class': 'row'
}).appendTo(jQuery('
', {
'class': 'container-fluid'
}).appendTo(body))));
this.wid_text = jQuery('
', {
'type': 'text',
'class': 'form-control input-sm'
}).appendTo(group);
// TODO completion
this.but_add = jQuery('
', {
'class': 'btn btn-default btn-sm',
'type': 'button',
'aria-label': Sao.i18n.gettext('Add')
}).append(jQuery('
', {
'class': 'glyphicon glyphicon-plus'
})).appendTo(jQuery('
', {
'class': 'input-group-btn'
}).appendTo(group));
this.but_add.click(this.add.bind(this));
this._readonly = false;
this._record_id = null;
},
add: function() {
var context = this.field().get_context(this.record());
var value = this.wid_text.val();
var domain = this.field().get_domain(this.record());
var callback = function(result) {
if (!jQuery.isEmptyObject(result)) {
var ids = result.map(function(e) {
return e[0];
});
this.add_new_keys(ids);
}
this.wid_text.val('');
}.bind(this);
var parser = new Sao.common.DomainParser();
var win = new Sao.Window.Search(this.schema_model.name,
callback, {
sel_multi: true,
context: context,
domain: domain,
new_: false,
search_filter: parser.quote(value)
});
},
add_new_keys: function(ids) {
var context = this.field().get_context(this.record());
this.schema_model.execute('get_keys', [ids], context)
.then(function(new_fields) {
var focus = false;
new_fields.forEach(function(new_field) {
if (this.fields[new_field.name]) {
return;
}
this.keys[new_field.name] = new_field;
this.add_line(new_field.name);
if (!focus) {
this.fields[new_field.name].input.focus();
focus = true;
}
}.bind(this));
}.bind(this));
},
remove: function(key, modified) {
if (modified === undefined) {
modified = true;
}
delete this.fields[key];
this.rows[key].remove();
delete this.rows[key];
if (modified) {
this.set_value(this.record(), this.field());
}
},
set_value: function(record, field) {
field.set_client(record, this.get_value());
},
get_value: function() {
var value = {};
for (var key in this.fields) {
var widget = this.fields[key];
value[key] = widget.get_value();
}
return value;
},
set_readonly: function(readonly) {
this._readonly = readonly;
this._set_button_sensitive();
for (var key in this.fields) {
var widget = this.fields[key];
widget.set_readonly(readonly);
}
this.wid_text.prop('disabled', readonly);
},
_set_button_sensitive: function() {
var create = this.attributes.create;
if (create === undefined) {
create = true;
}
var delete_ = this.attributes['delete'];
if (delete_ === undefined) {
delete_ = true;
}
this.but_add.prop('disabled', this._readonly || !create);
for (var key in this.fields) {
var button = this.fields[key].button;
button.prop('disabled', this._readonly || !delete_);
}
},
add_line: function(key) {
var field, row;
this.fields[key] = field = new (this.get_entries(
this.keys[key].type_))(key, this);
this.rows[key] = row = jQuery('
', {
'class': 'row'
});
// TODO RTL
var text = this.keys[key].string + Sao.i18n.gettext(':');
var label = jQuery('
', {
'text': text
}).appendTo(jQuery('
', {
'class': 'dict-label col-md-4'
}).appendTo(row));
field.el.addClass('col-md-8').appendTo(row);
label.uniqueId();
field.labelled.uniqueId();
field.labelled.attr('aria-labelledby', label.attr('id'));
label.attr('for', field.labelled.attr('id'));
field.button.click(function() {
this.remove(key, true);
}.bind(this));
row.appendTo(this.container);
},
add_keys: function(keys) {
var context = this.field().get_context(this.record());
var domain = this.field().get_domain(this.record());
var batchlen = Math.min(10, Sao.config.limit);
keys = jQuery.extend([], keys);
var get_keys = function(key_ids) {
return this.schema_model.execute('get_keys',
[key_ids], context).then(update_keys);
}.bind(this);
var update_keys = function(values) {
for (var i = 0, len = values.length; i < len; i++) {
var k = values[i];
this.keys[k.name] = k;
}
}.bind(this);
var prms = [];
while (keys.length > 0) {
var sub_keys = keys.splice(0, batchlen);
prms.push(this.schema_model.execute('search',
[[['name', 'in', sub_keys], domain],
0, Sao.config.limit, null], context)
.then(get_keys));
}
return jQuery.when.apply(jQuery, prms);
},
display: function(record, field) {
Sao.View.Form.Dict._super.display.call(this, record, field);
if (!field) {
return;
}
var record_id = record ? record.id : null;
var key;
if (record_id != this._record_id) {
for (key in this.fields) {
this.remove(key, false);
}
this._record_id = record_id;
}
var value = field.get_client(record);
var new_key_names = Object.keys(value).filter(function(e) {
return !this.keys[e];
}.bind(this));
var prm;
if (!jQuery.isEmptyObject(new_key_names)) {
prm = this.add_keys(new_key_names);
} else {
prm = jQuery.when();
}
prm.then(function() {
var i, len, key;
var keys = Object.keys(value).sort();
for (i = 0, len = keys.length; i < len; i++) {
key = keys[i];
var val = value[key];
if (!this.keys[key]) {
continue;
}
if (!this.fields[key]) {
this.add_line(key);
}
var widget = this.fields[key];
widget.set_value(val);
widget.set_readonly(this._readonly);
}
var removed_key_names = Object.keys(this.fields).filter(
function(e) {
return !value[e];
});
for (i = 0, len = removed_key_names.length; i < len; i++) {
key = removed_key_names[i];
this.remove(key, false);
}
}.bind(this));
this._set_button_sensitive();
},
get_entries: function(type) {
switch (type) {
case 'char':
return Sao.View.Form.Dict.Entry;
case 'boolean':
return Sao.View.Form.Dict.Boolean;
case 'selection':
return Sao.View.Form.Dict.Selection;
case 'integer':
return Sao.View.Form.Dict.Integer;
case 'float':
return Sao.View.Form.Dict.Float;
case 'numeric':
return Sao.View.Form.Dict.Numeric;
case 'date':
return Sao.View.Form.Dict.Date;
case 'datetime':
return Sao.View.Form.Dict.DateTime;
}
}
});
Sao.View.Form.Dict.Entry = Sao.class_(Object, {
class_: 'dict-char',
init: function(name, parent_widget) {
this.name = name;
this.definition = parent_widget.keys[name];
this.parent_widget = parent_widget;
this.create_widget();
},
create_widget: function() {
this.el = jQuery('
', {
'class': this.class_
});
var group = jQuery('
', {
'class': 'input-group input-group-sm'
}).appendTo(this.el);
this.input = this.labelled = jQuery('
', {
'type': 'text',
'class': 'form-control input-sm'
}).appendTo(group);
this.button = jQuery('
', {
'class': 'btn btn-default',
'type': 'button',
'arial-label': Sao.i18n.gettext('Remove')
}).append(jQuery('
', {
'class': 'glyphicon glyphicon-minus'
})).appendTo(jQuery('
', {
'class': 'input-group-btn'
}).appendTo(group));
this.el.change(
this.parent_widget.focus_out.bind(this.parent_widget));
},
get_value: function() {
return this.input.val();
},
set_value: function(value) {
this.input.val(value || '');
},
set_readonly: function(readonly) {
this.input.prop('readonly', readonly);
}
});
Sao.View.Form.Dict.Boolean = Sao.class_(Sao.View.Form.Dict.Entry, {
class_: 'dict-boolean',
create_widget: function() {
Sao.View.Form.Dict.Boolean._super.create_widget.call(this);
this.input.attr('type', 'checkbox');
this.input.change(
this.parent_widget.focus_out.bind(this.parent_widget));
},
get_value: function() {
return this.input.prop('checked');
},
set_value: function(value) {
this.input.prop('checked', value);
}
});
Sao.View.Form.Dict.Selection = Sao.class_(Sao.View.Form.Dict.Entry, {
class_: 'dict-selection',
create_widget: function() {
Sao.View.Form.Dict.Selection._super.create_widget.call(this);
var select = jQuery('
', {
'class': 'form-control input-sm'
});
select.change(
this.parent_widget.focus_out.bind(this.parent_widget));
this.input.replaceWith(select);
this.input = this.labelled = select;
var selection = jQuery.extend([], this.definition.selection);
selection.splice(0, 0, [null, '']);
selection.forEach(function(e) {
select.append(jQuery('
', {
'value': JSON.stringify(e[0]),
'text': e[1],
}));
});
},
get_value: function() {
return JSON.parse(this.input.val());
},
set_value: function(value) {
this.input.val(JSON.stringify(value));
}
});
Sao.View.Form.Dict.Integer = Sao.class_(Sao.View.Form.Dict.Entry, {
class_: 'dict-integer',
get_value: function() {
var value = parseInt(this.input.val(), 10);
if (isNaN(value)) {
return null;
}
return value;
}
});
Sao.View.Form.Dict.Float = Sao.class_(Sao.View.Form.Dict.Integer, {
class_: 'dict-float',
get_value: function() {
var value = Number(this.input.val());
if (isNaN(value)) {
return null;
}
return value;
}
});
Sao.View.Form.Dict.Numeric = Sao.class_(Sao.View.Form.Dict.Float, {
class_: 'dict-numeric',
get_value: function() {
var value = new Sao.Decimal(this.input.val());
if (isNaN(value.valueOf())) {
return null;
}
return value;
}
});
Sao.View.Form.Dict.Date = Sao.class_(Sao.View.Form.Dict.Entry, {
class_: 'dict-date',
format: '%x',
create_widget: function() {
Sao.View.Form.Dict.Date._super.create_widget.call(this);
var group = this.button.parent();
jQuery('
', {
'class': 'datepickerbutton btn btn-default',
'type': 'button'
}).append(jQuery('
', {
'class': 'glyphicon glyphicon-calendar'
})).prependTo(group);
this.input.datetimepicker({
'format': Sao.common.moment_format(this.format)
});
this.input.on('dp.change',
this.parent_widget.focus_out.bind(this.parent_widget));
},
get_value: function() {
var value = this.input.data('DateTimePicker').date();
if (value) {
value.isDate = true;
}
return value;
},
set_value: function(value) {
this.date.data('DateTimePicker').date(value);
}
});
Sao.View.Form.Dict.DateTime = Sao.class_(Sao.View.Form.Dict.Date, {
class_: 'dict-datetime',
format: '%x %X',
get_value: function() {
var value = this.input.data('DateTimePicker').date();
if (value) {
value.isDateTime = true;
}
return value;
}
});
Sao.View.editabletree_widget_get = function(type) {
switch (type) {
case 'char':
case 'text':
case 'url':
case 'email':
case 'callto':
case 'sip':
return Sao.View.EditableTree.Char;
case 'date':
return Sao.View.EditableTree.Date;
case 'time':
return Sao.View.EditableTree.Time;
case 'timedelta':
return Sao.View.EditableTree.TimeDelta;
case 'integer':
case 'biginteger':
return Sao.View.EditableTree.Integer;
case 'float':
case 'numeric':
return Sao.View.EditableTree.Float;
case 'selection':
return Sao.View.EditableTree.Selection;
case 'boolean':
return Sao.View.EditableTree.Boolean;
case 'many2one':
return Sao.View.EditableTree.Many2One;
case 'one2one':
return Sao.View.EditableTree.One2One;
case 'one2many':
case 'many2many':
return Sao.View.EditableTree.One2Many;
case 'binary':
return Sao.View.EditableTree.Binary;
}
};
Sao.View.EditableTree = {};
Sao.View.EditableTree.editable_mixin = function(widget) {
var key_press = function(event_) {
if ((event_.which == Sao.common.TAB_KEYCODE) ||
(event_.which == Sao.common.UP_KEYCODE) ||
(event_.which == Sao.common.DOWN_KEYCODE) ||
(event_.which == Sao.common.ESC_KEYCODE) ||
(event_.which == Sao.common.RETURN_KEYCODE)) {
this.focus_out();
}
};
widget.el.on('keydown', key_press.bind(widget));
};
Sao.View.EditableTree.Char = Sao.class_(Sao.View.Form.Char, {
class_: 'editabletree-char',
init: function(field_name, model, attributes) {
Sao.View.EditableTree.Char._super.init.call(this, field_name,
model, attributes);
Sao.View.EditableTree.editable_mixin(this);
}
});
Sao.View.EditableTree.Date = Sao.class_(Sao.View.Form.Date, {
class_: 'editabletree-date',
init: function(field_name, model, attributes) {
Sao.View.EditableTree.Date._super.init.call(this, field_name,
model, attributes);
Sao.View.EditableTree.editable_mixin(this);
}
});
Sao.View.EditableTree.Time = Sao.class_(Sao.View.Form.Time, {
class_: 'editabletree-time',
init: function(field_name, model, attributes) {
Sao.View.EditableTree.Time._super.init.call(this, field_name,
model, attributes);
Sao.View.EditableTree.editable_mixin(this);
}
});
Sao.View.EditableTree.TimeDelta = Sao.class_(Sao.View.Form.TimeDelta, {
class_: 'editabletree-timedelta',
init: function(field_name, model, attributes) {
Sao.View.EditableTree.TimeDelta._super.init.call(this, field_name,
model, attributes);
Sao.View.EditableTree.editable_mixin(this);
}
});
Sao.View.EditableTree.Integer = Sao.class_(Sao.View.Form.Integer, {
class_: 'editabletree-integer',
init: function(field_name, model, attributes) {
Sao.View.EditableTree.Integer._super.init.call(this, field_name,
model, attributes);
Sao.View.EditableTree.editable_mixin(this);
}
});
Sao.View.EditableTree.Float = Sao.class_(Sao.View.Form.Float, {
class_: 'editabletree-float',
init: function(field_name, model, attributes) {
Sao.View.EditableTree.Float._super.init.call(this, field_name,
model, attributes);
Sao.View.EditableTree.editable_mixin(this);
}
});
Sao.View.EditableTree.Selection = Sao.class_(Sao.View.Form.Selection, {
class_: 'editabletree-selection',
init: function(field_name, model, attributes) {
Sao.View.EditableTree.Selection._super.init.call(this, field_name,
model, attributes);
Sao.View.EditableTree.editable_mixin(this);
}
});
Sao.View.EditableTree.Boolean = Sao.class_(Sao.View.Form.Boolean, {
class_: 'editabletree-boolean',
init: function(field_name, model, attributes) {
Sao.View.EditableTree.Boolean._super.init.call(this, field_name,
model, attributes);
Sao.View.EditableTree.editable_mixin(this);
}
});
Sao.View.EditableTree.Many2One = Sao.class_(Sao.View.Form.Many2One, {
class_: 'editabletree-many2one',
init: function(field_name, model, attributes) {
Sao.View.EditableTree.Many2One._super.init.call(this, field_name,
model, attributes);
this.el.on('keydown', this.key_press.bind(this));
},
key_press: function(event_) {
if (event_.which == Sao.common.TAB_KEYCODE) {
this.focus_out();
} else {
Sao.View.EditableTree.Many2One._super.key_press.call(this,
event_);
}
}
});
Sao.View.EditableTree.One2One = Sao.class_(Sao.View.Form.One2One, {
class_: 'editabletree-one2one',
init: function(field_name, model, attributes) {
Sao.View.EditableTree.One2One._super.init.call(this, field_name,
model, attributes);
this.el.on('keydown', this.key_press.bind(this));
},
key_press: function(event_) {
if (event_.which == Sao.common.TAB_KEYCODE) {
this.focus_out();
} else {
Sao.View.EditableTree.One2One._super.key_press.call(this,
event_);
}
}
});
Sao.View.EditableTree.One2Many = Sao.class_(Sao.View.EditableTree.Char, {
class_: 'editabletree-one2many',
init: function(field_name, model, attributes) {
Sao.View.EditableTree.One2Many._super.init.call(this, field_name,
model, attributes);
},
display: function(record, field) {
if (record) {
this.el.val('(' + field.get_client(record).length + ')');
} else {
this.el.val('');
}
},
key_press: function(event_) {
if (event_.which == Sao.common.TAB_KEYCODE) {
this.focus_out();
}
},
set_value: function(record, field) {
}
});
Sao.View.EditableTree.Binary = Sao.class_(Sao.View.Form.Binary, {
class_: 'editabletree-binary',
init: function(field_name, model, attributes) {
Sao.View.EditableTree.Binary._super.init.call(this, field_name,
model, attributes);
Sao.View.EditableTree.editable_mixin(this);
}
});
Sao.View.Graph = Sao.class_(Sao.View, {
init: function(screen, xml) {
Sao.View.Graph._super.init.call(this, screen, xml);
this.view_type = 'graph';
this.el = jQuery('
', {
'class': 'graph'
});
this.widgets = {};
this.widget = this.parse(xml.children()[0]);
this.widgets.root = this.widget;
this.el.append(this.widget.el);
},
parse: function(node) {
var field, xfield = null, yfields = [], yattrs;
var child, node_child;
var i, len, j, c_len;
var get_attributes = function(node) {
var attributes = {}, attribute;
for (var i = 0, len = node.attributes.length; i < len; i++) {
attribute = node.attributes[i];
attributes[attribute.name] = attribute.value;
}
return attributes;
};
for (i=0, len=node.children.length; i < len; i++) {
child = node.children[i];
switch (child.tagName) {
case 'x':
for (j=0, c_len=child.children.length; j < c_len; j++) {
xfield = get_attributes(child.children[j]);
field = this.screen.model.fields[xfield.name];
if (!(xfield.string || '')) {
xfield.string = field.description.string;
}
}
break;
case 'y':
for (j=0, c_len=child.children.length; j < c_len; j++) {
yattrs = get_attributes(child.children[j]);
if (!(yattrs.string || '') &&
(yattrs.name != '#')) {
field = this.screen.model.fields[yattrs.name];
yattrs.string = field.description.string;
}
yfields.push(yattrs);
}
break;
}
}
var Widget;
switch (this.attributes.type) {
case 'hbar':
Widget = Sao.View.Graph.HorizontalBar;
break;
case 'line':
Widget = Sao.View.Graph.Line;
break;
case 'pie':
Widget = Sao.View.Graph.Pie;
break;
default:
Widget = Sao.View.Graph.VerticalBar;
}
return new Widget(this, xfield, yfields);
},
display: function() {
return this.widget.display(this.screen.group);
}
});
Sao.View.Graph.Chart = Sao.class_(Object, {
_chart_type: undefined,
init: function(view, xfield, yfields) {
this.view = view;
this.xfield = xfield;
this.yfields = yfields;
this.el = jQuery('
');
this.el.uniqueId();
},
update_data: function(group) {
var data = {};
var record, yfield, key;
var i, len, j, y_len;
this.ids = {};
data.columns = [['labels']];
var key2columns = {};
var fields2load = [this.xfield.name];
for (i = 0, len = this.yfields.length; i < len; i++) {
yfield = this.yfields[i];
data.columns.push([yfield.string]);
key2columns[yfield.key || yfield.name] = i + 1;
fields2load.push(yfield.name);
}
var prms = [];
var set_data = function(index) {
return function () {
record = group[index];
var x = record.field_get(this.xfield.name);
data.columns[0][index + 1] = x;
this._add_id(x, record.id);
var column;
for (j = 0, y_len = this.yfields.length; j < y_len; j++) {
yfield = this.yfields[j];
key = yfield.key || yfield.name;
column = data.columns[key2columns[key]];
if (yfield.domain) {
var ctx = jQuery.extend({},
Sao.session.current_session.context);
ctx.context = ctx;
ctx._user = Sao.session.current_session.user_id;
for (var field in group.model.fields) {
ctx[field] = record.field_get(field);
}
var decoder = new Sao.PYSON.Decoder(ctx);
if (!decoder.decode(yfield.domain)) {
column[index + 1] = 0;
continue;
}
}
if (yfield.name == '#') {
column[index + 1] = 1;
} else {
var value = record.field_get(yfield.name);
if (value && value.isTimeDelta) {
value = value.asSeconds();
}
column[index + 1] = value || 0;
}
}
}.bind(this);
}.bind(this);
var load_field = function(record) {
return function(fname) {
prms.push(record.load(fname));
};
};
var r_prms = [];
for (i = 0, len = group.length; i < len; i++) {
record = group[i];
fields2load.forEach(load_field(group[i]));
for (j = 0, y_len = data.columns.length; j < y_len; j++) {
data.columns[j].push(undefined);
}
r_prms.push(
jQuery.when.apply(jQuery, prms).then(set_data(i)));
}
return jQuery.when.apply(jQuery, r_prms).then(function() {
return data;
});
},
_add_id: function(key, id) {
// c3 do not use the moment instance but its date repr when calling
// onclick
var id_x = (key.isDate || key.isDateTime) ? key._d : key;
if (!(id_x in this.ids)) {
this.ids[id_x] = [];
}
this.ids[id_x].push(id);
},
display: function(group) {
var update_prm = this.update_data(group);
update_prm.done(function(data) {
c3.generate(this._c3_config(data));
}.bind(this));
return update_prm;
},
_c3_config: function(data) {
var c3_config = {};
c3_config.bindto = '#' + this.el.attr('id');
c3_config.data = data;
c3_config.data.type = this._chart_type;
c3_config.data.x = 'labels';
c3_config.data.onclick = this.action.bind(this);
var i, len;
var found, labels;
for (i = 0, len = data.columns.length; i < len; i++) {
labels = data.columns[i];
if (labels[0] == 'labels') {
found = true;
break;
}
}
if (found && (labels.length > 1) &&
(labels[1] && (labels[1].isDateTime || labels[1].isDate)))
{
var format_func, date_format, time_format;
date_format = this.view.screen.context.date_format || '%x';
time_format = '%X';
if (labels[1].isDateTime) {
format_func = function(dt) {
return Sao.common.format_datetime(date_format,
time_format, moment(dt));
};
} else {
format_func = function(dt) {
return Sao.common.format_date(date_format, moment(dt));
};
}
c3_config.axis = {
x: {
type: 'timeseries',
tick: {
format: format_func,
}
}
};
}
return c3_config;
},
action: function(data, element) {
var ids = this.ids[this._action_key(data)];
var ctx = jQuery.extend({}, this.view.screen.context);
delete ctx.active_ids;
delete ctx.active_id;
Sao.Action.exec_keyword('graph_open', {
model: this.view.screen.model_name,
id: ids[0],
ids: ids
}, ctx, false);
},
_action_key: function(data) {
return data.x;
}
});
Sao.View.Graph.VerticalBar = Sao.class_(Sao.View.Graph.Chart, {
_chart_type: 'bar'
});
Sao.View.Graph.HorizontalBar = Sao.class_(Sao.View.Graph.Chart, {
_chart_type: 'bar',
_c3_config: function(data) {
var config = Sao.View.Graph.HorizontalBar._super._c3_config
.call(this, data);
config.axis.rotated = true;
}
});
Sao.View.Graph.Line = Sao.class_(Sao.View.Graph.Chart, {
_chart_type: 'line'
});
Sao.View.Graph.Pie = Sao.class_(Sao.View.Graph.Chart, {
_chart_type: 'pie',
_c3_config: function(data) {
var config = Sao.View.Graph.Pie._super._c3_config.call(this, data);
var pie_columns = [];
var i, len;
var labels, values;
for (i = 0, len = data.columns.length; i < len; i++) {
if (data.columns[i][0] == 'labels') {
labels = data.columns[i].slice(1);
} else {
values = data.columns[i].slice(1);
}
}
// Pie chart do not support axis definition.
delete config.axis;
delete config.data.x;
var format_func, date_format, datetime_format;
if ((labels.length > 0) &&
(labels[0].isDateTime || labels[0].isDate)) {
date_format = this.view.screen.context.date_format || '%x';
datetime_format = date_format + ' %X';
if (labels[1].isDateTime) {
format_func = function(dt) {
return Sao.common.format_datetime(datetime_format, dt);
};
} else {
format_func = function(dt) {
return Sao.common.format_date(date_format, dt);
};
}
}
var label;
for (i = 0, len = labels.length; i < len; i++) {
label = labels[i];
if (format_func) {
label = format_func(label);
}
pie_columns.push([label, values[i]]);
}
config.data.columns = pie_columns;
return config;
},
_add_id: function(key, id) {
var id_x = key;
if (key.isDateTime || key.isDate) {
var date_format = this.view.screen.context.date_format || '%x';
var datetime_format = date_format + ' %X';
if (key.isDateTime) {
id_x = Sao.common.format_datetime(datetime_format, key);
} else {
id_x = Sao.common.format_date(date_format, key);
}
}
if (!(id_x in this.ids)) {
this.ids[id_x] = [];
}
this.ids[id_x].push(id);
},
_action_key: function(data) {
return data.id;
}
});
Sao.View.Calendar = Sao.class_(Sao.View, {
init: function(screen, xml) {
Sao.View.Graph._super.init.call(this, screen, xml);
this.view_type = 'calendar';
this.el = jQuery('
', {
'class': 'calendar'
});
// TODO
Sao.common.warning.run(
Sao.i18n.gettext('Calendar view not yet implemented'),
Sao.i18n.gettext('Warning'));
},
display: function() {
return jQuery.when();
}
});
}());