Use dropdown for attachments
issue7659 review50551002
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
* Remove dialog for input file
|
||||
* Use dropdown for attachment
|
||||
* Manage icons in input
|
||||
* Support RTL language direction
|
||||
* Apply factor on domain parser
|
||||
|
||||
@@ -3412,6 +3412,19 @@
|
||||
|
||||
};
|
||||
|
||||
Sao.common.get_input_data = function(input, callback, char_) {
|
||||
var reader = new FileReader(),
|
||||
file = input[0].files[0];
|
||||
reader.onload = function() {
|
||||
var value = new Uint8Array(reader.result);
|
||||
if (char_) {
|
||||
value = String.fromCharCode.apply(null, value);
|
||||
}
|
||||
callback(value, file.name);
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
};
|
||||
|
||||
Sao.common.ellipsize = function(string, length) {
|
||||
if (string.length <= length) {
|
||||
return string;
|
||||
|
||||
@@ -124,6 +124,14 @@ input[type='color'] {
|
||||
}
|
||||
}
|
||||
|
||||
.input-file {
|
||||
& input[type='file'] {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide empty image displayed as broken image */
|
||||
[src=''] {
|
||||
visibility: hidden;
|
||||
|
||||
+110
-16
@@ -72,6 +72,7 @@
|
||||
icon: 'tryton-attach',
|
||||
label: Sao.i18n.gettext('Attachment'),
|
||||
tooltip: Sao.i18n.gettext('Add an attachment to the record'),
|
||||
dropdown: true,
|
||||
}, {
|
||||
id: 'note',
|
||||
icon: 'tryton-note',
|
||||
@@ -208,16 +209,37 @@
|
||||
'role': 'group'
|
||||
}).appendTo(toolbar.find('.btn-toolbar'));
|
||||
}
|
||||
this.buttons[item.id] = jQuery('<button/>', {
|
||||
var attributes = {
|
||||
'type': 'button',
|
||||
'class': 'btn btn-default navbar-btn',
|
||||
'title': item.label,
|
||||
'id': item.id
|
||||
})
|
||||
.append(Sao.common.ICONFACTORY.get_icon_img(item.icon, {
|
||||
'aria-hidden': 'true',
|
||||
}))
|
||||
.appendTo(group);
|
||||
};
|
||||
if (item.dropdown) {
|
||||
attributes['class'] += ' dropdown-toggle';
|
||||
attributes['data-toggle'] = 'dropdown';
|
||||
attributes['aria-expanded'] = false;
|
||||
attributes['aria-haspopup'] = true;
|
||||
}
|
||||
var button = jQuery('<button/>', attributes)
|
||||
.append(Sao.common.ICONFACTORY.get_icon_img(item.icon, {
|
||||
'aria-hidden': 'true',
|
||||
}));
|
||||
this.buttons[item.id] = button;
|
||||
if (item.dropdown) {
|
||||
var dropdown = jQuery('<div/>', {
|
||||
'class': 'btn-group dropdown',
|
||||
'role': 'group',
|
||||
}).append(button.append(jQuery('<span/>', {
|
||||
'class': 'caret',
|
||||
}))).append(jQuery('<ul/>', {
|
||||
'class': 'dropdown-menu',
|
||||
'role': 'menu',
|
||||
'aria-labelledby': item.id,
|
||||
})).appendTo(group);
|
||||
} else {
|
||||
button.appendTo(group);
|
||||
}
|
||||
this.buttons[item.id].click(item, function(event) {
|
||||
var item = event.data;
|
||||
var button = this.buttons[item.id];
|
||||
@@ -234,8 +256,17 @@
|
||||
}).appendTo(jQuery('<div/>', {
|
||||
'class': 'navbar-text hidden-xs',
|
||||
}).insertAfter(this.buttons.previous));
|
||||
toolbar.find('.btn-toolbar > .btn-group').last().addClass(
|
||||
'hidden-xs');
|
||||
toolbar.find('.btn-toolbar > .btn-group').last()
|
||||
.addClass( 'hidden-xs')
|
||||
.find('.dropdown')
|
||||
.on('show.bs.dropdown', function() {
|
||||
jQuery(this).parents('.btn-group')
|
||||
.removeClass( 'hidden-xs');
|
||||
})
|
||||
.on('hide.bs.dropdown', function() {
|
||||
jQuery(this).parents('.btn-group')
|
||||
.addClass('hidden-xs');
|
||||
});
|
||||
var tabs = jQuery('#tabs');
|
||||
toolbar.affix({
|
||||
'target': tabs.parent(),
|
||||
@@ -487,7 +518,7 @@
|
||||
Sao.i18n.gettext('Print report')]
|
||||
].forEach(function(menu_action) {
|
||||
var button = jQuery('<div/>', {
|
||||
'class': 'btn-group',
|
||||
'class': 'btn-group dropdown',
|
||||
'role': 'group'
|
||||
})
|
||||
.append(jQuery('<button/>', {
|
||||
@@ -521,7 +552,7 @@
|
||||
jQuery(this).parents('.btn-group').addClass(
|
||||
'hidden-xs');
|
||||
});
|
||||
var menu = button.find('ul[role*="menu"]');
|
||||
var menu = button.find('.dropdown-menu');
|
||||
button.click(function() {
|
||||
menu.find('.' + menu_action[0] + '_button').remove();
|
||||
var buttons = screen.get_buttons();
|
||||
@@ -886,14 +917,77 @@
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
attach: function() {
|
||||
var record = this.screen.current_record;
|
||||
if (!record || (record.id < 0)) {
|
||||
attach: function(evt) {
|
||||
var window_ = function() {
|
||||
return new Sao.Window.Attachment(record, function() {
|
||||
this.update_attachment_count(true);
|
||||
}.bind(this));
|
||||
}.bind(this);
|
||||
var dropdown = this.buttons.attach.parents('.dropdown');
|
||||
if (!evt) {
|
||||
window.setTimeout(function() {
|
||||
this.buttons.attach.click();
|
||||
}.bind(this));
|
||||
return;
|
||||
}
|
||||
new Sao.Window.Attachment(record, function() {
|
||||
this.update_attachment_count(true);
|
||||
}.bind(this));
|
||||
var record = this.screen.current_record;
|
||||
var menu = dropdown.find('.dropdown-menu');
|
||||
menu.children().remove();
|
||||
Sao.Window.Attachment.get_attachments(record)
|
||||
.then(function(attachments) {
|
||||
attachments.forEach(function(value) {
|
||||
var name = value[0],
|
||||
callback = value[1];
|
||||
var link = jQuery('<a/>', {
|
||||
'role': 'menuitem',
|
||||
'href': '#',
|
||||
'tabindex': -1,
|
||||
}).append(name).appendTo(jQuery('<li/>', {
|
||||
'role': 'presentation',
|
||||
}).appendTo(menu));
|
||||
if (typeof callback == 'string') {
|
||||
link.attr('href', callback);
|
||||
link.attr('target', '_new');
|
||||
} else {
|
||||
link.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
callback();
|
||||
});
|
||||
}
|
||||
});
|
||||
}).always(function() {
|
||||
menu.append(jQuery('<li/>', {
|
||||
'class': 'divider',
|
||||
}));
|
||||
menu.append(jQuery('<li/>', {
|
||||
'role': 'presentation',
|
||||
'class': 'input-file',
|
||||
}).append(jQuery('<input/>', {
|
||||
'type': 'file',
|
||||
'role': 'menuitem',
|
||||
'tabindex': -1,
|
||||
}).change(function() {
|
||||
Sao.common.get_input_data(
|
||||
jQuery(this), function(data, filename) {
|
||||
window_().add_data(data, filename);
|
||||
});
|
||||
})).append(jQuery('<a/>', {
|
||||
'role': 'menuitem',
|
||||
'href': '#',
|
||||
'tabindex': -1,
|
||||
}).append(Sao.i18n.gettext('Add...'))));
|
||||
menu.append(jQuery('<li/>', {
|
||||
'role': 'presentation',
|
||||
}).append(jQuery('<a/>', {
|
||||
'role': 'menuitem',
|
||||
'href': '#',
|
||||
'tabindex': -1,
|
||||
}).append(Sao.i18n.gettext('Manage...'))
|
||||
.click(function(evt) {
|
||||
evt.preventDefault();
|
||||
window_();
|
||||
})));
|
||||
});
|
||||
},
|
||||
update_attachment_count: function(reload) {
|
||||
var record = this.screen.current_record;
|
||||
|
||||
+20
-57
@@ -3512,14 +3512,17 @@ function eval_pyson(value){
|
||||
).appendTo(group);
|
||||
this.but_save_as.click(this.save_as.bind(this));
|
||||
|
||||
this.but_select = jQuery('<button/>', {
|
||||
'class': 'btn btn-default',
|
||||
this.input_select = jQuery('<input/>', {
|
||||
'type': 'file',
|
||||
}).change(this.select.bind(this));
|
||||
this.but_select = jQuery('<div/>', {
|
||||
'class': 'btn btn-default input-file',
|
||||
'type': 'button',
|
||||
'aria-label': Sao.i18n.gettext("Select"),
|
||||
'title': Sao.i18n.gettext("Select..."),
|
||||
}).append(Sao.common.ICONFACTORY.get_icon_img('tryton-search')
|
||||
}).append(this.input_select
|
||||
).append(Sao.common.ICONFACTORY.get_icon_img('tryton-search')
|
||||
).appendTo(group);
|
||||
this.but_select.click(this.select.bind(this));
|
||||
|
||||
this.but_clear = jQuery('<button/>', {
|
||||
'class': 'btn btn-default',
|
||||
@@ -3533,9 +3536,11 @@ function eval_pyson(value){
|
||||
return group;
|
||||
},
|
||||
filename_field: function() {
|
||||
var record = this.record();
|
||||
if (record) {
|
||||
return record.model.fields[this.filename];
|
||||
if (this.filename) {
|
||||
var record = this.record();
|
||||
if (record) {
|
||||
return record.model.fields[this.filename];
|
||||
}
|
||||
}
|
||||
},
|
||||
update_buttons: function(value) {
|
||||
@@ -3550,58 +3555,16 @@ function eval_pyson(value){
|
||||
}
|
||||
},
|
||||
select: function() {
|
||||
var record = this.record();
|
||||
var record = this.record(),
|
||||
field = this.field(),
|
||||
filename_field = this.filename_field();
|
||||
|
||||
var close = function() {
|
||||
file_dialog.modal.on('hidden.bs.modal', function(event) {
|
||||
jQuery(this).remove();
|
||||
});
|
||||
file_dialog.modal.modal('hide');
|
||||
};
|
||||
|
||||
var save_file = function() {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(evt) {
|
||||
var field = this.field();
|
||||
var uint_array = new Uint8Array(reader.result);
|
||||
var value;
|
||||
if (field.get_size) {
|
||||
value = uint_array;
|
||||
} else {
|
||||
value = String.fromCharCode.apply(null, uint_array);
|
||||
}
|
||||
field.set_client(record, value);
|
||||
}.bind(this);
|
||||
reader.onloadend = function(evt) {
|
||||
close();
|
||||
};
|
||||
var file = file_selector[0].files[0];
|
||||
reader.readAsArrayBuffer(file);
|
||||
if (this.filename) {
|
||||
this.filename_field().set_client(record, file.name);
|
||||
Sao.common.get_input_data(this.input_select, function(data, filename) {
|
||||
field.set_client(record, data);
|
||||
if (filename_field) {
|
||||
filename_field.set_client(record, filename);
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
var file_dialog = new Sao.Dialog(
|
||||
Sao.i18n.gettext('Select'), 'file-dialog');
|
||||
file_dialog.footer.append(jQuery('<button/>', {
|
||||
'class': 'btn btn-link',
|
||||
'type': 'button'
|
||||
}).append(Sao.i18n.gettext('Cancel')).click(close))
|
||||
.append(jQuery('<button/>', {
|
||||
'class': 'btn btn-primary',
|
||||
'type': 'submit'
|
||||
}).append(Sao.i18n.gettext('OK')).click(save_file));
|
||||
file_dialog.content.submit(function(e) {
|
||||
save_file();
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
var file_selector = jQuery('<input/>', {
|
||||
type: 'file'
|
||||
}).appendTo(file_dialog.body);
|
||||
|
||||
file_dialog.modal.modal('show');
|
||||
}, !field.get_size);
|
||||
},
|
||||
open: function() {
|
||||
var params = {};
|
||||
|
||||
+64
-18
@@ -55,23 +55,12 @@
|
||||
this.info_bar = new Sao.Window.InfoBar();
|
||||
var view_type = kwargs.view_type || 'form';
|
||||
|
||||
var form_prm = jQuery.when();
|
||||
var screen_views = [];
|
||||
for (var i = 0, len = this.screen.views.length; i < len; i++) {
|
||||
screen_views.push(this.screen.views[i].view_type);
|
||||
}
|
||||
if (!~screen_views.indexOf(view_type) &&
|
||||
!~this.screen.view_to_load.indexOf(view_type)) {
|
||||
form_prm = this.screen.add_view_id(null, view_type);
|
||||
}
|
||||
|
||||
var switch_prm = form_prm.then(function() {
|
||||
return this.screen.switch_view(view_type).done(function() {
|
||||
this.switch_prm = this.screen.switch_view(view_type)
|
||||
.done(function() {
|
||||
if (kwargs.new_) {
|
||||
this.screen.new_(undefined, kwargs.rec_name);
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
var dialog = new Sao.Dialog('', 'window-form', 'lg', false);
|
||||
this.el = dialog.modal;
|
||||
this.el.on('keydown', function(e) {
|
||||
@@ -231,7 +220,7 @@
|
||||
|
||||
dialog.body.append(this.info_bar.el);
|
||||
|
||||
switch_prm.done(function() {
|
||||
this.switch_prm.done(function() {
|
||||
title_prm.done(dialog.add_title.bind(dialog));
|
||||
content.append(this.screen.screen_container.alternate_viewport);
|
||||
this.el.modal('show');
|
||||
@@ -433,14 +422,14 @@
|
||||
mode: ['tree', 'form'],
|
||||
context: context,
|
||||
});
|
||||
screen.switch_view().done(function() {
|
||||
screen.search_filter();
|
||||
});
|
||||
var title = record.rec_name().then(function(rec_name) {
|
||||
return Sao.i18n.gettext('Attachments (%1)', rec_name);
|
||||
});
|
||||
Sao.Window.Attachment._super.init.call(this, screen, this.callback,
|
||||
{view_type: 'tree', title: title});
|
||||
this.switch_prm = this.switch_prm.then(function() {
|
||||
return screen.search_filter();
|
||||
});
|
||||
},
|
||||
callback: function(result) {
|
||||
var prm = jQuery.when();
|
||||
@@ -450,8 +439,65 @@
|
||||
if (this.attachment_callback) {
|
||||
prm.always(this.attachment_callback.bind(this));
|
||||
}
|
||||
}
|
||||
},
|
||||
add_data: function(data, filename) {
|
||||
var screen = this.screen;
|
||||
this.switch_prm.then(function() {
|
||||
screen.set_current_record(null);
|
||||
screen.switch_view('form').then(function() {
|
||||
screen.new_().then(function(record) {
|
||||
var data_field = record.model.fields.data;
|
||||
record.field_set_client(
|
||||
data_field.description.filename, filename);
|
||||
record.field_set_client('data', data);
|
||||
screen.display();
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
Sao.Window.Attachment.get_attachments = function(record) {
|
||||
var prm;
|
||||
if (record && (record.id >= 0)) {
|
||||
var context = record.get_context();
|
||||
prm = Sao.rpc({
|
||||
'method': 'model.ir.attachment.search_read',
|
||||
'params': [
|
||||
[['resource', '=', record.model.name + ',' + record.id]],
|
||||
0, 20, null, ['rec_name', 'name', 'type', 'link'],
|
||||
context],
|
||||
}, record.model.session);
|
||||
} else {
|
||||
prm = jQuery.when([]);
|
||||
}
|
||||
var partial = function(callback, attachment, context, session) {
|
||||
return function() {
|
||||
return callback(attachment, context, session);
|
||||
};
|
||||
};
|
||||
return prm.then(function(attachments) {
|
||||
return attachments.map(function(attachment) {
|
||||
var name = attachment.rec_name;
|
||||
if (attachment.type == 'link') {
|
||||
return [name, attachment.link];
|
||||
} else {
|
||||
var callback = Sao.Window.Attachment[
|
||||
'open_' + attachment.type];
|
||||
return [name, partial(
|
||||
callback, attachment, context, record.model.session)];
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
Sao.Window.Attachment.open_data = function(attachment, context, session) {
|
||||
Sao.rpc({
|
||||
'method': 'model.ir.attachment.read',
|
||||
'params': [
|
||||
[attachment.id], ['data'], context],
|
||||
}, session).then(function(values) {
|
||||
Sao.common.download_file(values[0].data, attachment.name);
|
||||
});
|
||||
};
|
||||
|
||||
Sao.Window.Note = Sao.class_(Sao.Window.Form, {
|
||||
init: function(record, callback) {
|
||||
|
||||
Reference in New Issue
Block a user