1252 lines
35 KiB
JavaScript
1252 lines
35 KiB
JavaScript
// ReportContainer Contains ReportBuilder objects for all DocTypes
|
|
// - Only one ReportContainer exists
|
|
// - Page header is als a part
|
|
// - New ReportBuilder is made here
|
|
|
|
_r.ReportContainer = function() {
|
|
this.wrapper = page_body.add_page("Report Builder", function() { });
|
|
this.wrapper.className ='layout_wrapper';
|
|
var head_div = $a(this.wrapper, 'div');
|
|
this.rb_area = $a(this.wrapper, 'div');
|
|
|
|
$dh(this.wrapper);
|
|
|
|
var me = this;
|
|
this.rb_dict = {};
|
|
|
|
// tool bar
|
|
this.page_head = new PageHeader(head_div);
|
|
$y(this.page_head.wrapper, {marginBottom:'0px'});
|
|
|
|
// buttons
|
|
|
|
var run_fn = function() {
|
|
if(me.cur_rb){
|
|
me.cur_rb.dt.start_rec = 1;
|
|
me.cur_rb.dt.run();
|
|
}
|
|
}
|
|
|
|
var runbtn = this.page_head.add_button('Run', run_fn, 1, 'ui-icon-circle-triangle-e', 1);
|
|
|
|
// new
|
|
if(has_common(['Administrator', 'System Manager'], user_roles)) {
|
|
// save
|
|
|
|
var savebtn = this.page_head.add_button('Save', function() {if(me.cur_rb) me.cur_rb.save_criteria(); }, 0, 'ui-icon-disk');
|
|
|
|
// advanced
|
|
var fn = function() {
|
|
if(me.cur_rb) {
|
|
if(!me.cur_rb.current_loaded) {
|
|
msgprint("error:You must save the report before you can set Advanced features");
|
|
return;
|
|
}
|
|
loaddoc('Search Criteria', me.cur_rb.sc_dict[me.cur_rb.current_loaded]);
|
|
}
|
|
};
|
|
var advancedbtn = this.page_head.add_button('Advanced Settings', fn);
|
|
}
|
|
|
|
// set a type
|
|
this.set_dt = function(dt, onload) {
|
|
my_onload = function(f) {
|
|
if(!f.forbidden) {
|
|
me.cur_rb = f;
|
|
me.cur_rb.mytabs.items['Result'].expand();
|
|
if(onload)onload(f);
|
|
}
|
|
}
|
|
|
|
if(me.cur_rb)
|
|
me.cur_rb.hide();
|
|
if(me.rb_dict[dt]){
|
|
me.rb_dict[dt].show(my_onload);
|
|
} else {
|
|
me.rb_dict[dt] = new _r.ReportBuilder(me.rb_area, dt, my_onload);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// ===================================================================================
|
|
// + ReportBuilder
|
|
// + Datatable (grid)
|
|
// + ColumnPicker
|
|
// + ReportFilter
|
|
//
|
|
// - Contains all methods relating to saving, loading and executing Search Criteria
|
|
// - Contains ui objects of the report including tabs
|
|
|
|
_r.ReportBuilder = function(parent, doctype, onload) {
|
|
this.menuitems = {};
|
|
this.has_primary_filters = false;
|
|
this.doctype = doctype;
|
|
this.forbidden = 0;
|
|
|
|
this.filter_fields = [];
|
|
this.filter_fields_dict = {};
|
|
|
|
var me = this;
|
|
|
|
this.fn_list = ['beforetableprint','beforerowprint','afterrowprint','aftertableprint','customize_filters','get_query'];
|
|
|
|
this.wrapper = $a(parent, 'div', 'finder_wrapper');
|
|
|
|
this.make_tabs();
|
|
this.current_loaded = null;
|
|
this.setup_doctype(onload);
|
|
|
|
this.hide = function() {
|
|
$dh(me.wrapper);
|
|
}
|
|
this.show = function(my_onload) {
|
|
$ds(me.wrapper);
|
|
|
|
// reset main title
|
|
this.set_main_title('Report: ' + get_doctype_label(me.doctype));
|
|
|
|
if(my_onload)my_onload(me);
|
|
}
|
|
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportBuilder.prototype.make_tabs = function() {
|
|
this.tab_wrapper = $a(this.wrapper, 'div', 'finder_tab_area');
|
|
this.mytabs = new TabbedPage(this.tab_wrapper);
|
|
|
|
this.mytabs.add_item('Result', null, null, 1);
|
|
this.mytabs.add_item('More Filters', null, null, 1);
|
|
this.mytabs.add_item('Select Columns', null, null, 1);
|
|
|
|
this.mytabs.tabs = this.mytabs.items;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportBuilder.prototype.make_body = function() {
|
|
|
|
this.set_main_title('Report: ' + get_doctype_label(this.doctype));
|
|
var me = this;
|
|
|
|
this.make_save_criteria();
|
|
this.column_picker = new _r.ReportColumnPicker(this);
|
|
this.report_filters = new _r.ReportFilters(this);
|
|
}
|
|
|
|
//
|
|
// Make list of all Criterias relating to this DocType
|
|
// -------------------------------------------------------------------------------------
|
|
// Search Criterias are loaded with the DocType - put them in a list and dict
|
|
|
|
_r.ReportBuilder.prototype.make_save_criteria = function() {
|
|
var me = this;
|
|
|
|
// make_list
|
|
// ---------
|
|
|
|
this.sc_list = []; this.sc_dict = {};
|
|
for(var n in locals['Search Criteria']) {
|
|
var d = locals['Search Criteria'][n];
|
|
if(d.doc_type==this.doctype) {
|
|
this.sc_list[this.sc_list.length] = d.criteria_name;
|
|
this.sc_dict[d.criteria_name] = n;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Save Criteria
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportBuilder.prototype.save_criteria = function(save_as) {
|
|
var overwrite = 0;
|
|
// is loaded?
|
|
if(this.current_loaded && (!save_as)) {
|
|
var overwrite = confirm('Do you want to overwrite the saved criteria "'+this.current_loaded+'"');
|
|
if(overwrite) {
|
|
var doc = locals['Search Criteria'][this.sc_dict[this.current_loaded]];
|
|
var criteria_name = this.current_loaded;
|
|
}
|
|
}
|
|
|
|
// new criteria
|
|
if(!overwrite) {
|
|
var criteria_name = prompt('Select a name for the criteria:', '');
|
|
if(!criteria_name)
|
|
return;
|
|
|
|
var dn = createLocal('Search Criteria');
|
|
var doc = locals['Search Criteria'][dn];
|
|
|
|
doc.criteria_name = criteria_name;
|
|
doc.doc_type = this.doctype;
|
|
}
|
|
|
|
var cl = []; var fl = {};
|
|
|
|
// save columns
|
|
var t = this.column_picker.get_selected();
|
|
for(var i=0;i<t.length;i++)
|
|
cl.push(t[i].parent + '\1' + t[i].label);
|
|
|
|
// save filters
|
|
for(var i=0;i<this.filter_fields.length;i++) {
|
|
var t = this.filter_fields[i];
|
|
var v = t.get_value?t.get_value():'';
|
|
if(v)fl[t.df.parent + '\1' + t.df.label + (t.bound?('\1'+t.bound):'')] = v;
|
|
}
|
|
|
|
doc.columns = cl.join(',');
|
|
doc.filters = docstring(fl);
|
|
|
|
// sort by and sort order
|
|
doc.sort_by = sel_val(this.dt.sort_sel);
|
|
doc.sort_order = this.dt.sort_order;
|
|
doc.page_len = this.dt.page_len;
|
|
|
|
// save advanced
|
|
if(this.parent_dt)
|
|
doc.parent_doc_type = this.parent_dt
|
|
|
|
// rename
|
|
var me = this;
|
|
var fn = function(r) {
|
|
me.sc_dict[criteria_name] = r.main_doc_name;
|
|
me.set_criteria_sel(criteria_name);
|
|
}
|
|
if(this.current_loaded && overwrite) {
|
|
msgprint('Filters and Columns Synchronized. You must also "Save" the Search Criteria to update');
|
|
loaddoc('Search Criteria', this.sc_dict[this.current_loaded]);
|
|
} else {
|
|
save_doclist(doc.doctype, doc.name, 'Save', fn); // server-side save
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportBuilder.prototype.hide_all_filters = function() {
|
|
for(var i=0; i<this.filter_fields.length; i++) {
|
|
this.filter_fields[i].df.filter_hide = 1;
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportBuilder.prototype.run = function() {
|
|
// Note: all client code is executed in datatable
|
|
this.dt.run();
|
|
}
|
|
|
|
// Load Criteria
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportBuilder.prototype.clear_criteria = function() {
|
|
|
|
this.column_picker.clear();
|
|
this.column_picker.set_defaults();
|
|
|
|
// clear filters
|
|
// -------------
|
|
for(var i=0; i<this.filter_fields.length; i++) {
|
|
// reset filters
|
|
this.filter_fields[i].df.filter_hide = 0;
|
|
this.filter_fields[i].df.ignore = 0;
|
|
if(this.filter_fields[i].is_custom) {
|
|
|
|
// hide+ignore customized filters
|
|
this.filter_fields[i].df.filter_hide = 1;
|
|
this.filter_fields[i].df.ignore = 1;
|
|
}
|
|
|
|
this.filter_fields[i].set_input(null);
|
|
}
|
|
|
|
this.set_sort_options();
|
|
|
|
this.set_main_title('Report: ' + get_doctype_label(this.doctype));
|
|
|
|
this.current_loaded = null;
|
|
this.customized_filters = null;
|
|
this.sc = null;
|
|
this.has_index = 1; this.has_headings = 1;
|
|
|
|
for(var i in this.fn_list) this[this.fn_list[i]] = null; // clear custom functions
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportBuilder.prototype.set_main_title = function(t, t1) {
|
|
_r.rb_con.page_head.main_head.innerHTML = t;
|
|
_r.rb_con.page_head.sub_head.innerHTML = (t1 ? t1 : '');
|
|
set_title(t);
|
|
}
|
|
|
|
_r.ReportBuilder.prototype.select_column = function(dt, label, value) {
|
|
if(value==null)value = 1;
|
|
this.column_picker.set(dt, label, value);
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportBuilder.prototype.set_filter = function(dt, label, value) {
|
|
if(this.filter_fields_dict[dt+'\1'+ label])
|
|
this.filter_fields_dict[dt+'\1'+ label].set_input(value);
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportBuilder.prototype.load_criteria = function(criteria_name) {
|
|
this.clear_criteria();
|
|
|
|
if(!this.sc_dict[criteria_name]) {
|
|
alert(criteria_name + ' could not be loaded. Please Refresh and try again');
|
|
}
|
|
this.sc = locals['Search Criteria'][this.sc_dict[criteria_name]];
|
|
|
|
// eval the custom script
|
|
var report = this;
|
|
if(this.sc && this.sc.report_script) eval(this.sc.report_script);
|
|
|
|
this.large_report = 0;
|
|
|
|
// execute the customize_filters method from Search Criteria
|
|
if(report.customize_filters) {
|
|
try {
|
|
report.customize_filters(this);
|
|
} catch(err) {
|
|
errprint('Error in "customize_filters":\n' + err);
|
|
}
|
|
}
|
|
|
|
// refresh fiters
|
|
this.report_filters.refresh();
|
|
|
|
// set fields
|
|
// ----------
|
|
this.column_picker.clear();
|
|
|
|
var cl = this.sc.columns ? this.sc.columns.split(',') : [];
|
|
for(var c=0;c<cl.length;c++) {
|
|
var key = cl[c].split('\1');
|
|
this.select_column(key[0], key[1], 1);
|
|
}
|
|
|
|
// set filters
|
|
// -----------
|
|
var fl = eval('var a='+this.sc.filters+';a');
|
|
for(var n in fl) {
|
|
if(fl[n]) {
|
|
var key = n.split('\1');
|
|
if(key[1]=='docstatus') { /* ? */ }
|
|
this.set_filter(key[0], key[1], fl[n]);
|
|
}
|
|
}
|
|
|
|
// refresh column picker
|
|
this.set_criteria_sel(criteria_name);
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
// this method must be called after resetting the Search Criteria (or clearing)
|
|
// to set Data table properties
|
|
|
|
_r.ReportBuilder.prototype.set_criteria_sel = function(criteria_name) {
|
|
|
|
// add additional columns
|
|
var sc = locals['Search Criteria'][this.sc_dict[criteria_name]];
|
|
if(sc && sc.add_col)
|
|
var acl = sc.add_col.split('\n');
|
|
else
|
|
var acl = [];
|
|
var new_sl = [];
|
|
|
|
// update the label in datatable where the column name is specified in the query using AS
|
|
for(var i=0; i<acl.length; i++) {
|
|
var tmp = acl[i].split(' AS ');
|
|
if(tmp[1]) {
|
|
var t = eval(tmp[1]);
|
|
new_sl[new_sl.length] = [t, "`"+t+"`"];
|
|
}
|
|
}
|
|
|
|
// set sort
|
|
this.set_sort_options(new_sl);
|
|
if(sc && sc.sort_by) {
|
|
this.dt.sort_sel.value = sc.sort_by;
|
|
}
|
|
if(sc && sc.sort_order) {
|
|
sc.sort_order=='ASC' ? this.dt.set_asc() : this.dt.set_desc();
|
|
}
|
|
if(sc && sc.page_len) {
|
|
this.dt.page_len_sel.inp.value = sc.page_len;
|
|
}
|
|
|
|
this.current_loaded = criteria_name;
|
|
// load additional fields sort option
|
|
this.set_main_title(criteria_name, sc.description);
|
|
}
|
|
|
|
//
|
|
// Create the filter UI and column selection UI
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportBuilder.prototype.setup_filters_and_cols = function() {
|
|
|
|
// function checks where there is submit permission on the DocType or if the DocType
|
|
// can be trashed
|
|
function can_dt_be_submitted(dt) {
|
|
if(locals.DocType && locals.DocType[dt] && locals.DocType[dt].allow_trash) return 1;
|
|
var plist = getchildren('DocPerm', dt, 'permissions', 'DocType');
|
|
for(var pidx in plist) {
|
|
if(plist[pidx].submit) return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
var me = this;
|
|
var dt = me.parent_dt?me.parent_dt:me.doctype;
|
|
|
|
// default filters
|
|
var fl = [
|
|
{'fieldtype':'Data', 'label':'ID', 'fieldname':'name', 'in_filter':1, 'parent':dt},
|
|
{'fieldtype':'Data', 'label':'Owner', 'fieldname':'owner', 'in_filter':1, 'parent':dt},
|
|
{'fieldtype':'Date', 'label':'Created on', 'fieldname':'creation', 'in_filter':0, 'parent':dt},
|
|
{'fieldtype':'Date', 'label':'Last modified on', 'fieldname':'modified', 'in_filter':0, 'parent':dt},
|
|
];
|
|
|
|
// can this be submitted?
|
|
if(can_dt_be_submitted(dt)) {
|
|
fl[fl.length] = {'fieldtype':'Check', 'label':'Saved', 'fieldname':'docstatus', 'search_index':1, 'in_filter':1, 'def_filter':1, 'parent':dt};
|
|
fl[fl.length] = {'fieldtype':'Check', 'label':'Submitted', 'fieldname':'docstatus', 'search_index':1, 'in_filter':1, 'def_filter':1, 'parent':dt};
|
|
fl[fl.length] = {'fieldtype':'Check', 'label':'Cancelled', 'fieldname':'docstatus', 'search_index':1, 'in_filter':1, 'parent':dt};
|
|
}
|
|
|
|
// make the datatable
|
|
me.make_datatable();
|
|
|
|
// Add columns and filters of parent doctype
|
|
me.orig_sort_list = [];
|
|
if(me.parent_dt) {
|
|
me.setup_dt_filters_and_cols(fl, me.parent_dt);
|
|
var fl = [];
|
|
}
|
|
|
|
// Add columns and filters of selected doctype
|
|
me.setup_dt_filters_and_cols(fl, me.doctype);
|
|
|
|
// hide primary filters blue box if there are no primary filters
|
|
if(!this.has_primary_filters)
|
|
$dh(this.report_filters.first_page_filter);
|
|
|
|
this.column_picker.refresh();
|
|
|
|
// show body
|
|
$ds(me.body);
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportBuilder.prototype.add_filter = function(f) {
|
|
if(this.filter_fields_dict[f.parent + '\1' + f.label]) {
|
|
// exists
|
|
this.filter_fields_dict[f.parent + '\1' + f.label].df = f; // reset properties
|
|
} else {
|
|
this.report_filters.add_field(f, f.parent, null, 1);
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
// this is where the filters and columns are created for a particular doctype
|
|
|
|
_r.ReportBuilder.prototype.setup_dt_filters_and_cols = function(fl, dt) {
|
|
var me = this;
|
|
|
|
// set section headings
|
|
var lab = $a(me.filter_area,'div','filter_dt_head');
|
|
lab.innerHTML = 'Filters for ' + get_doctype_label(dt);
|
|
|
|
var lab = $a(me.picker_area,'div','builder_dt_head');
|
|
lab.innerHTML = 'Select columns for ' + get_doctype_label(dt);
|
|
|
|
// get fields
|
|
var dt_fields = fields_list[dt];
|
|
for(var i=0;i<dt_fields.length;i++) {
|
|
fl[fl.length] = dt_fields[i];
|
|
}
|
|
|
|
// get "high priority" search fields
|
|
// if the field is in search_field then it should be primary filter (i.e. on first page)
|
|
|
|
var sf_list = locals.DocType[dt].search_fields ? locals.DocType[dt].search_fields.split(',') : [];
|
|
for(var i in sf_list) sf_list[i] = strip(sf_list[i]);
|
|
|
|
// make fields
|
|
for(var i=0;i<fl.length;i++) {
|
|
|
|
var f=fl[i];
|
|
|
|
// add to filter
|
|
if(f && cint(f.in_filter)) {
|
|
me.report_filters.add_field(f, dt, in_list(sf_list, f.fieldname));
|
|
}
|
|
|
|
// add to column selector (builder)
|
|
if(f && !in_list(no_value_fields, f.fieldtype) && f.fieldname != 'docstatus' && (!f.report_hide)) {
|
|
me.column_picker.add_field(f);
|
|
}
|
|
}
|
|
me.set_sort_options();
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportBuilder.prototype.set_sort_options = function(l) {
|
|
var sl = this.orig_sort_list;
|
|
|
|
empty_select(this.dt.sort_sel);
|
|
|
|
if(l) sl = add_lists(l, this.orig_sort_list);
|
|
|
|
// no sorts, add one
|
|
if(!l.length) {
|
|
l.push(['ID', 'name'])
|
|
}
|
|
|
|
for(var i=0; i<sl.length; i++) {
|
|
this.dt.add_sort_option(sl[i][0], sl[i][1]);
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportBuilder.prototype.validate_permissions = function(onload) {
|
|
this.perm = get_perm(this.parent_dt ? this.parent_dt : this.doctype);
|
|
if(!this.perm[0][READ]) {
|
|
this.forbidden = 1;
|
|
if(user=='Guest') {
|
|
msgprint('You must log in to view this page');
|
|
} else {
|
|
msgprint('No Read Permission');
|
|
}
|
|
nav_obj.show_last_open();
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportBuilder.prototype.setup_doctype = function(onload) {
|
|
// load doctype
|
|
var me = this;
|
|
|
|
if(!locals['DocType'][this.doctype]) {
|
|
this.load_doctype_from_server(onload);
|
|
} else {
|
|
// find parent dt if required
|
|
for(var key in locals.DocField) {
|
|
var f = locals.DocField[key];
|
|
if(f.fieldtype=='Table' && f.options==this.doctype)
|
|
this.parent_dt = f.parent;
|
|
}
|
|
if(!me.validate_permissions())
|
|
return;
|
|
me.validate_permissions();
|
|
me.make_body();
|
|
me.setup_filters_and_cols();
|
|
if(onload)onload(me);
|
|
}
|
|
}
|
|
|
|
_r.ReportBuilder.prototype.load_doctype_from_server = function(onload) {
|
|
var me = this;
|
|
$c('webnotes.widgets.form.getdoctype', args = {'doctype': this.doctype, 'with_parent':1 },
|
|
function(r,rt) {
|
|
if(r.parent_dt)me.parent_dt = r.parent_dt;
|
|
if(!me.validate_permissions())
|
|
return;
|
|
me.make_body();
|
|
me.setup_filters_and_cols();
|
|
if(onload)onload(me);
|
|
}
|
|
);
|
|
}
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportBuilder.prototype.reset_report = function() {
|
|
this.clear_criteria();
|
|
|
|
// show column picker if find
|
|
this.mytabs.items['Select Columns'].show();
|
|
this.mytabs.items['More Filters'].show();
|
|
|
|
this.report_filters.refresh();
|
|
this.column_picker.refresh();
|
|
|
|
var dt = this.parent_dt?this.parent_dt: this.doctype;
|
|
this.set_filter(dt, 'Saved', 1);
|
|
this.set_filter(dt, 'Submitted', 1);
|
|
this.set_filter(dt, 'Cancelled', 0);
|
|
|
|
this.column_picker.set_defaults();
|
|
|
|
this.dt.clear_all();
|
|
|
|
this.dt.sort_sel.value = 'ID';
|
|
this.dt.page_len_sel.inp.value = '50';
|
|
this.dt.set_no_limit(0);
|
|
this.dt.set_desc();
|
|
}
|
|
|
|
//
|
|
// Make the SQL query
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
|
|
_r.ReportBuilder.prototype.make_datatable = function() {
|
|
var me = this;
|
|
|
|
this.dt_area = $a(this.mytabs.items['Result'].body, 'div');
|
|
|
|
var clear_area = $a(this.mytabs.items['Result'].body, 'div');
|
|
clear_area.style.marginTop = '8px';
|
|
clear_area.style.textAlign = 'right';
|
|
|
|
this.clear_btn = $a($a(clear_area, 'span'), 'button');
|
|
this.clear_btn.innerHTML = 'Clear Settings';
|
|
this.clear_btn.onclick = function() {
|
|
me.reset_report();
|
|
}
|
|
|
|
var d = $a(clear_area, 'span', '', {marginLeft:'16px'});
|
|
d.innerHTML = '<span>Show Query: </span>';
|
|
this.show_query = $a_input(d, 'checkbox');
|
|
this.show_query.checked = false;
|
|
|
|
|
|
this.dt = new _r.DataTable(this.dt_area, '');
|
|
this.dt.finder = this;
|
|
this.dt.make_query = function() {
|
|
// attach report script functions
|
|
var report = me;
|
|
|
|
// get search criteria
|
|
if(me.current_loaded && me.sc_dict[me.current_loaded]) {
|
|
var sc = get_local('Search Criteria', me.sc_dict[me.current_loaded]);
|
|
}
|
|
|
|
if(sc) me.dt.search_criteria = sc;
|
|
else me.dt.search_criteria = null;
|
|
|
|
// reset no_limit
|
|
//me.dt.set_no_limit(0);
|
|
|
|
//load server script
|
|
if(sc && sc.server_script) me.dt.server_script = sc.server_script;
|
|
else me.dt.server_script = null;
|
|
|
|
// load client scripts - attach all functions from ReportBuilder to Datatable
|
|
// this is a bad way of doing things but since DataTable is a stable object
|
|
// currently this is okay.... to change in future
|
|
|
|
for(var i=0;i<me.fn_list.length;i++) {
|
|
if(me[me.fn_list[i]]) me.dt[me.fn_list[i]] = me[me.fn_list[i]];
|
|
else me.dt[me.fn_list[i]] = null;
|
|
}
|
|
|
|
var fl = []; // field list
|
|
var docstatus_cl = [];
|
|
var cl = []; // cond list
|
|
|
|
// format table name
|
|
var table_name = function(t) { return '`tab' + t + '`'; }
|
|
|
|
// advanced - make list of diabled filters
|
|
var dis_filters_list = [];
|
|
if(sc && sc.dis_filters)
|
|
var dis_filters_list = sc.dis_filters.split('\n');
|
|
|
|
// make a list of selected columns from ColumnPicker in tableName.fieldName format
|
|
var t = me.column_picker.get_selected();
|
|
for(var i=0;i<t.length;i++) {
|
|
fl.push(table_name(t[i].parent) + '.`'+t[i].fieldname+'` AS `'+t[i].parent +'.'+ t[i].fieldname+'`');
|
|
}
|
|
me.selected_fields = fl;
|
|
|
|
// advanced - additional fields
|
|
if(sc && sc.add_col) {
|
|
var adv_fl = sc.add_col.split('\n');
|
|
for(var i=0;i<adv_fl.length;i++) {
|
|
fl[fl.length] = adv_fl[i];
|
|
}
|
|
}
|
|
|
|
// build dictionary for filter values for server side
|
|
me.dt.filter_vals = {}
|
|
add_to_filter = function(k,v,is_select) {
|
|
if(v==null)v='';
|
|
if(!in_list(keys(me.dt.filter_vals), k)) {
|
|
me.dt.filter_vals[k] = v;
|
|
} else {
|
|
if(is_select)
|
|
me.dt.filter_vals[k] += '\n' + v;
|
|
else
|
|
me.dt.filter_vals[k+'1'] = v; // for date, numeric (from-to)
|
|
}
|
|
}
|
|
|
|
// loop over the fields and construct the SQL query
|
|
// ------------------------------------------------
|
|
for(var i=0;i<me.filter_fields.length;i++) {
|
|
var t = me.filter_fields[i];
|
|
|
|
// add to "filter_values"
|
|
var v = t.get_value?t.get_value():'';
|
|
if(t.df.fieldtype=='Select') {
|
|
if(t.input.multiple) {
|
|
for(var sel_i=0;sel_i < v.length; sel_i++) {
|
|
add_to_filter(t.df.fieldname, v[sel_i], 1);
|
|
}
|
|
// no values? atleast add key
|
|
if(!v.length) add_to_filter(t.df.fieldname, "", 1);
|
|
} else {
|
|
add_to_filter(t.df.fieldname, v);
|
|
}
|
|
} else add_to_filter(t.df.fieldname, v);
|
|
|
|
// if filter is not disabled
|
|
if(!in_list(dis_filters_list, t.df.fieldname) && !t.df.ignore) {
|
|
if(t.df.fieldname=='docstatus') {
|
|
|
|
// work around for docstatus
|
|
// -------------------------
|
|
|
|
if(t.df.label=='Saved'){
|
|
if(t.get_value()) docstatus_cl[docstatus_cl.length] = table_name(t.df.parent)+'.docstatus=0';
|
|
else cl[cl.length] = table_name(t.df.parent)+'.docstatus!=0';
|
|
}
|
|
else if(t.df.label=='Submitted'){
|
|
if(t.get_value()) docstatus_cl[docstatus_cl.length] = table_name(t.df.parent)+'.docstatus=1';
|
|
else cl[cl.length] = table_name(t.df.parent)+'.docstatus!=1';
|
|
}
|
|
else if(t.df.label=='Cancelled'){
|
|
if(t.get_value()) docstatus_cl[docstatus_cl.length] = table_name(t.df.parent)+'.docstatus=2';
|
|
else cl[cl.length] = table_name(t.df.parent)+'.docstatus!=2';
|
|
}
|
|
} else {
|
|
|
|
// normal
|
|
// -------
|
|
var fn = '`' + t.df.fieldname + '`';
|
|
var v = t.get_value?t.get_value():'';
|
|
if(v) {
|
|
if(in_list(['Data','Link','Small Text','Text'],t.df.fieldtype)) {
|
|
cl[cl.length] = table_name(t.df.parent) + '.' + fn + ' LIKE "' + v + '%"';
|
|
|
|
} else if(t.df.fieldtype=='Select') {
|
|
if(t.input.multiple) {
|
|
// loop for multiple select
|
|
var tmp_cl = [];
|
|
for(var sel_i=0;sel_i < v.length; sel_i++) {
|
|
if(v[sel_i]) {
|
|
tmp_cl[tmp_cl.length] = table_name(t.df.parent) + '.' + fn + ' = "' + v[sel_i] + '"';
|
|
}
|
|
}
|
|
|
|
// join multiple select conditions by OR
|
|
if(tmp_cl.length)cl[cl.length] = '(' + tmp_cl.join(' OR ') + ')';
|
|
} else {
|
|
cl[cl.length] = table_name(t.df.parent) + '.' + fn + ' = "' + v + '"';
|
|
}
|
|
} else {
|
|
var condition = '=';
|
|
if(t.sql_condition) condition = t.sql_condition;
|
|
cl[cl.length] = table_name(t.df.parent) + '.' + fn + condition + '"' + v + '"';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// standard filters
|
|
me.dt.filter_vals.user = user;
|
|
me.dt.filter_vals.user_email = user_email;
|
|
me.filter_vals = me.dt.filter_vals; // in both dt and report
|
|
|
|
// overloaded query - finish it here
|
|
this.is_simple = 0;
|
|
if(sc && sc.custom_query) {
|
|
this.query = repl(sc.custom_query, me.dt.filter_vals);
|
|
this.is_simple = 1;
|
|
return
|
|
}
|
|
|
|
if(me.get_query) {
|
|
// custom query method
|
|
this.query = me.get_query();
|
|
this.is_simple = 1;
|
|
} else {
|
|
// add docstatus conditions
|
|
if(docstatus_cl.length)
|
|
cl[cl.length] = '('+docstatus_cl.join(' OR ')+')';
|
|
|
|
// advanced - additional conditions
|
|
if(sc && sc.add_cond) {
|
|
var adv_cl = sc.add_cond.split('\n');
|
|
for(var i=0;i< adv_cl.length;i++) {
|
|
cl[cl.length] = adv_cl[i];
|
|
}
|
|
}
|
|
|
|
// atleast one field
|
|
if(!fl.length) {
|
|
alert('You must select atleast one column to view');
|
|
this.query = '';
|
|
return;
|
|
}
|
|
|
|
// join with parent in case of child
|
|
var tn = table_name(me.doctype);
|
|
if(me.parent_dt) {
|
|
tn = tn + ',' + table_name(me.parent_dt);
|
|
cl[cl.length] = table_name(me.doctype) + '.`parent` = ' + table_name(me.parent_dt) + '.`name`';
|
|
}
|
|
|
|
// advanced - additional tables
|
|
if(sc && sc.add_tab) {
|
|
var adv_tl = sc.add_tab.split('\n');
|
|
tn = tn + ',' + adv_tl.join(',');
|
|
}
|
|
|
|
// make the query
|
|
if(!cl.length)
|
|
this.query = 'SELECT ' + fl.join(',\n') + ' FROM ' + tn
|
|
else
|
|
this.query = 'SELECT ' + fl.join(',') + ' FROM ' + tn + ' WHERE ' + cl.join('\n AND ');
|
|
|
|
// advanced - group by
|
|
if(sc && sc.group_by) {
|
|
this.query += ' GROUP BY ' + sc.group_by;
|
|
}
|
|
|
|
// replace - in custom query if %(key)s is specified, then replace it by filter values
|
|
this.query = repl(this.query, me.dt.filter_vals)
|
|
}
|
|
|
|
if(me.show_query.checked) {
|
|
this.show_query = 1;
|
|
}
|
|
|
|
// report name - used as filename in export
|
|
if(me.current_loaded) this.rep_name = me.current_loaded;
|
|
else this.rep_name = me.doctype;
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportBuilder.prototype.get_filter = function(dt, label) {
|
|
return this.filter_fields_dict[dt + FILTER_SEP + label];
|
|
}
|
|
|
|
_r.ReportBuilder.prototype.set_filter_properties = function(dt, label, properties) {
|
|
var f = this.filter_fields_dict[dt + FILTER_SEP + label];
|
|
for(key in properties) {
|
|
f.df[key]=properties[key];
|
|
}
|
|
}
|
|
|
|
// Report Filter
|
|
// ===================================================================================
|
|
|
|
_r.ReportFilters = function(rb) {
|
|
this.rb = rb;
|
|
|
|
// filters broken into - primary - in searchfields and others
|
|
this.first_page_filter = $a(rb.mytabs.items['Result'].body, 'div', 'finder_filter_area');
|
|
this.filter_area = $a(rb.mytabs.items['More Filters'].body, 'div', 'finder_filter_area');
|
|
|
|
// filter fields area
|
|
this.filter_fields_area = $a(this.filter_area,'div');
|
|
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportFilters.prototype.refresh = function() {
|
|
// called after customization
|
|
var fl = this.rb.filter_fields
|
|
|
|
for(var i=0; i<fl.length; i++) {
|
|
var f = fl[i];
|
|
|
|
// is hidden ?
|
|
if(f.df.filter_hide) {
|
|
$dh(f.wrapper);
|
|
} else {
|
|
$ds(f.wrapper);
|
|
}
|
|
|
|
// is bold?
|
|
if(f.df.bold) {
|
|
if(f.label_cell)
|
|
$y(f.label_cell, {fontWeight:'bold'})
|
|
} else {
|
|
if(f.label_cell) $y(f.label_cell, {fontWeight:'normal'})
|
|
}
|
|
|
|
// set default value
|
|
if(f.df['report_default'])
|
|
f.set_input(f.df['report_default']);
|
|
|
|
// show in first page?
|
|
if(f.df.in_first_page && f.df.filter_cell) {
|
|
f.df.filter_cell.parentNode.removeChild(f.df.filter_cell);
|
|
this.first_page_filter.appendChild(f.df.filter_cell);
|
|
this.rb.has_primary_filters = 1;
|
|
$ds(this.first_page_filter);
|
|
}
|
|
|
|
// clear / hide all custom added filters
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportFilters.prototype.add_date_field = function(cell, f, dt, is_custom) {
|
|
var my_div = $a(cell,'div','',{});
|
|
|
|
// from date
|
|
var f1 = copy_dict(f);
|
|
f1.label = 'From ' + f1.label;
|
|
var tmp1 = this.make_field_obj(f1, dt, my_div, is_custom);
|
|
tmp1.sql_condition = '>=';
|
|
tmp1.bound = 'lower';
|
|
|
|
// to date
|
|
var f2 = copy_dict(f);
|
|
f2.label = 'To ' + f2.label;
|
|
var tmp2 = this.make_field_obj(f2, dt, my_div, is_custom);
|
|
tmp2.sql_condition = '<=';
|
|
tmp2.bound = 'upper';
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportFilters.prototype.add_numeric_field = function(cell, f, dt, is_custom) {
|
|
var my_div = $a(cell,'div','',{});
|
|
|
|
// from value
|
|
var f1 = copy_dict(f);
|
|
f1.label = f1.label + ' >=';
|
|
var tmp1 = this.make_field_obj(f1, dt, my_div, is_custom);
|
|
tmp1.sql_condition = '>=';
|
|
tmp1.bound = 'lower';
|
|
|
|
// to value
|
|
var f2 = copy_dict(f);
|
|
f2.label = f2.label + ' <=';
|
|
var tmp2 = this.make_field_obj(f2, dt, my_div, is_custom);
|
|
tmp2.sql_condition = '<=';
|
|
tmp2.bound = 'upper';
|
|
}
|
|
|
|
// make a field object
|
|
_r.ReportFilters.prototype.make_field_obj = function(f, dt, parent, is_custom) {
|
|
var tmp = make_field(f, dt, parent, this.rb, false);
|
|
tmp.not_in_form = 1;
|
|
tmp.in_filter = 1;
|
|
tmp.refresh();
|
|
this.rb.filter_fields[this.rb.filter_fields.length] = tmp;
|
|
this.rb.filter_fields_dict[f.parent + '\1' + f.label] = tmp;
|
|
if(is_custom) tmp.is_custom = 1;
|
|
return tmp;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportFilters.prototype.add_field = function(f, dt, in_primary, is_custom) {
|
|
var me = this;
|
|
|
|
// insert in (parent element)
|
|
if(f.in_first_page) in_primary = true;
|
|
|
|
var fparent = this.filter_fields_area;
|
|
if(in_primary) {
|
|
fparent = this.first_page_filter;
|
|
this.rb.has_primary_filters = 1;
|
|
}
|
|
|
|
// label
|
|
// --- ability to insert
|
|
if(f.on_top) {
|
|
var cell = document.createElement('div');
|
|
fparent.insertBefore(cell, fparent.firstChild);
|
|
$y(cell,{width:'70%'});
|
|
|
|
} else if(f.insert_before) {
|
|
var cell = document.createElement('div');
|
|
fparent.insertBefore(cell, fparent[f.df.insert_before].filter_cell);
|
|
$y(cell,{width:'70%'});
|
|
}
|
|
|
|
else
|
|
var cell = $a(fparent, 'div', '', {width:'70%'});
|
|
|
|
f.filter_cell = cell;
|
|
|
|
// make field
|
|
if(f.fieldtype=='Date') {
|
|
// date field
|
|
this.add_date_field(cell, f, dt);
|
|
} else if(in_list(['Currency', 'Int', 'Float'], f.fieldtype)) {
|
|
// numeric
|
|
this.add_numeric_field(cell, f, dt);
|
|
} else if (!in_list(['Section Break', 'Column Break', 'Read Only', 'HTML', 'Table', 'Image', 'Button'], f.fieldtype)) {
|
|
var tmp = this.make_field_obj(f, dt, cell, is_custom);
|
|
}
|
|
|
|
// add to datatable sort
|
|
if(f.fieldname != 'docstatus')
|
|
me.rb.orig_sort_list.push([f.label, '`tab' + f.parent + '`.`' + f.fieldname + '`']);
|
|
|
|
// check saved
|
|
if(f.def_filter)
|
|
tmp.input.checked = true;
|
|
}
|
|
|
|
|
|
|
|
// Column Picker
|
|
// ===================================================================================
|
|
|
|
_r.ReportColumnPicker = function(rb) {
|
|
this.rb = rb;
|
|
this.picker_area = $a(this.rb.mytabs.items['Select Columns'].body, 'div', 'finder_picker_area');
|
|
|
|
this.all_fields = [];
|
|
this.sel_idx = 0;
|
|
|
|
this.make_body();
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportColumnPicker.prototype.make_body = function() {
|
|
|
|
var t = make_table(this.picker_area, 1, 3, '100%', ['35%','30%','35%'], {verticalAlign:'middle', textAlign:'center'});
|
|
|
|
// all fields
|
|
$a($td(t,0,0), 'h3', '', {marginBottom:'8px'}).innerHTML = 'Columns';
|
|
this.unsel_fields = $a($td(t,0,0), 'select', '', {height:'200px', width:'100%', border:'1px solid #AAA'});
|
|
this.unsel_fields.multiple = true;
|
|
this.unsel_fields.onchange = function() { for(var i=0; i<this.options.length; i++) this.options[i].field.is_selected = this.options[i].selected; }
|
|
|
|
// buttons
|
|
var me = this;
|
|
this.up_btn = $a($a($td(t,0,1), 'div'), 'button', '', {width:'70px'});
|
|
this.up_btn.innerHTML = 'Up ↑';
|
|
this.up_btn.onclick = function() { me.move_up(); }
|
|
|
|
this.add_all = $a($a($td(t,0,1), 'div'), 'button', '', {width:'40px'});
|
|
this.add_all.innerHTML = '>>';
|
|
this.add_all.onclick = function() { me.move(me.unsel_fields, 'add', 1); }
|
|
|
|
this.add_btn = $a($a($td(t,0,1), 'div'), 'button', '', {width:'110px'});
|
|
this.add_btn.innerHTML = '<b>Add ></b>';
|
|
this.add_btn.onclick = function() { me.move(me.unsel_fields, 'add'); }
|
|
|
|
this.remove_btn = $a($a($td(t,0,1), 'div'), 'button', '', {width:'110px'});
|
|
this.remove_btn.innerHTML = '<b>< Remove</b>';
|
|
this.remove_btn.onclick = function() { me.move(me.sel_fields, 'remove'); }
|
|
|
|
this.remove_all = $a($a($td(t,0,1), 'div'), 'button', '', {width:'40px'});
|
|
this.remove_all.innerHTML = '<<';
|
|
this.remove_all.onclick = function() { me.move(me.sel_fields, 'remove', 1); }
|
|
|
|
this.dn_btn = $a($a($td(t,0,1), 'div'), 'button', '', {width:'70px'});
|
|
this.dn_btn.innerHTML = 'Down ↓';
|
|
this.dn_btn.onclick = function() { me.move_down(); }
|
|
|
|
// multiple fields
|
|
$a($td(t,0,2), 'h3', '', {marginBottom:'8px'}).innerHTML = 'Selected Columns';
|
|
this.sel_fields = $a($td(t,0,2), 'select', '', {height:'200px', width:'100%', border:'1px solid #AAA'});
|
|
this.sel_fields.multiple = true;
|
|
this.sel_fields.onchange = function() { for(var i=0; i<this.options.length; i++) this.options[i].field.is_selected = this.options[i].selected; }
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportColumnPicker.prototype.get_by_sel_idx = function(s, idx) {
|
|
for(var j=0;j<s.options.length; j++) {
|
|
if(s.options[j].field.sel_idx == idx)
|
|
return s.options[j].field;
|
|
}
|
|
return {} // nothing
|
|
}
|
|
|
|
_r.ReportColumnPicker.prototype.move_up = function() {
|
|
var s = this.sel_fields;
|
|
for(var i=1;i<s.options.length; i++ ) {
|
|
if(s.options[i].selected) {
|
|
s.options[i].field.sel_idx--;
|
|
this.get_by_sel_idx(s, i-1).sel_idx++;
|
|
}
|
|
}
|
|
this.refresh();
|
|
}
|
|
|
|
_r.ReportColumnPicker.prototype.move_down = function() {
|
|
var s = this.sel_fields;
|
|
|
|
if(s.options.length<=1) return;
|
|
|
|
for(var i=s.options.length-2;i>=0; i-- ) {
|
|
if(s.options[i].selected) {
|
|
this.get_by_sel_idx(s, i+1).sel_idx--;
|
|
s.options[i].field.sel_idx++;
|
|
}
|
|
}
|
|
this.refresh();
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportColumnPicker.prototype.move = function(s, type, all) {
|
|
for(var i=0;i<s.options.length; i++ ) {
|
|
if(s.options[i].selected || all) {
|
|
if(type=='add') {
|
|
s.options[i].field.selected = 1;
|
|
s.options[i].field.sel_idx = this.sel_idx;
|
|
this.sel_idx++;
|
|
} else {
|
|
s.options[i].field.selected = 0;
|
|
s.options[i].field.sel_idx = 0;
|
|
this.sel_idx--;
|
|
}
|
|
}
|
|
}
|
|
this.refresh();
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportColumnPicker.prototype.refresh = function() {
|
|
// separate
|
|
var ul = []; var sl=[];
|
|
for(var i=0; i<this.all_fields.length; i++) {
|
|
var o = this.all_fields[i];
|
|
if(o.selected) {
|
|
sl.push(o);
|
|
// enable sort option
|
|
if(this.rb.dt) this.rb.dt.set_sort_option_disabled(o.df.label, 0);
|
|
} else {
|
|
ul.push(o);
|
|
// disable sort option
|
|
if(this.rb.dt) this.rb.dt.set_sort_option_disabled(o.df.label, 1);
|
|
}
|
|
}
|
|
|
|
|
|
// sort by field idx
|
|
ul.sort(function(a,b){return (cint(a.df.idx)-cint(b.df.idx))});
|
|
|
|
// sort by order in which they were selected
|
|
sl.sort(function(a,b){return (cint(a.sel_idx)-cint(b.sel_idx))})
|
|
|
|
// re-number selected
|
|
for(var i=0; i<sl.length; i++) { sl[i].sel_idx = i; }
|
|
|
|
// add options
|
|
this.set_options(this.unsel_fields, ul);
|
|
this.set_options(this.sel_fields, sl);
|
|
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportColumnPicker.prototype.set_options = function(s, l) {
|
|
empty_select(s);
|
|
|
|
for(var i=0; i<l.length; i++) {
|
|
var v = l[i].df.parent + '.' + l[i].df.label;
|
|
var v_label = get_doctype_label(l[i].df.parent) + '.' + l[i].df.label;
|
|
var o = new Option (v_label, v, false, false);
|
|
o.field = l[i];
|
|
if(o.field.is_selected) o.selected = 1;
|
|
s.options[s.options.length] = o;
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportColumnPicker.prototype.clear = function() {
|
|
this.sel_idx = 0;
|
|
for(var i=0; i<this.all_fields.length; i++) {
|
|
this.all_fields[i].selected = 0;
|
|
}
|
|
this.refresh();
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportColumnPicker.prototype.get_selected = function() {
|
|
var sl = [];
|
|
for(var i=0; i<this.all_fields.length; i++) {
|
|
var o = this.all_fields[i];
|
|
if(o.selected) {
|
|
sl[sl.length] = o.df;
|
|
o.df.sel_idx = o.sel_idx;
|
|
}
|
|
}
|
|
return sl.sort(function(a,b){return (cint(a.sel_idx)-cint(b.sel_idx))});
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportColumnPicker.prototype.set_defaults = function() {
|
|
for(var i=0; i<this.all_fields.length; i++) {
|
|
if(this.all_fields[i].selected_by_default)
|
|
this.all_fields[i].selected = 1;
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportColumnPicker.prototype.add_field = function(f) {
|
|
// column picker
|
|
if(!f.label) return;
|
|
|
|
var by_default = (f.in_filter) ? 1 : 0;
|
|
|
|
this.all_fields.push({
|
|
selected:by_default
|
|
,df:f
|
|
,sel_idx: (by_default ? this.sel_idx : 0)
|
|
,selected_by_default : by_default
|
|
});
|
|
|
|
this.sel_idx += by_default;
|
|
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
_r.ReportColumnPicker.prototype.set = function(dt, label, selected) {
|
|
for(var i=0; i<this.all_fields.length; i++) {
|
|
if(this.all_fields[i].df.parent == dt && this.all_fields[i].df.label==label) {
|
|
this.all_fields[i].selected = selected;
|
|
this.all_fields[i].sel_idx = this.sel_idx;
|
|
this.sel_idx += cint(selected);
|
|
this.refresh();
|
|
return;
|
|
}
|
|
}
|
|
}
|