/* Big Table Sorter v2.1 (+ JS Data Filter)
@require http://ir2.ru/tabsort.css 31.09.2010 */
/* Использование:
(Описание сортировщика: http://ir2.ru/javascript1-3.aspx,
описание фильтрации данных: http://ir2.ru/js_data_filter.aspx)
I Сортировщик
1) подключить (через эл-т HEAD) к странице этот скрипт и файл http://ir2.ru/tabsort.css;
2) сортируемым таблицам (тэгам TABLE) добавить class='sortable'
(можно через пробел: class='big superborder sortable');
3) в строке заголовка (при щелчке по которому происходит сортировка)
должны быть элементы TH (а не TD);
4) вводится 3 типа данных (str не вводится - он по умолчанию) для сотрировки: num|datru|daten,
их следует вписывать в ячейку заголовка как атрибут axis:
;
5) пользователь может сам определять тип сортировки:
щелчок с удержанным Shift - Number,
щелчок с удержанным Ctrl - Date (RU),
щелчок с удержанным Ctrl+Alt - Date (EN)
6) можно при сортировке добавлять к заголовкам ячеек title "Отсортировано по...",
если указать в в секции "настройки" use_title = true;
7) можно сохранять состояние сортировки для каждой таблицы (в cookie),
для этого в секции "настройки" нужно указать use_cookie = true;
8) удалить куки для данной таблицы (сбросить сохранённое состояние сортировки)
можно щелчком по заголовку с удержанными клавишами Ctrl+Alt+Shift;
9) можно использовать многострочные заголовки, если явно помещать
заголовочные строки в элемент THEAD (между тэгами );
10) при use_appendChild = false для прорисовки таблицы используется innerHTML;
11) use_zebra = true делает таблицу полосатой;
12) для визуального отображения (и изменения) настроек нужно подключить файл test_sort.js;
II Фильтры
1) для подключения модуля фильтров по значениям колонок таблицы с явно указанным типом
сортировки (axis) в секции "Настройки" назначить use_inputs = true;
2) для подключения модуля фильтров ко всем заголовкам сортируемых таблиц без разбора
в секции "Настройки" назначить use_inputs = true, inputs_force = true;
3) для удаления сообщения с количеством результатов нажать Escape;
4) для поиска в середине полей (строковый тип) добавлять перед искомой фразой пробел.
*/
/* настройки */
var def = {
/* Использование всплывающего title: */
use_title: true, /* added by Clusta */
/* Сохранение-восстановление предыдущей сортировки */
use_cookie: true,
/* Сообщать о времени работы скрипта: */
show_log: true,
/* Если true, сортированные строки рисует
tbody.appendChild, если false - innerHTML: */
use_appendChild: true,
/* "Полосатая" таблица: */
use_zebra: false,
/* Последние два параметра (use_appendChild && use_zebra) вместе
могут фатально тормозить ИЕ */
/* Использовать отбор строк (фильтры): */
use_inputs: true,
/* Использовать фильтры без axis (всегда тип String): */
inputs_force: true,
/* Стрелки направления сортировки: */
use_arrows: true,
/* эксперимент пока провалился из-за ИЕ */
paginate: true,
page_x_2: false
}
/* настройки конец */
/* константы */
var global = [] /* там будут массивы для таблиц */
var dec = (1/2).toString().replace(/\d/g, ""),
undigit = new RegExp("[^\\d\\" + dec + "]+", "g")
var ru = new RegExp("[а-яА-Я]+", "ig")
var month = {
ru: {"янв":"01", "фев":"02", "мар":"03", "апр":"04", "май":"05", "июн":"06", "июл":"07", "авг":"08", "сен":"09", "окт":"10", "ноя":"11", "дек":"12"},
func: function (str) {
// alert(str)
var m = str.substring(0, 3)
m = month.ru[m] ? month.ru[m] : "00"
// m = (p1 + m + p3)
return(m)
}
}
/* класс таблиц для сортировки: */
var sort_table_class = "sortable"
/* класс элемента-обёртки для таблиц: */
var table_container_class = "package_for_table"
/* классы "невидимости" и "условной невидимости" (должны быть в CSS): */
var invis_class = "disnone"
var vis_class = "vis"
var invis_if_class = "disnone_if"
var hide_child_class = "unvis_child" /*disnone_child*/
/* класс элемента, отображающего количество найденных строк: */
var result_class = "abstopleft"
/* данные отфильтрованы: */
var under_filter = false
/* надеемся на лучшее: */
var govnosoft_detected = false
/* числа стилей стрелок (в tabsort.css): */
var init_arrow_color = 0
/* начальный класс для стрелок: */
var arrow_unsort = "c_0_c"
var page_size = 20
/* константы конец */
addLoadEvent(prepTabs)
/******************** Big Table Sorter *******************/
function prepTabs() {
if (window.init_boxes) init_boxes() /* Визуальные настройки */
page_size = page_size * ((def.page_x_2) ? 2 : 1)
arrows()
if (def.show_log) {
var dom = 'Убрать: ESC. ', d1
window.msg = document.createElement("DIV")
msg.className = "abs0"
msg = document.body.appendChild(msg)
if (!window.d0) window.d0 = new Date()
else {
addLog("DOM: ")
}
addLog("Настройка... ", "", true)
}
if (def.paginate) {
window.p = document.createElement("DIV")
p.className = "abs1"
p = document.body.appendChild(p)
}
if (def.use_arrows) { /* шарик - метка последней сортировки */
window.bull = document.createElement("DIV")
bull.className = "bull"
bull.innerHTML = "•"
}
if (def.use_inputs) { /* отображать количество найденных строк */
window.result=document.createElement("SPAN")
result.id="num_res"
result.className = result_class
document.body.appendChild(result)
}
document.onkeyup = hideres /* прятать всплывшее */
/* Поиск таблиц и назначение onclick */
var uri = location.pathname, el, thead, task
var list = document.getElementsByTagName("TABLE");
for (var k=0; k < list.length; k++) {
el = list[k];
if (!hasClass(el, sort_table_class)) continue;
/* innerHTML для ИЕ */
try {el.lastChild.previousSibling.innerHTML += ""; }
catch(e) {govnosoft_detected = true;}
if (!def.use_appendChild && govnosoft_detected) {
el = inBox(el);
addLog("Table_inboxIE: ", k)
}
/* innerHTML для ИЕ конец */
global[k] = {};
addClass(el, "tid_" + k + "_tid");
global[k].sorted = NaN; /* для reverse */
global[k].rarr = []; /* rarr - 'row array' */
global[k].vrarr = null;
global[k].vice_versa = false;
global[k].last_line = page_size - 1;
global[k].first_line = 0;
global.last_table = el;
global.last_table_index = k;
if (def.paginate) global[k].page_num = 0;
/* обработка [многострочного] заголовка */
var first_sort_line = 0, rh = el.rows[first_sort_line];
thead = rh.parentNode;
while (rh.parentNode.tagName == "THEAD"){
first_sort_line++;
rh = el.rows[first_sort_line];
}
var tbody = findChild(el, "TBODY")
if (!first_sort_line) { /* rh.parentNode - НЕ thead! */
/* заголовком считается первая строка, сортировка со строки #1 */
first_sort_line = 1;
/* thead будет в таблице всегда */
thead = document.createElement("THEAD")
el.insertBefore(thead, tbody)
thead.appendChild(rh)
}
global[k].first_sort_line = first_sort_line;
global[k].thead = thead;
thead.onclick = clickTab;
addClass(thead, "pointer");
cellsInHeader(el, first_sort_line)
addLog("Table_arrows: ", k)
/* обработка заголовка end */
if (def.use_title) thead.title = "Сортировать"
if (def.use_cookie) {
/* восстановление предыдущей сортировки */
global[k].cookid = new Array(uri + "_tab" + k, "");
task = getCookie(global[k].cookid[0])
if (task) {
if (def.show_log) msg.innerHTML += "Восстановление... "
var taskarr, cellid, rowid, coo, obj
task=task.split(",")
for (var j=0; j-1) txt = txt.replace(/\_/, num + "_")
else txt += num.toString()
}
msg.innerHTML += txt
msg.innerHTML += (!no_upd) ? (d1 - d0) + " ms. " : ""
if (!no_upd) d0 = d1
}
function clickTab(e) {
if (def.show_log) d0 = new Date()
e = e || window.event;
prevent(e);
var data_type = false;
var obj = e.target || e.srcElement;
// obj.onselectstart = function() {return false};
if (!e.ctrlKey && e.shiftKey && !e.altKey) {data_type = "num"; deselect()}
if (e.ctrlKey && !e.shiftKey && e.altKey) data_type = "daten";
if (e.ctrlKey && !e.shiftKey && !e.altKey) data_type = "datru";
/* Если в ячейке заголовка HTML */
if ("INPUT" == obj.tagName) return;
if ("TH" != obj.tagName && "TD" != obj.tagName) {
var testobj = findParent(obj, "TH"); /* ячейка заголовка */
if (!testobj) { /* обратная совместимость (с TD в заголовке) */
testobj = findParent(obj, "TD");
if (findChild(this, "TR") != testobj.parentNode) testobj = null;
}
obj=testobj;
}
if (obj.axis == 'unsort') return
if (!obj) return;
// alert(obj.realIndex)
var table = findParent(obj, "TABLE", sort_table_class);
if (!table) return;
var k = extractTid(table)
if (e.ctrlKey && e.shiftKey && e.altKey) {
if (!global[k].cookid) return;
setCookie(global[k].cookid[0], "", "", -1) /* 'delete cookie' */
location.reload();
return;
}
sortTab(obj, data_type) /* Параметры: ячейка, строка заголовка, тип сортировки */
}
function sortTab(obj, user_data_type, dont_draw) {
var ci = obj.cellIndex, table = findParent(obj, "TABLE"); /* таблица */
var k = extractTid(table)
var row = findParent(obj, "TR"), ri = row.rowIndex; /* строка */
var i = obj.realIndex; /* номер сортируемой колонки в TBODY global[k].realIndex[ri][ci]; */
var cell = ri.toString() + "." + ci.toString();
var rarr = global[k].vrarr || global[k].rarr, sortcell = "sortcell_" + i
verse = false; /* обратный порядок сортировки */
verse = /d\_\d+\_d/.test(obj.className)
var data_type = user_data_type || getDataType(obj);
user_data_type = user_data_type || data_type
/* сложная проверка, потому что при использовании innerHTML в ИЕ
рвётся связь между массивом rarr и таблицей (всё равно не помогает!) */
if (!rarr || !rarr[0] || undefined == rarr[0]["sortcell_" + i]
|| undefined == rarr[0].val || data_type != user_data_type) {
makeSortArr(table, i, data_type)
}
sorttype = (/^(num|datru|daten)$/.test(data_type)) ? 0 : 1
global.sortcell = "sortcell_" + i
// var vice_versa = (global[k].sorted == i && global[k].sorttype == sorttype && def.use_appendChild)
// if (!vice_versa) { //хорошая была идея, но бесполезная
var fnc
if (verse)
fnc = (sorttype) ? cmpRowVerse : cmpNumVerse
else
fnc = (sorttype) ? cmpRow : cmpNum
rarr = rarr.sort(fnc)
//alert(fnc + rarr[2][global.sortcell])
global[k].sorted = i;
global[k].sorttype = sorttype;
addLog("Table_sort (" + data_type + "): ", k)
updArrow(obj, table, cell, verse)
if (!dont_draw) {
// vice_versa = (global[k].vice_versa && vice_versa) ? false : vice_versa
draw(table)
if (def.use_arrows) addBull(obj, verse, cell)
}
}
function findCell(cell) {
if (!Pare) return null
var table = findChild(Pare, "table", sort_table_class)
if (!table) return null
var coo = cell.split(".")
if (coo.length<2) return null
return(table.rows[coo[0]].cells[coo[1]])
}
function addBull(obj, verse, cell) {
if (!obj.innerHTML) { /* govnosoft_detected */
obj = findCell(cell)
if (!obj) return
}
var a = findChild(obj, "div", "arrows", true)
if (a) {
a.appendChild(bull)
if (verse) addClass(bull, "bup")
else delClass(bull, "bup")
// bull.style.width = parseInt(a.offsetWidth) + "px"
// alert(a.offsetWidth + "/" + bull.offsetWidth)
}
}
function updArrow(obj, table, cell, verse) {
var k = extractTid(table)
/* var ci = cell.split("."), ri = ci[0]
ci = ci && ci[1] */
var i = obj.realIndex;
var data_type = getDataType(obj)
addClass(obj, "sorted")
var title = "Отсортировано по возрастанию", cookid1 = ","
var dir = "d"
if (verse) {
cookid1 += "-"
title = "Отсортировано по убыванию"
dir = "u"
}
if (def.use_title) obj.title = title
/* new arrows (div) */
// var a = findChild(obj, "div", "arrows")
// if (a) {
var c = obj.className, re = new RegExp(/[cdu]\_\d+\_[cdu]/),
new_class = dir + "_" + init_arrow_color + "_" + dir
if (init_arrow_color < 8) init_arrow_color++
if (re.test(c)) obj.className = c.replace(re, new_class)
else addClass(obj, new_class)
// }
/* new arrows (div) end*/
if (def.use_cookie && global[k].cookid) {
global[k].cookid[1] += cookid1 + cell + ":" + data_type
var tocut=new RegExp(cell+"\\:"+data_type+"\\,(\\-?"+cell+"\\:\\w+\\,)+"+cell+"\\:"+data_type)
global[k].cookid[1] = global[k].cookid[1].replace(tocut, cell+":"+data_type)
setCookie(global[k].cookid[0], global[k].cookid[1], "", 0)
}
addLog("Upd_arrow: ", i)
}
function calcSortData(data_type, sortcell_value) {
var sortcell_calc_value
switch (data_type) {
case "num":
sortcell_calc_value = parseFloat(sortcell_value.replace(undigit, ""));
sortcell_calc_value = (isNaN(sortcell_calc_value)) ? Infinity : sortcell_calc_value;
break
case "datru":
if (sortcell_value.search(ru) != -1) sortcell_calc_value = sortcell_value.replace(ru, month.func)
else sortcell_calc_value = sortcell_value
// return sortcell_calc_value
if (/\:/.test(sortcell_calc_value)) sortcell_calc_value = sortcell_calc_value.replace(/^(.*?)(\d+)\:(\d+)/, "$3 $2 $1")
else sortcell_calc_value = "0000 " + sortcell_calc_value
sortcell_calc_value = sortcell_calc_value.replace(/\b(\d)\b/g, "0$1")
sortcell_calc_value = sortcell_calc_value.split(/\D+/).reverse().join("");
// sortcell_calc_value = sortcell_calc_value.replace(/\D+/g, "")
// sortcell_calc_value = Date.parse(sortcell_calc_value);
sortcell_calc_value = (isNaN(sortcell_calc_value)) ? Infinity : sortcell_calc_value;
break
case "daten":
sortcell_calc_value = Date.parse(sortcell_value);
sortcell_calc_value = (isNaN(sortcell_calc_value)) ? Infinity : sortcell_calc_value;
break
default:
sortcell_calc_value = sortcell_value.toString()
break
}
return sortcell_calc_value
}
function makeSortArr(table, i, data_type) {
data_type = data_type || "str"
var k = extractTid(table), n = -1
/* создание массива строк таблицы и приведение к типу сортировки */
var tmp, row, newval,
sortcell = "sortcell_" + i, source = "source_" + i, sortcell_value,
sortcell_calc_value, newrarr, first_sort_line = global[k].first_sort_line,
rlen = table.rows[first_sort_line].cells.length,
first, last, rarr = global[k].vrarr || global[k].rarr,
arr_name = (rarr == global[k].vrarr) ? "vrarr" : "rarr"
if (rarr && rarr.length) {
first = 0
last = rarr.length
newrarr = false
}
else {
rarr = []
first = first_sort_line
last = table.rows.length
newrarr = true
}
// alert("first:" + first +"//last:" + last)
for (var j = first; j < last; j ++) {
n++
newval = 0;
row = (newrarr) ? table.rows[j] : rarr[j].val
/* ячейки может не быть в кривой таблице */
sortcell_value = row && row.cells[i];
try {sortcell_value = sortcell_value && sortcell_value.innerHTML || "";}
catch(e) {
//alert("Вероятно, ваш браузер не может восстановить \nсортировку такой большой таблицы. Ошибка: \n"
// + e.message + j + "//" + i); return;
sortcell_value = ""
}
sortcell_value = stripTags(sortcell_value).toLowerCase();
sortcell_calc_value = calcSortData(data_type, sortcell_value)
// if (row.cells[i]) row.cells[i].innerHTML += " " + sortcell_calc_value
/* проверить вложенность в табличный контейнер (IE): если да - cloneNode? */
if (newrarr) {
global[k][arr_name][n] = {val:row}
global[k][arr_name][n][sortcell] = sortcell_calc_value
global[k][arr_name][n][source] = sortcell_value.toString()
}
else {
global[k][arr_name][j][sortcell] = sortcell_calc_value
global[k][arr_name][j][source] = sortcell_value.toString()
}
// if (table.rows[j].className) return alert(table.rows[j].className)
}
addLog("Создание массива (" + sortcell + "): ")
// alert(global[k].rarr.length + "//" + k + "//" + i + "//" + global[k].rarr[1]["sortcell_" + i] + "//" + sortcell)
}
function draw(table, vice_versa) {
if (def.use_arrows) if (bull.parentNode) bull = bull.parentNode.removeChild(bull)
var k = extractTid(table)
global.last_table = table
global.last_table_index = k
var old_tbody = findChild(table, "TBODY")
var tbody = document.createElement("TBODY") //неудачная попытка ускорения
var newtbody = "", rarr = global[k].vrarr || global[k].rarr, el;
if (!rarr.length) rarr = old_tbody.rows
// if (global[k].vrarr) alert(global[k].vrarr.length + "//draw")
for (var l=0; l global[k].last_line))
addClass(el.val, invis_class)
else {delClass(el.val, invis_class); }
*/
new_row = el.val.cloneNode(true)
if (def.paginate && !hasClass(class_old, invis_class)) addClass(new_row, invis_class);
rarr[l].val = new_row
if (!vice_versa) tbody.appendChild(new_row);
else tbody.insertBefore(new_row, tbody.firstChild)
window.status = l
}
//строка добавляется в таблицу, удаляясь из той же таблицы
//(массив rarr - только упорядоченные ссылки на строки)
/* пытаемся сделать всё ещё проще и быстрее: */
else {
// if (classN.indexOf(" ")>-1) return (alert(classN))
newtbody += "