📄 smart_grid_lib.js
字号:
/*==============================================================================
Smart Grid 1.3
==============
Copyright (c) 2007 Vyacheslav Smolin
Author:
-------
Vyacheslav Smolin (http://www.richarea.com, http://html2xhtml.richarea.com,
re@richarea.com)
About the script:
-----------------
Smart Grid is 100% JavaScript Ajax-based table editing tool. Powered with
Smart Cells - Ajax-based library that allow to make any part or your page
editable.
Requirements:
-------------
Smart Cells works in IE, Mozilla-based browsers such as Firefox, Opera 9+,
and Safari 3.0.
Usage:
------
Please see example.html.
Demo:
-----
http://www.richarea.com/demo/smart_grid/
License:
--------
Free for non-commercial using. Copyright information must stay intact.
Please contact author for permission to use it in commercial projects.
==============================================================================*/
// smart grid object
function SmartGrid(obj) {
// parent object of the grid
if (typeof(obj) == 'object') {
this.obj = obj;
} else {
this.obj = document.getElementById(obj);
}
// columns info (header names, cells that the columns are based on, etc)
this.columns = new Array();
// initial grid data
this.data = new Array();
// id of the last clicked row
this.last_clicked_row_id = null;
// ids of the selected rows
this.selected_rows = new Array();
// on save cell handler
// this.on_save_cell = null;
// paging mode
this.page_mode = false;
// current page
this.current_page = 0;
// page size, 0 - no paging
this.page_size = 0;
// page sizes
this.page_sizes = new Array(0, 1, 2, 3, 5, 10, 20, 50, 100);
// actual number of rows in page
this.real_page_size = 0;
// total number of pages
this.total_pages = 1;
// url to read data from
this.data_url = '';
// dynamic loading mode (grid loads and renders data that are visible only)
// invisible smart cells are converted to common cells
this.dynamic_loading = false;
// max number of rows loaded first time when number of rows in visible area
// could not be determined
this.dynamic_loading_size = 3;
// row cache
this.rows = new Array();
// timer to initiate loading rows that became visible after scrolling
this.dl_timer = null;
// flag to prevent addition the same rows twice from different data sets
this.dl_adding_rows = false;
// number of columns to be freezed
this.frozen_col_num = 0;
this.frozen_grid = null; // grid with frozen columns if any
// actions
this.show_actions = false;
// url to send add/update/delete queries to
this.actions_url = '';
// permissions to do the actions
this.add_allowed = true;
this.update_allowed = true;
this.delete_allowed = true;
this.language = 'en';
// use default langauge if lang data not found for the language specified
this.default_language = 'en';
// header's border draggable area width (used to drag cells' borders)
this.header_drag_width = 10;
// true when resizing a column
this.resize_mode = false;
// path to grid images
this.image_path = 'img/';
// row height (used if could not determine - happens eg in IE when
// page is not loaded completely)
this.row_height = 20;
// index of the last sorted column
this.last_sorted = null;
this.obj.className = 'sg_main_div';
// this.obj.style.position = "relative"; //!!!!
this.obj.onselectstart = function(){return false;};
// create main table
this.main_table = document.createElement('TABLE');
this.main_table.border = 0;
this.main_table.cellSpacing = 0;
this.main_table.cellPadding = 0;
this.main_table.width = "100%";
this.main_table.style.tableLayout = "fixed";
this.main_table.className = "sg_main_table";
// this.main_table.style.position = "relative"; //!!!!
var main_header_cell = this.main_table.insertRow(0).insertCell(0);
var main_content_cell = this.main_table.insertRow(1).insertCell(0);
// header div
this.header_div = document.createElement("DIV");
this.header_div.style.width = "100%";
// this.header_div.style.height = '100px';
this.header_div.style.overflow = "hidden";
this.header_div.style.position = "relative";
this.header_div.className = "sg_header_div";
// header table
this.header_table = document.createElement('TABLE');
this.header_table.width = '100%';
// this.header_table.border = 1;
this.header_table.cellSpacing = 0;
this.header_table.cellPadding = 0;
this.header_table.className = "sg_header_table";
this.header_table.style.tableLayout = "fixed";
this.header_table.onmousemove = new Function("e","this.grid.header_mousemove(e||window.event)");
this.header_table.onmousedown = new Function("e","this.grid.start_header_drag(e||window.event)");
// change cursor state to see if it is inside a draggable area or not
this.header_mousemove = function(e) {
var src_obj = e.target?e.target:window.event.srcElement;
var cell_obj = get_previous_object(src_obj, 'TD');
if (!cell_obj) return;
if (this.cursor_in_drag_area(e, cell_obj)) {
cell_obj.style.cursor = 'E-resize';
} else {
cell_obj.style.cursor = 'default';
}
// Opera fix, otherwise it jumps to 0 scroll position - sucs browser ;)
this.header_div.scrollLeft = this.content_div.scrollLeft;
};
// check if cursor is inside draggable area
this.cursor_in_drag_area = function (e, cell_obj) {
var cell_pos = get_obj_pos(cell_obj);
if (cell_pos[0]+cell_obj.offsetWidth - e.clientX <=
this.header_drag_width) {
return true;
}
return false;
};
// set event parsers necessary to change column sizes
this.start_header_drag = function(e) {
this.resize_mode = false;
var src_obj = e.target?e.target:window.event.srcElement;
var cell_obj = get_previous_object(src_obj, 'TD');
if (!cell_obj) return;
if (!this.cursor_in_drag_area(e, cell_obj)) {
return;
}
var mouse_x = e.clientX;
// alert('Start Drag!');
// this.obj.onmousemove = new Function("e","this.grid.resize_column(e||window.event, cell_obj)");
var start_x = e.clientX;
var start_col_width = parseInt(cell_obj.style.width);
//alert(start_col_width);
var start_table_width = parseInt(this.content_table.style.width);
//alert(start_table_width);
this.obj.onmousemove = function(e) {this.grid.resize_column(e||window.event, cell_obj, start_x, start_col_width, start_table_width);};
sc_attach_event(document.body, 'mouseup', this.doc_mouseup);
};
this.doc_mouseup = new Function("e","document.getElementById('" + this.obj.id + "').grid.stop_header_drag();");
// resize column
this.resize_column = function(e, cell_obj, mouse_x, col_width, table_width) {
this.resize_mode = true;
var incr = e.clientX - mouse_x;
var new_width = Math.max(col_width + incr, this.header_drag_width);
var new_incr = new_width - col_width;
//var new_width = col_width+incr;
//var new_incr = incr;
//alert(cell_obj.cell_index);
//alert(this.columns[cell_obj.cell_index]['col_width']);
//if (incr != 0) alert(e.clientX + ' => ' + mouse_x + ' => ' + incr);
this.columns[cell_obj.cell_index+this.frozen_col_num]['col_width'] = new_width;
this.header_table.rows[0].cells[cell_obj.cell_index].style.width = new_width + 'px';
// this.header_table.style.width = table_width + incr + 'px';
this.content_table.style.width = table_width + new_incr + 'px';
// change width of frozen grid if this is such a grid
// does not work in Opera (get back to this later)
if (0 && this.common_grid) {
this.frozen_div.style.width = table_width + new_incr + 'px';
this.frozen_cell.width = table_width + new_incr;
this.frozen_cell.style.width = table_width + new_incr + 'px';
}
//alert(this.content_table.style.width);
// this.header_div.scrollLeft = 0;
//alert(cell_obj.cell_index + ' => ' + mouse_x + ' => ' + col_width + ' => ' + table_width);
// set new width to column of data rows
var rows = this.get_rows();
var rows_len = rows.length;
var i;
for (i=0; i<rows_len; i++) {
var data_cell = rows[i].cells[cell_obj.cell_index];
data_cell.style.width = new_width + 'px';
}
this.header_div.scrollLeft = this.content_div.scrollLeft;
// move sort image if it is in the column resized
if (this.last_sorted != null) {
var sorted_cell_obj = cell_obj.parentNode.cells[this.last_sorted];
this.move_sort_image(sorted_cell_obj);
}
};
// exit resize column size mode
this.stop_header_drag = function() {
this.obj.onmousemove = "";
sc_detach_event(document.body, 'mouseup', this.doc_mouseup);
//alert('Stop drag!');
};
this.header_table.onclick = new Function("e","this.grid.header_click(e||window.event)");
// parse mouseclick on a header cell
this.header_click = function(e) {
if (this.resize_mode) return;
var src_obj = e.target?e.target:window.event.srcElement;
var cell_obj = get_previous_object(src_obj, 'TD');
if (!cell_obj) return;
this.sort_rows(cell_obj);
};
// image to display sorting order
this.sort_img = document.createElement('IMG');
this.sort_img.setAttribute('src', this.image_path + 'sort_desc.gif');
this.sort_img.style.display = 'none';
this.sort_img.style.position = 'absolute';
// document.body.appendChild(this.sort_img);
this.header_div.appendChild(this.sort_img);
// returns path to image corresponding to sort order sort_order
this.get_sort_img_src = function(sort_order) {
if (sort_order == 'desc') {
return this.image_path + 'sort_desc.gif';
} else {
return this.image_path + 'sort_asc.gif';
}
};
// load images in cache
var sort_asc_img = new Image();
sort_asc_img.src = this.get_sort_img_src('asc');
var sort_desc_img = new Image();
sort_desc_img.src = this.get_sort_img_src('desc');
// sort column chosen
this.sort_rows = function(cell_obj) {
// do not sort if not all rows are loaded
if (this.dynamic_loading ||
this.common_grid && this.common_grid.dynamic_loading) {
alert(this.get_text_data('dynamic_loading'));
return;
}
var i;
var cell_index = cell_obj.cell_index;
// determine sort order
if (this.last_sorted != null && this.last_sorted == cell_index &&
String(this.sort_img.getAttribute('src')).indexOf('asc') >= 0) {
var sort_order = 'desc';
} else {
var sort_order = 'asc';
}
this.sort_img.setAttribute('src', this.get_sort_img_src(sort_order));
// move sort image into the right column
this.move_sort_image(cell_obj);
// get values of column cells
var cell_values = new Array();
// rows in the order desired
var rows_sorted = new Array();
var rows = this.get_rows();
var rows_len = rows.length;
for (i=0; i<rows_len; i++) {
rows_sorted[i] = rows[i];
var cur_cell_obj = rows[i].cells[cell_index];
var sc = SmartCells.get_cell(cur_cell_obj);
cell_values[rows[i].getAttribute('id')] = sc.get_sort_value();
}
var sc_column = this.columns[cell_index+this.frozen_col_num]['cell'];
// choose compare function necessary
switch (sc_column.sort_type) {
case 'number':
var cmp_function = function(a, b) {
var a_val = Number(cell_values[a.getAttribute('id')]);
var b_val = Number(cell_values[b.getAttribute('id')]);
if (isNaN(a_val) && isNaN(b_val)) return 0;
//alert(a.getAttribute('id') + ' => ' + b.getAttribute('id') + ' | ' + a_val + ' => ' + b_val);
if (sort_order == 'asc') {
return isNaN(b_val)||a_val>b_val?1:-1;
} else {
return isNaN(a_val)||b_val>a_val?1:-1;
}
};
break;
case 'date':
var cmp_function = function(a, b) {
var a_val = Number(cell_values[a.getAttribute('id')]);
var b_val = Number(cell_values[b.getAttribute('id')]);
if (sort_order == 'asc') {
return a_val-b_val;
} else {
return b_val-a_val;
}
};
break;
case 'string':
case 'time':
var cmp_function = function(a, b) {
var a_val = cell_values[a.getAttribute('id')];
var b_val = cell_values[b.getAttribute('id')];
if (a_val == b_val) return 0;
if (sort_order == 'asc') {
//alert(cell_values[a.getAttribute('id')] + ' > ' + cell_values[b.getAttribute('id')] + ' = ' + (cell_values[a.getAttribute('id')]>cell_values[b.getAttribute('id')]?1:-1));
return a_val>b_val?1:-1;
} else {
return a_val>b_val?-1:1;
}
};
break;
default:
break;
}
rows_sorted.sort(cmp_function);
// if there are frozen rows then sort the both of the grids
if (this.frozen_grid || this.common_grid) {
if (this.frozen_grid) {
var grid = this.frozen_grid;
} else {
var grid = this.common_grid;
}
var rows2 = grid.get_rows();
// hide sorting image of this grid
grid.sort_img.style.display = 'none';
} else {
var rows2 = null;
}
for (i=0; i<rows_len; i++) {
if (rows_sorted[i].getAttribute('id') != rows[i].getAttribute('id')) {
// sort another grid if any
if (rows2) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -