sao-styles/src/tab.js

607 lines
24 KiB
JavaScript

/* 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.Tab = Sao.class_(Object, {
init: function() {
Sao.Tab.tabs.push(this);
this.buttons = {};
},
create_tabcontent: function() {
this.el = jQuery('<div/>', {
'class': this.class_
});
this.title = this.make_title_bar();
this.el.append(this.title);
var toolbar = this.create_toolbar();
this.el.append(toolbar);
},
make_title_bar: function() {
var title = jQuery('<div/>', {
'class': 'tab-title-bar ui-widget-header ui-corner-all'
});
var menu = this.set_menu();
title.append(menu);
title.append(jQuery('<button/>', {
'class': 'tab-title'
}).button({
label: this.name,
text: true,
icons: {
primary: 'ui-icon-triangle-1-s'
}
}).click(function() {
menu.toggle().position({
my: 'left top',
at: 'left bottom',
of: jQuery(this)
});
// Bind hide after the processing of the current click
window.setTimeout(function() {
jQuery(document).one('click', function() {
menu.hide();
});
}, 0);
}));
this.status = jQuery('<span/>', {
'class': 'tab-status'
});
title.append(this.status);
this.info = jQuery('<span/>', {
'class': 'tab-info'
});
title.append(this.info);
return title;
},
set_menu: function() {
var menu = jQuery('<ul/>');
this.menu_def.forEach(function(definition) {
var icon = definition[0];
var name = definition[1];
var func = definition[2];
if (!func) {
return;
}
var item = jQuery('<li/>').append(
jQuery('<a/>').append(jQuery('<span/>', {
'class': 'ui-icon ' + icon
})).append(name));
menu.append(item);
item.click(function() {
this[func]();
}.bind(this));
}.bind(this));
menu.menu({}).hide().css({
position: 'absolute',
'z-index': 100
});
return menu;
},
create_toolbar: function() {
var toolbar = jQuery('<div/>', {
'class': 'ui-widget-header ui-corner-all'
});
var add_button = function(tool) {
var click_func = function() {
this[tool[4]]();
};
var button = jQuery('<button/>').button({
id: tool[0],
text: tool[2],
icons: {
primary: tool[1]
},
label: tool[2]
})
.click(click_func.bind(this));
toolbar.append(button);
// TODO tooltip
this.buttons[tool[0]] = button;
};
this.toolbar_def.forEach(add_button.bind(this));
return toolbar;
},
close: function() {
var tabs = jQuery('#tabs > div');
tabs.tabs('select', this.id);
return this.modified_save().then(function() {
tabs.tabs('remove', this.id);
if (!tabs.find('> ul').children().length) {
tabs.remove();
}
Sao.Tab.tabs.splice(Sao.Tab.tabs.indexOf(this), 1);
}.bind(this));
}
});
Sao.Tab.counter = 0;
Sao.Tab.tabs = [];
Sao.Tab.tabs.close = function(warning) {
if (warning && Sao.Tab.tabs.length) {
return Sao.common.sur.run(
'The following action requires to close all tabs.\n' +
'Do you want to continue?').then(function() {
return Sao.Tab.tabs.close(false);
});
}
if (Sao.Tab.tabs.length) {
var tab = Sao.Tab.tabs[0];
return tab.close().then(function() {
if (!~Sao.Tab.tabs.indexOf(tab)) {
return Sao.Tab.tabs.close();
} else {
return jQuery.Deferred().reject();
}
});
}
if (Sao.main_menu_screen) {
Sao.main_menu_screen.save_tree_state();
Sao.main_menu_screen = null;
}
return jQuery.when();
};
Sao.Tab.tabs.close_current = function() {
var tabs = jQuery('#tabs > div');
var tab = Sao.Tab.tabs[tabs.tabs('option', 'active')];
tab.close();
};
Sao.Tab.create = function(attributes) {
if (attributes.context === undefined) {
attributes.context = {};
}
var tab;
if (attributes.model) {
tab = new Sao.Tab.Form(attributes.model, attributes);
} else {
tab = new Sao.Tab.Board(attributes);
}
if (!jQuery('#tabs').children().length) {
jQuery('#tabs').append(jQuery('<div/>').append(jQuery('<ul/>')));
}
var tabs = jQuery('#tabs > div');
tabs.tabs();
tab.id = '#tab-' + Sao.Tab.counter++;
tabs.tabs('add', tab.id, tab.name);
tabs.find('> ul li').last().append(jQuery('<a href="#">' +
'<span class="ui-icon ui-icon-circle-close"></span>' +
'</a>')
.hover(
function() {
jQuery(this).css('cursor', 'pointer');
},
function() {
jQuery(this).css('cursor', 'default');
})
.click(function() {
tab.close();
}));
jQuery(tab.id).html(tab.el);
tabs.tabs('select', tab.id);
jQuery(window).resize();
};
Sao.Tab.Form = Sao.class_(Sao.Tab, {
class_: 'tab-form',
init: function(model_name, attributes) {
Sao.Tab.Form._super.init.call(this);
var screen = new Sao.Screen(model_name, attributes);
screen.tab = this;
this.screen = screen;
this.attributes = jQuery.extend({}, attributes);
this.name = attributes.name; // XXX use screen current view title
if (!Sao.common.MODELHISTORY.contains(model_name)) {
this.menu_def = jQuery.extend([], this.menu_def);
this.menu_def[10] = jQuery.extend([], this.menu_def[10]);
// Remove callback to revision
this.menu_def[10][2] = null;
}
this.create_tabcontent();
var access = Sao.common.MODELACCESS.get(model_name);
[['new', 'create'], ['save', 'write']].forEach(function(e) {
var button = e[0];
var access_type = e[1];
this.buttons[button].prop('disabled', !access[access_type]);
}.bind(this));
this.view_prm = this.screen.switch_view().done(function() {
this.el.append(screen.screen_container.el);
if (attributes.res_id) {
screen.group.load([attributes.res_id]);
screen.set_current_record(
screen.group.get(attributes.res_id));
screen.display();
} else {
if (screen.current_view.view_type == 'form') {
screen.new_();
}
if (~['tree', 'graph', 'calendar'].indexOf(
screen.current_view.view_type)) {
screen.search_filter();
}
}
this.update_revision();
}.bind(this));
},
// TODO translate labels
toolbar_def: [
['new', 'ui-icon-document', 'New', 'Create a new record', 'new_'],
['save', 'ui-icon-disk', 'Save', 'Save this record', 'save'],
['switch', 'ui-icon-arrow-4-diag', 'Switch', 'Switch view',
'switch_'],
['reload', 'ui-icon-refresh', 'Reload', 'Reload', 'reload'],
['previous', 'ui-icon-arrowthick-1-w', 'Previous',
'Previous Record', 'previous'],
['next', 'ui-icon-arrowthick-1-e', 'Next', 'Next Record', 'next'],
['attach', 'ui-icon-pin-w', 'Attachment',
'Add an attachment to the record', 'attach']
],
menu_def: [
['ui-icon-document', 'New', 'new_'],
['ui-icon-disk', 'Save', 'save'],
['ui-icon-arrow-4-diag', 'Switch', 'switch_'],
['ui-icon-refresh', 'Reload/Undo', 'reload'],
['ui-icon-copy', 'Duplicate', 'copy'],
['ui-icon-trash', 'Delete', 'delete_'],
['ui-icon-arrowthick-1-w', 'Previous', 'previous'],
['ui-icon-arrowthick-1-e', 'Next', 'next'],
['ui-icon-search', 'Search', 'search'],
['ui-icon-clock', 'View Logs...', 'logs'],
['ui-icon-clock', 'Show revisions...', 'revision'],
['ui-icon-circle-close', 'Close Tab', 'close'],
['ui-icon-pin-w', 'Attachment', 'attach'],
['ui-icon-gear', 'Action', 'action'],
['ui-icon-arrowreturn-1-e', 'Relate', 'relate'],
['ui-icon-print', 'Print', 'print']
],
create_toolbar: function() {
var toolbar = Sao.Tab.Form._super.create_toolbar.call(this);
var screen = this.screen;
var buttons = this.buttons;
var prm = screen.model.execute('view_toolbar_get', [],
screen.context);
prm.done(function(toolbars) {
// TODO translation
[
['action', 'ui-icon-gear', 'Action', 'Launch action'],
['relate', 'ui-icon-arrowreturn-1-e', 'Relate',
'Open related records'],
['print', 'ui-icon-print', 'Print', 'Print report']
].forEach(function(menu_action) {
var button = jQuery('<button/>').button({
id: menu_action[0],
text: true,
icons: {
primary: menu_action[1],
secondary: 'ui-icon-triangle-1-s'
},
label: menu_action[2]
});
buttons[menu_action[0]] = button;
toolbar.append(button);
var menu = jQuery('<ul/>');
button.click(function() {
menu.toggle().position({
my: 'left top',
at: 'left bottom',
of: button
});
if (menu_action[0] == 'action') {
menu.find('.action_button').remove();
var buttons = screen.get_buttons();
buttons.forEach(function(button) {
var item = jQuery('<li/>', {
'class': 'ui-menu-item action_button'
}).append(
jQuery('<a/>').append(
button.attributes.string || ''));
menu.append(item);
item.click(function() {
screen.button(button.attributes);
});
});
}
// Bind hide after the processing of the current click
window.setTimeout(function() {
jQuery(document).one('click', function() {
menu.hide();
});
}, 0);
});
toolbars[menu_action[0]].forEach(function(action) {
var item = jQuery('<li/>').append(
jQuery('<a/>').append(action.name));
menu.append(item);
item.click(function() {
screen.save_current().then(function() {
var exec_action = jQuery.extend({}, action);
var record_id = null;
if (screen.current_record) {
record_id = screen.current_record.id;
}
var record_ids = screen.current_view
.selected_records().map(function(record) {
return record.id;
});
exec_action = Sao.Action.evaluate(exec_action,
menu_action[0], screen.current_record);
var data = {
model: screen.model_name,
id: record_id,
ids: record_ids
};
Sao.Action.exec_action(exec_action, data,
screen.context);
});
});
});
menu.menu({}).hide().css({
position: 'absolute',
'z-index': 100
});
toolbar.append(menu);
});
});
return toolbar;
},
modified_save: function() {
this.screen.save_tree_state();
this.screen.current_view.set_value();
if (this.screen.modified()) {
return Sao.common.sur_3b.run('This record has been modified\n' +
'do you want to save it?')
.then(function(result) {
switch(result) {
case 'ok':
return this.save();
case 'ko':
return this.reload(false);
default:
return jQuery.Deferred().reject();
}
}.bind(this));
}
return jQuery.when();
},
new_: function() {
if (!Sao.common.MODELACCESS.get(this.screen.model_name).create) {
return;
}
this.modified_save().done(function() {
this.screen.new_();
// TODO message
// TODO activate_save
}.bind(this));
},
save: function() {
if (!Sao.common.MODELACCESS.get(this.screen.model_name).write) {
return;
}
// TODO message
return this.screen.save_current();
},
switch_: function() {
this.modified_save().done(function() {
this.screen.switch_view();
}.bind(this));
},
reload: function(test_modified) {
if (test_modified === undefined) {
test_modified = true;
}
var reload = function() {
this.screen.cancel_current().then(function() {
this.screen.save_tree_state(false);
if (this.screen.current_view.view_type != 'form') {
this.screen.search_filter(
this.screen.screen_container.search_entry.val());
// TODO set current_record
}
this.screen.display();
// TODO message
// TODO activate_save
}.bind(this));
}.bind(this);
if (test_modified) {
return this.modified_save().then(reload);
} else {
return reload();
}
},
copy: function() {
if (!Sao.common.MODELACCESS.get(this.screen.model_name).create) {
return;
}
this.modified_save().done(function() {
this.screen.copy();
// TODO message
}.bind(this));
},
delete_: function() {
if (!Sao.common.MODELACCESS.get(this.screen.model_name)['delete']) {
return;
}
var msg;
if (this.screen.current_view.view_type == 'form') {
msg = 'Are you sure to remove this record?'; // TODO translate
} else {
msg = 'Are you sure to remove those records?';
}
Sao.common.sur.run(msg).done(function() {
this.screen.remove(true, false, true).done(function() {
// TODO message
});
}.bind(this));
},
previous: function() {
this.modified_save().done(function() {
this.screen.display_previous();
// TODO message and activate_save
}.bind(this));
},
next: function() {
this.modified_save().done(function() {
this.screen.display_next();
// TODO message and activate_save
}.bind(this));
},
search: function() {
var search_entry = this.screen.screen_container.search_entry;
if (search_entry.is(':visible')) {
window.setTimeout(function() {
search_entry.focus();
}, 0);
}
},
logs: function() {
var record = this.screen.current_record;
if ((!record) || (record.id < 0)) {
// TODO message
return;
}
// TODO translation
var fields = [
['id', 'ID:'],
['create_uid.rec_name', 'Creation User:'],
['create_date', 'Creation Date:'],
['write_uid.rec_name', 'Latest Modification by:'],
['write_date', 'Latest Modification Date:']
];
this.screen.model.execute('read', [[record.id],
fields.map(function(field) {
return field[0];
})], this.screen.context)
.then(function(result) {
result = result[0];
var message = '';
fields.forEach(function(field) {
var key = field[0];
var label = field[1];
var value = result[key] || '/';
if (result[key] &&
~['create_date', 'write_date'].indexOf(key)) {
value = Sao.common.format_datetime(
Sao.common.date_format(),
'%H:%M:%S',
value);
}
message += label + ' ' + value + '\n';
});
message += 'Model: ' + this.screen.model.name;
Sao.common.message.run(message);
}.bind(this));
},
revision: function() {
var current_id = null;
if (this.screen.current_record) {
current_id = this.screen.current_record.id;
}
var set_revision = function(revision) {
if (revision) {
// Add a millisecond as microseconds are truncated
revision.setMilliseconds(revision.getMilliseconds() + 1);
}
if (revision != this.screen.context._datetime) {
// Update screen context that will be propagated by
// recreating new group
this.screen.context._datetime = revision;
if (this.screen.current_view.view_type != 'form') {
this.screen.search_filter(
this.screen.screen_container
.search_entry.val());
} else {
// Test if record exist in revisions
this.screen.new_group([current_id]);
}
this.screen.display();
this.update_revision();
}
}.bind(this);
this.modified_save().done(function() {
var ids = this.screen.current_view.selected_records().map(
function(record) {
return record.id;
});
this.screen.model.execute('history_revisions',
[ids], this.screen.context)
.then(function(revisions) {
new Sao.Window.Revision(revisions, set_revision);
});
}.bind(this));
},
update_revision: function() {
var revision = this.screen.context._datetime;
var label;
if (revision) {
var date_format = Sao.common.date_format();
var time_format = '%H:%M:%S.%f';
revision = Sao.common.format_datetime(date_format, time_format,
revision);
label = this.name + ' @ '+ revision;
} else {
label = this.name;
}
this.title.find('button').button({
label: label
});
['new', 'save'].forEach(function(button) {
this.buttons[button].prop('disabled', revision);
}.bind(this));
},
attach: function() {
var record = this.screen.current_record;
if (!record || (record.id < 0)) {
return;
}
new Sao.Window.Attachment(record, function() {
this.update_attachment_count(true);
}.bind(this));
},
update_attachment_count: function(reload) {
var record = this.screen.current_record;
if (record) {
record.get_attachment_count(reload).always(
this.attachment_count.bind(this));
} else {
this.attachment_count(0);
}
},
attachment_count: function(count) {
var label = 'Attachment(' + count + ')'; // TODO translate
this.buttons.attach.button('option', 'label', label);
if (count) {
this.buttons.attach.button('option', 'icons', {
primary: 'ui-icon-pin-s'
});
} else {
this.buttons.attach.button('option', 'icons', {
primary: 'ui-icon-pin-w'
});
}
var record_id = this.screen.get_id();
this.buttons.attach.prop('disabled',
record_id < 0 || record_id === null);
},
action: function() {
this.buttons.action.click();
},
relate: function() {
this.buttons.relate.click();
},
print: function() {
this.buttons.print.click();
}
});
}());