Javascript-форум (https://javascript.ru/forum/)
-   Ваши сайты и скрипты (https://javascript.ru/forum/project/)
-   -   Простой сортировщик HTML таблиц (https://javascript.ru/forum/project/21463-prostojj-sortirovshhik-html-tablic.html)

stopkran 10.09.2011 10:16

Простой сортировщик HTML таблиц
 
Simple Table Sorter v 0.01

Подключение:

1) в head HTML-документа добавить две строчки:

<link rel='stylesheet' href='tabsort0.css' type='text/css'>
<script type='text/javascript' src='tabsort0.js'>


2) Добавить сортируемым таблицам атрибут class='sortable'.

3) Распаковать архив SimpleTableSorter.zip в папку с HTML документами.

Функциональность: 1) щелчок по заголовку таблицы сортирует строки; 2) Ctrl + Click по заголовку таблицы приводит таблицу в первоначальное состояние (reset).

Рабочий пример: http://ir2.ru/sorters/table400.htm

Два года писал этот код, и всё никак не могу закончить, всё время кажется, что чего-то в нём не хватает. Он небольшой, можно привести целиком:

-function(){
	
	var hc = function (s, c) {return (" " + s + " ").indexOf(" " + c + " ") !== -1},
	 ac = function (e, c) {var s = e.className; if (!hc(s, c)) e.className += " " + c};
	
	prepTabs = function (t){
		var el, th, ts = (t && t.className) ? [t] : document.getElementsByTagName("table")
		for (var e in ts) {
			el = ts[e]
			if (!hc(el.className, "sortable")) continue
			if (!el.tHead) {
				th = document.createElement("thead")
				th.appendChild(el.rows[0])
				el.appendChild(th)
			}
			th = el.tHead
			ac(th, "c_0_c")
			th.title = "Сортировать"
			th.onclick = clicktab
			el.sorted = NaN
			//reset
			el.tb = el.tBodies[0]
			el.tb_res = el.tb.cloneNode(true) 
			el.th_res = th.cloneNode(true) 
			el.a_color = 0 
		}
	}
	
	var clicktab = function (e) {
		e = e || window.event
		var obj = e.target || e.srcElement;
		while (!obj.tagName.match(/^(th|td)$/i)) obj = obj.parentNode
		var i = obj.cellIndex, t = obj.parentNode, cn = obj.className, verse = /d\_\d+\_d/.test(cn);
		while (!t.tagName.match(/^table$/i)) t = t.parentNode
		var j = 0, rows = t.tb.rows, l = rows.length, c, v, vi;
		
		if (e.ctrlKey) { /* reset */
			t.replaceChild(t.tb_res, t.tb); 
			t.replaceChild(t.th_res, t.tHead); 
			prepTabs(t); 
			return;
		}
		 
		if (i !== t.sorted) {
			if (t.a_color < 9) t.a_color++ 
			else t.a_color = 1
			t.sarr = []
			for (j; j < l; j++) {
				c = rows[j].cells[i]
				v = (c) ? (c.innerHTML.replace(/\<[^<>]+?\>/g, '')) : ''
				vi = Math.round(100 * parseFloat(v)).toString()
				if (isFinite(vi)) while (vi.length < 10) vi = '0' + vi
				else vi = v
				t.sarr[j] = [vi + (j/1000000000).toFixed(10), rows[j]]
				//c.innerHTML = t.sarr[j][0]
			}
		}
		t.sarr = (verse) ? t.sarr.reverse() : t.sarr.sort()
		t.sorted = i
		
		var dir = (verse) ? "u" : "d", new_cls = dir + "_" + t.a_color + "_" + dir,
		 a_re = /[cdu]\_\d+\_[cdu]/;
		if (a_re.test(cn)) obj.className = cn.replace(a_re, new_cls)
		else obj.className = new_cls
		for (j = 0; j < l; j++) t.tb.appendChild(t.sarr[j][1])
		obj.title = "Отсортировано по " + ((verse) ? "убыванию" : "возрастанию")
	}
	window.onload = prepTabs
}()

melky 10.09.2011 10:41

несколько советов

а так.. код ужат уже. переменные с именами в одну букву.. зачем это делать самому, если GCC сделает это сам?

var hc = function (s, c) {return (" " + s + " ").indexOf(" " + c + " ") !== -1},

var hc = function (s, c) {return !!~(" " + s + " ").indexOf(" " + c + " ") },


..
window.onload = prepTabs

document.addEventListener("DOMContentLoaded", prepTabs, false );

with-love-from-siberia 10.09.2011 10:59

Вопрос. Как справляется сортировщик с большими таблицами (например, несколько тысяч строк)?

stopkran 10.09.2011 12:14

Цитата:

Сообщение от with-love-from-siberia (Сообщение 125878)
Вопрос. Как справляется сортировщик с большими таблицами (например, несколько тысяч строк)?

Плохо справляется! :-) Посмотрите: http://ir2.ru/sorters/table2000_1.htm. Хотя на самом деле javascript тут ни при чём, просто браузер долго отрисовывает длинную таблицу. Её надо искусственно сокращать, разбивать на страницы, тогда будет хорошо:

http://ir2.ru/sort1/table2000_1.htm

Gozar 10.09.2011 16:11

Цитата:

Сообщение от stopkran (Сообщение 125887)
Плохо справляется!

У меня нормуль.

stopkran 11.09.2011 13:27

Цитата:

Сообщение от melky
!!~(" " + s + " ").indexOf(" " + c + " ")

Идея интересная, но без восклицательных знаков было бы ещё круче.

stopkran 11.09.2011 13:29

Цитата:

Сообщение от Gozar (Сообщение 125909)
У меня нормуль.

Скорость движения роты равна скорости самого плохого солдата. Проверьте на msie.

melky 11.09.2011 15:15

Цитата:

Сообщение от stopkran (Сообщение 125985)
Идея интересная, но без восклицательных знаков было бы ещё круче.

да ты что. без восклицательных знаков будет тип другой.

хотя можно и без них. все равно дальше будет преобразовываться в буль :)

NoResponse 12.09.2011 15:39

если цель сократить код, то я бы "избавился" от всех... или почти всех var
например вот этот кусочек
...
	    prepTabs = function (t){
	        var el, th, ts = (t && t.className) ? [t] : document.getElementsByTagName("table")
	        for (var e in ts) {
...

можно заменить на
...
	    prepTabs = function (t,   el,th,ts,e){
	        ts = (t && t.className) ? [t] : document.getElementsByTagName("table")
	        for (e in ts) {
...

stopkran 13.09.2011 04:19

Цитата:

Сообщение от NoResponse (Сообщение 126122)
если цель сократить код...

Интересное решение насчёт var. Занятно. Сократить код - одна из целей, но не главная. Важнее всё-таки оставить код логичным, понятным. Например, если переменные из одной буквы, то достаточно очевидные: r - row, c - cell, t - table...

...ну, и сокращение тут происходит не всегда: вариант "function(a, b, c){a = 1; b = 2; c = 3;}" на три буквы длиннее традиционного "function(){var a = 1, b = 2, c = 3;}"

Kolyaj 13.09.2011 11:53

Цитата:

Сообщение от NoResponse
если цель сократить код, то я бы "избавился" от всех... или почти всех var

Интересно вы код сократили, на 1 байт больше стало. Если одновременно с объявлением переменной идёт её инициализация, то с var короче будет.

with-love-from-siberia 14.09.2011 20:46

Исправления предлагаю. Замените строку
Код:

for (var e in ts) {
на
Код:

for(var e = 0; e < ts.length; e++) {

stopkran 15.09.2011 05:59

Цитата:

Сообщение от with-love-from-siberia
Исправления предлагаю

А что мне за это будет? Вы предлагаете удлинить код - ради чего? в чём выгода? :-) Вот если бы вы предложили в строке 07 заменить фрагмент "ts = (t && t.className) ? [t] ..." на более простой "ts = (t) ? [t] ...", я бы ещё подумал.

Octane 15.09.2011 08:33

Для Array часто добавляют реализацию стандартных методов в прототип для старых браузеров, поэтому el может оказаться, например, "forEach" или "indexOf"… можно конечно добавить проверку hasOwnProperty, но лучше перебирать по индексам элементов.

with-love-from-siberia 15.09.2011 08:45

Цитата:

Сообщение от Octane
Для Array часто добавляют реализацию стандартных методов

На самом деле getElementsByTagName возвращает не массив а коллекцию. for in в данном случае занимается перебором всех свойств коллекции - 0, ..., length, item, namedItem.

Цитата:

Сообщение от stopkran
А что мне за это будет?

Ничего плохого. Лишние проходы цикла - сомнительная экономия в ущерб производительности. Хотя их всего три, но ведь их может быть и больше. Вдруг Вы еще где-то съэкономили на производительности?

stopkran 15.09.2011 10:22

Согласен, for in выглядит несколько некошерным, таким "неформалом". Но, к сожалению, я это знал и раньше, и прошёл много всяких граблей на эту тему, использовать теперь не боюсь. Оставлю пока как "каприз художника".

О, я много где сэкономил на производительности! :-) Но вы всё равно не найдёте. Да я и сам сейчас не вспомню всего. Но можно ведь производительность просто измерить. В первой версии я сэкономил на коде (измерителя нет). Но вот в следующей (Simple Table Sorter v0.03) можно посмотреть скорость:

http://ir2.ru/sort0.03/table1000.htm

Можно даже сравнить по скорости с некоторыми другими сортировщиками (желательно в IE):

http://ir2.ru/sorters/fd/
http://ir2.ru/sorters/la/
http://ir2.ru/sorters/standardista/

Это, конечно, очень приблизительно (измеритель прикручивал к чужому коду, мог не всё учесть и неправильно назвать какие-то моменты). Ну, плюс я добрый - добавил в standardista небольшой хак, без которого в IE сортировка работала бы десятки секунд.

Octane 15.09.2011 11:33

Кстати заметил, что последнее время, с появлением Object.keys, у меня в коде вообще исчезли for-in, теперь пишу:
var keys = Object.keys(obj), i = keys.length;
while (i--) {
    obj[keys[i]]…
}

в браузерах поддерживающих Object.keys разница в скорости с вариантом:
for (key in obj) {
    if (obj.hasOwnProperty(key)) {
        obj[key]…
    }
}

несущественна.

Kolyaj 15.09.2011 12:27

Цитата:

Сообщение от Octane
с, появлением Object.keys, у меня в коде вообще исчезли for-in

А почему while не исчезли?
Object.keys(obj).forEach(function(key) {
   // ...
});

Octane 15.09.2011 12:36

Как-то расточительно на каждую итерацию выполнять функцию, когда можно этого не делать

Kolyaj 15.09.2011 12:40

Да перестань, на фоне любой операции внутри функции вызов самой функции будет незначительным. Выигрыш у тебя будет только если ты проверяешь на скорость различные виды ничего не делающих циклов.
А вот создающийся скоп внутри функции реально полезен.

Octane 15.09.2011 13:19

Еще у меня из-за замыкания начинается паранойя:
proto = {
	method: function (…) {
		var a, b, c, d, …;
		Object.keys(…).forEach(function (…) {
			//к примеру, тут не нужны a, b, c, d
		});
	}
}

приходится выносить в отдельный метод:
proto = {
	_method: function (…) {
		//тут this → window
	},
	method: function (…) {
		var a, b, c, d, …;
		Object.keys(…).forEach(this._method);
	}
}

но метод в прототипе, ничего не делающий с this, кажется лишним, выносим его в отдельный объект:
utils = {
	method: function (…) {…}
}

proto = {
	method: function (…) {
		var a, b, c, d, …;
		Object.keys(…).forEach(utils.method);
	}
}

в итоге придется искать в коде, что же там за utils.method, который возможно состоит из пары строчек и самостоятельно не имеет смысла, появляется проблема с передачей дополнительных переменных.

а можно было всего-лишь написать:
proto = {
	method: function (…) {
		var a, b, c, d, …, keys = Object.keys(…), i = keys.length;
		while (i--) {
			…
		}
	}
}


поэтому forEach использую, только когда действительно нужен локальный скоп, а еще в светлом будущем ожидается let

Kolyaj 15.09.2011 13:33

proto = {
    method: function (…) {
        var a, b, c, d, …, keys = Object.keys(…), i = keys.length;
        while (i--) {
            //к примеру, тут не нужны a, b, c, d
        }
    }
}

И в чём разница?

Octane 15.09.2011 13:38

Ну так они никуда не замыкаются, паранойя не наступает :D

Kolyaj 15.09.2011 13:42

А что меняется от того, замыкаются они или не замыкаются? Не пойму, откуда паранойя растёт.

Octane 15.09.2011 14:05

Да ничего страшного не происходит. Я понимаю, что разница будет заметна только в тестах, где 100500 раз одно и тоже повторяют, но просто зачем все эти лишние действия (создание функции, связь скопов, call, …) будут происходить, если используя while, их не будет.

float 16.09.2011 06:17

я тоже сначала заморачивался по этому поводу, а потом перестал, когда сравнил скорость...

x-yuri 25.09.2011 20:09

Цитата:

Сообщение от stopkran
Два года писал этот код,

с этим надо что-то делать... например, разобраться, все-таки, почему он не закончен. И что из этого всего стоило потраченных усилий, а что - нет

Цитата:

Сообщение от stopkran
О, я много где сэкономил на производительности! :-) Но вы всё равно не найдёте. Да я и сам сейчас не вспомню всего.

в результате имеем код, который желательно не менять. Либо надо осознавать, что изменения могут свести на нет усилия по оптимизации. Комментарии тогда надо было делать для таких неочевидных моментов. Собственно, это их основное назначение

вот, float, это правильный подход при борьбе с паранойей, я считаю :)

B~Vladi 26.09.2011 11:42

Цитата:

Сообщение от Octane
Да ничего страшного не происходит. Я понимаю, что разница будет заметна только в тестах, где 100500 раз одно и тоже повторяют, но просто зачем все эти лишние действия (создание функции, связь скопов, call, …) будут происходить, если используя while, их не будет.

О, я тоже параноик, круто.

stopkran 27.09.2011 16:11

Цитата:

Сообщение от x-yuri
в результате имеем код, который желательно не менять. Либо надо осознавать, что изменения могут свести на нет усилия по оптимизации. Комментарии тогда надо было делать для таких неочевидных моментов

В точку. Любые изменения этого кода приводят к ухудшению производительности. Он находится в состоянии устойчивого равновесия. Вещь в себе. На данном этапе.

Но на следующем - возникает потребность не в совершенстве кода, а в новой функциональности. И маховик начинает раскручиваться заново: добавляем, например, раскраску строк в зависимости от значений, и оказывается, что простой алгоритм не способен решить эту задачу.

x-yuri 27.09.2011 23:43

Цитата:

Сообщение от stopkran
И маховик начинает раскручиваться заново:

вот поэтому я не люблю готовые визуальные компоненты. Наличие готового компонента хорошо, а умение создать такой же, знание подводных камней, еще лучше. Поэтому самое главное ты, на мой взгляд, упустил: ты не помнишь всех проблем с которыми ты сталкивался. Хотя не думаю, что все проблемы были действительно важны...

stopkran 29.09.2011 13:50

Цитата:

Сообщение от x-yuri (Сообщение 128347)
самое главное ты, на мой взгляд, упустил: ты не помнишь всех проблем с которыми ты сталкивался...

не-е, дядя Фёдор, я правильно бутерброд ем! Важное я не упустил, это я так, для красного словца болтанул, что не помню.

И, кстати, маховик провернулся уже третий раз. О версии 0.03 с раскраской ячеек в зависимости от содержания я уже говорил (http://ir2.ru/sort0.03/table400.htm), код с комментариями 9К.

А вот версия 0.04, с визуальными настройками для пользователя (можно мышкой выбирать типы данных для сортировки или указывать очередь предопределённой сортировки для разных столбцов: http://ir2.ru/sort0.03/table404.htm (код 18К, а ничего, кроме удобства для пользователей, не добавилось!).

Никаких готовых визуальных компонентов, всё на коленке рисовал! А вот пару функций для куки позаимствовал у соседей (хватило ума понять, что свои хуже :-)). Причём, как-то вот выбрал так, что getCookie мне больше понравились у Riim (нафига возвращать null, если в этом случае это совпадает по работе с undefined), а вот setCookie взял у Kolyaj (ибо не нужен мне сложный массив параметров, хотя теоретически это точнее).


Часовой пояс GMT +3, время: 03:55.