страничка рейтинга оконных профилей
This commit is contained in:
@@ -18,7 +18,7 @@ from django.contrib import admin
|
|||||||
from django.urls import path, re_path
|
from django.urls import path, re_path
|
||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
from oknardia.settings import *
|
from oknardia.settings import *
|
||||||
from web import views, autocomplete_addr, user_manager, blog, diagrams
|
from web import views, autocomplete_addr, user_manager, blog, diagrams, report2
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
@@ -41,13 +41,15 @@ urlpatterns = [
|
|||||||
re_path(r'^change_password$', user_manager.change_password),
|
re_path(r'^change_password$', user_manager.change_password),
|
||||||
# ОБРАБОТЧИКИ СПИСКА ПУБЛИКАЦИЙ И САМИХ ПУБЛИКАЦИЙ БЛОГА
|
# ОБРАБОТЧИКИ СПИСКА ПУБЛИКАЦИЙ И САМИХ ПУБЛИКАЦИЙ БЛОГА
|
||||||
re_path(r'^blog/*$', blog.blog_list),
|
re_path(r'^blog/*$', blog.blog_list),
|
||||||
re_path(r'^blog/P(?P<page>\d{1,})/*$', blog.blog_list_posts),
|
re_path(r'^blog/P(?P<page>\d+)/*$', blog.blog_list_posts),
|
||||||
re_path(r'^blogpost/(?P<post_id>\d{1,})/(?P<page_back>\d{1,})/\S*/*$', blog.blog_post),
|
re_path(r'^blogpost/(?P<post_id>\d+)/(?P<page_back>\d+)/\S*/*$', blog.blog_post),
|
||||||
re_path(r'^blogpost/(?P<post_id>\d{1,})/\S*/*$', blog.blog_post),
|
re_path(r'^blogpost/(?P<post_id>\d+)/\S*/*$', blog.blog_post),
|
||||||
# САТИЧЕСКИЕ СТРАНИЦЫ
|
# САТИЧЕСКИЕ СТРАНИЦЫ
|
||||||
re_path(r'^tariff$', views.tariff),
|
re_path(r'^tariff[/*]$', views.tariff),
|
||||||
re_path(r'^contact', views.contact),
|
re_path(r'^contact[/*]$', views.contact),
|
||||||
re_path(r'^stat_all$', diagrams.statistic_menu),
|
re_path(r'^stat_all[/*]$', diagrams.statistic_menu),
|
||||||
|
re_path(r'^stat/rating[/*]$', report2.ratings),
|
||||||
|
re_path(r'^stat/rating/profiles_rank[/*]$', report2.profiles_rating),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
67
oknardia/templates/rating/profiles_rating.html
Executable file
67
oknardia/templates/rating/profiles_rating.html
Executable file
@@ -0,0 +1,67 @@
|
|||||||
|
{% extends "base.html" %}{% load static %}
|
||||||
|
|
||||||
|
{% block Title %}: Тарифы и услуги{% endblock %}
|
||||||
|
|
||||||
|
{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %}
|
||||||
|
|
||||||
|
{# block Date4Meta %}{{ META_DATA_PUBLISH|date:"c" }}{% endblock #}
|
||||||
|
|
||||||
|
{# block Last4Meta %}{{ META_DATA_PUBLISH|date:"c" }}{% endblock #}
|
||||||
|
|
||||||
|
{% block Description %}Тарифы и услуги маркетплейс-агрегатора Окнардия. Размещение предложений пластиковых и деревянных окон, обновление цен на окна, рекламные баннеры и виджеты на сайт оконной компании.{% endblock %}
|
||||||
|
|
||||||
|
{% block Keywords %}типовые проекты зданий, панельное строительство, {% for CountSeria in SERIA_NAV_DIM %}серия {{ CountSeria.SERIA_R }}, {{ CountSeria.SERIA_R }}, {% endfor %}, года постройки, регионы постройки, распространённость{% endblock %}
|
||||||
|
|
||||||
|
{% block Top_JS5 %}
|
||||||
|
<script src="{% static 'js/sortable-table.js' %}" type="text/javascript"></script>{% endblock %}
|
||||||
|
|
||||||
|
{% block Main_Content %}<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-9"><h1>Рейтинг оконных профилей базы «Окнардия»</h1></div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-10 col-sm-12">
|
||||||
|
<table class="rang table-hover table-responsive" id="for_including1" style="margin-bottom: 4em;">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>№</th>
|
||||||
|
<th>Производитель</th>
|
||||||
|
<th>Марка</th>
|
||||||
|
<th>Рейтинг</th>{% for k in KEYS %}
|
||||||
|
<th title="K{{ forloop.counter }}: {{ k }}">K{{ forloop.counter }}</th>{% endfor %}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>{% for i in TABLE %}
|
||||||
|
<tr {% if not i.R_REAL %} class="NR" {% endif %}>
|
||||||
|
<td data-sort="{{ forloop.counter }}">{{ forloop.counter }}.</td>
|
||||||
|
<td data-sort="{{ i.BRAND }}"><a href="/catalog/profile/{{ i.ID }}-{{ i.BRAND_URL }}">{{ i.BRAND }}</a></td>
|
||||||
|
<td data-sort="{{ i.NAME }}"><a href="/catalog/profile/{{ i.ID }}-{{ i.BRAND_URL }}/{{ i.ID }}-{{ i.NAME_URL }}">{{ i.NAME }}</a></td>
|
||||||
|
<td data-sort="{{ i.RATING_N|stringformat:".2f" }}" class="c" style="background:rgb({{ i.RATING_COLOR }});">
|
||||||
|
<nobr title="Рейтинг «Окнардии» для профиля {{ i.NAME }} компании {{ i.BRAND }} — {% if i.RATING_N >= 0 %}{{ i.RATING_N|stringformat:".2f" }}{% else %}не присвоен{% endif %}"><!-- НАЧАЛО звездочки рейтинга -->{% for Star in i.RATING_STAR %}{% if Star == 0 %}<i class="glyphicon glyphicon-star-empty"{% if i.RATING_COLOR2 %} style="color:rgb({{ i.RATING_COLOR2 }})"{% endif %}></i>{% else %}<b class="glyphicon glyphicon-star"{% if i.RATING_COLOR2 %} style="color:rgb({{ i.RATING_COLOR2 }})"{% endif %}></b>{% endif %}{% endfor %}<!-- КОНЕЦ звездочки рейтинга НАЧАЛО бедж --> {% if i.RATING_N >= 0 %}<tt class="badge"{% if i.RATING_COLOR2 %} style="background:rgb({{ i.RATING_COLOR2 }})"{% endif %}>{{ i.RATING_N|stringformat:".2f" }}</tt>{% endif %}<!-- КОНЕЦ бедж --></nobr></td>{% for j in i.K_ARR %}
|
||||||
|
<td data-sort="{{ j.VAL|stringformat:".4f" }}" style="background-color:rgb({{ j.COLOR }});"> </td>{% endfor %}
|
||||||
|
</tr>{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
<script src="{% static 'js/sortable-table.js' %}" type="text/javascript"></script>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-2 col-md-3 kk">
|
||||||
|
<p>Характеристики оконных профилей по которым производится ранжирование:</p>
|
||||||
|
<ul>{% for k in KEYS %}
|
||||||
|
<li><b>K{{ forloop.counter }}:</b> {{ k }}</li>{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<hr />
|
||||||
|
<h2>Условные обозначения:</h2>
|
||||||
|
<p><span style="background:linear-gradient(to left,#0f0,#fff);border:1px solid grey;white-space:nowrap;">   </span> — Цвето­вое коди­ров­ание окон­ных про­филей присут­ству­ющих в пред­ложе­ниях участ­ников «Окнар­дии» <em>(реаль­ный рей­тинг)</em>. Более насы­щен­ный зелё­ный озна­чает лучшую харак­те­ристику. Харак­те­рис­тики профилей с реаль­ным рей­тингом предос­тавлены <nobr>компа­ниями-участ­никами</nobr>.</p>
|
||||||
|
<p><span style="background:linear-gradient(to left,silver,#fff);border:1px solid grey;white-space:nowrap;">   </span> — Цвето­вое коди­рова­ние окон­ных про­филей из базы «Окнар­дии» по кото­рым нет ком­мерче­ских пред­лож­ений участ­ников <em>(вир­туаль­ный рей­тинг)</em>. Более яркий цвет озна­чает лучшую харак­терис­тику. Харак­терис­тики про­филей с вир­туаль­ным рей­тин­гом взяты из незави­симый источ­ников.</p>
|
||||||
|
<hr />
|
||||||
|
<p>Методика формирования рейтинга «Окнардии», порядок ранжирования и веса характеристик оконных профилей <a href="/blogpost/13/Rejting-Oknardii-i-kak-on-ustroen-(chast-2)">описаны в нашем блоге </a>.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>{% endblock %}
|
||||||
|
|
||||||
|
{% comment %}
|
||||||
|
{% block Top_Nav_Bar %}
|
||||||
|
{# ОТЛАДКА, ГАСИМ ВЕРХНЕЕ МЕНЮ #}
|
||||||
|
{% endblock %}
|
||||||
|
{% endcomment %}
|
||||||
|
|
||||||
@@ -9,8 +9,8 @@ import math
|
|||||||
def safe_html_spec_symbols(s: str) -> str:
|
def safe_html_spec_symbols(s: str) -> str:
|
||||||
""" Очистка строки от HTML-разметки типографа
|
""" Очистка строки от HTML-разметки типографа
|
||||||
|
|
||||||
:param s: строка которую надо очистить
|
:param s: str -- строка которую надо очистить
|
||||||
:return: str:
|
:return: str: str -- очищенная строка
|
||||||
"""
|
"""
|
||||||
# очистка строки от некоторых спец-символов HTML
|
# очистка строки от некоторых спец-символов HTML
|
||||||
result = s.replace('­', '')
|
result = s.replace('­', '')
|
||||||
@@ -40,50 +40,60 @@ def safe_html_spec_symbols(s: str) -> str:
|
|||||||
# ), "ru", reversed=True).replace(u" ", u"-").replace(u"'", u"").replace(u"/", u"~").replace(u"\\", u"~").replace(u"--", u"-")
|
# ), "ru", reversed=True).replace(u" ", u"-").replace(u"'", u"").replace(u"/", u"~").replace(u"\\", u"~").replace(u"--", u"-")
|
||||||
|
|
||||||
|
|
||||||
def Rus2Url (RusString):
|
# def Rus2Url (RusString):
|
||||||
return re.sub(r'^-|-$', '',
|
# return re.sub(r'^-|-$', '',
|
||||||
re.sub(r'-{1,}', '-',
|
# re.sub(r'-{1,}', '-',
|
||||||
re.sub(r'<[\s\S]*?>|&[\S]*?;|[\W]', '-',
|
# re.sub(r'<[\s\S]*?>|&[\S]*?;|[\W]', '-',
|
||||||
re.sub(r'\+', '-plus', translit(RusString, "ru", reversed=True))
|
# re.sub(r'\+', '-plus', translit(RusString, "ru", reversed=True))
|
||||||
)
|
# )
|
||||||
)
|
# )
|
||||||
).lower()
|
# ).lower()
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# # Суммирует все цифры в строке через произвольные (не цифровые) разделители
|
||||||
|
# def SummThrought(StringWSlash):
|
||||||
|
# StringWSlash = re.sub( r"[^0-9]", u",", StringWSlash)
|
||||||
|
# ListTerms = StringWSlash.split(u',')
|
||||||
|
# Summ = 0
|
||||||
|
# for Count in ListTerms:
|
||||||
|
# try:
|
||||||
|
# Summ += int(Count)
|
||||||
|
# except:
|
||||||
|
# pass
|
||||||
|
# return Summ
|
||||||
|
#
|
||||||
|
#
|
||||||
|
def get_rating_set_for_stars(rating: float = 0.) -> list:
|
||||||
|
""" Возвращает массив 1 и 0 для отрисовки звёздочек.
|
||||||
|
|
||||||
|
:param rating: float -- рейтинг
|
||||||
# Суммирует все цифры в строке через произвольные (не цифровые) разделители
|
:return: list: list -- массив 1 и 0 для отрисовки звёздочек
|
||||||
def SummThrought(StringWSlash):
|
"""
|
||||||
StringWSlash = re.sub( r"[^0-9]", u",", StringWSlash)
|
|
||||||
ListTerms = StringWSlash.split(u',')
|
|
||||||
Summ = 0
|
|
||||||
for Count in ListTerms:
|
|
||||||
try:
|
|
||||||
Summ += int(Count)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
return Summ
|
|
||||||
|
|
||||||
|
|
||||||
# возвращает массив 1 и 0 для отрисовки зввездочек.
|
|
||||||
def GetRatingSet4Star ( fRating ):
|
|
||||||
# if fRating < 0.01:
|
# if fRating < 0.01:
|
||||||
# return []
|
# return []
|
||||||
RatingSet = []
|
rating_set = []
|
||||||
for CountStar in range(RARING_STAR):
|
for CountStar in range(RARING_STAR):
|
||||||
if RARING_SET_MIN+CountStar*(RARING_SET_MAX-RARING_SET_MIN)/RARING_STAR+1 <= fRating:
|
if RARING_SET_MIN+CountStar * (RARING_SET_MAX - RARING_SET_MIN) / RARING_STAR + 1. <= rating:
|
||||||
RatingSet.append(1)
|
rating_set.append(1)
|
||||||
else:
|
else:
|
||||||
RatingSet.append(0)
|
rating_set.append(0)
|
||||||
return RatingSet
|
return rating_set
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# # рассчитывает дистанцию в км. между двумя геокоординатами
|
||||||
|
# def GetGeoDistance(lon1, lat1, lat2, lon2):
|
||||||
|
# lonA, latA, latB, lonB = map(math.radians, [lon1, lat1, lat2, lon2])
|
||||||
|
# distance = 2 * math.asin(math.sqrt(math.sin((latB - latA) / 2) ** 2 + math.cos(latA) * math.cos(latB) * math.sin(
|
||||||
|
# (lonB - lonA) / 2) ** 2)) * 6371.032 # РАДИУС ЗЕМЛИ 6371.032 КМ.
|
||||||
|
# return distance
|
||||||
|
|
||||||
|
|
||||||
# рассчитывает дистанцию в км. между двумя геокоординатами
|
def normalize(val: float, val_max: float = 5., val_min: float = 0.) -> float:
|
||||||
def GetGeoDistance(lon1, lat1, lat2, lon2):
|
""" Нормализация значения
|
||||||
lonA, latA, latB, lonB = map(math.radians, [lon1, lat1, lat2, lon2])
|
|
||||||
distance = 2 * math.asin(math.sqrt(math.sin((latB - latA) / 2) ** 2 + math.cos(latA) * math.cos(latB) * math.sin(
|
|
||||||
(lonB - lonA) / 2) ** 2)) * 6371.032 # РАДИУС ЗЕМЛИ 6371.032 КМ.
|
|
||||||
return distance
|
|
||||||
|
|
||||||
|
:param val: float -- значение которое надо нормализовать
|
||||||
# нормализация
|
:param val_max: float -- максимальное значение в нормализуемом диапазоне
|
||||||
def Normalize(Val, ValMax=5, ValMin=0):
|
:param val_min: float -- минимальное значение в нормализуемом диапазоне
|
||||||
return float(Val-ValMin)/float(ValMax-ValMin)
|
:return: float: float -- нормализованное значение
|
||||||
|
"""
|
||||||
|
return float(val - val_min) / float(val_max - val_min)
|
||||||
|
|||||||
90
oknardia/web/report2.py
Normal file
90
oknardia/web/report2.py
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# __author__ = 'Sergei Erjemin'
|
||||||
|
from django.shortcuts import render, redirect
|
||||||
|
from django.http import HttpRequest, HttpResponse
|
||||||
|
from oknardia.models import PVCprofiles
|
||||||
|
from oknardia.settings import *
|
||||||
|
from web.add_func import normalize, get_rating_set_for_stars
|
||||||
|
from time import time
|
||||||
|
import json
|
||||||
|
import pytils
|
||||||
|
|
||||||
|
|
||||||
|
def ratings(request: HttpRequest) -> HttpResponse:
|
||||||
|
""" Страница "Рейтинги" в главном меню
|
||||||
|
|
||||||
|
Т.к. пока есть данные и рейтинги только профилей, то делаем редирект на неё
|
||||||
|
|
||||||
|
:param request: HttpRequest -- входящий http-запрос
|
||||||
|
:return: HttpResponse -- исходящий http-ответ
|
||||||
|
"""
|
||||||
|
return redirect('/stat/rating/profiles_rank/')
|
||||||
|
|
||||||
|
|
||||||
|
def profiles_rating(request: HttpRequest) -> HttpResponse:
|
||||||
|
""" Формирует таблицу с рейтингами оконных профилей
|
||||||
|
|
||||||
|
:param request: HttpRequest -- входящий http-запрос
|
||||||
|
:return: HttpResponse -- исходящий http-ответ
|
||||||
|
"""
|
||||||
|
time_start = time()
|
||||||
|
template = "rating/profiles_rating.html"
|
||||||
|
to_template = {}
|
||||||
|
q = PVCprofiles.objects.order_by("fProfileRating", "fProfileSeals", "fProfileHeatTransf",
|
||||||
|
"fProfileSoundproofing", "iProfileHeight", "iProfileRabbet",
|
||||||
|
"iProfileGlazingThickness", "iProfileThickness", "iProfileCameras")
|
||||||
|
table = []
|
||||||
|
keys = [RANK_PVCP_HEAT_TRANSFER_NAME, RANK_PVCP_SOUNDPROOFING_NAME, RANK_PVCP_SEALS_NAME,
|
||||||
|
RANK_PVCP_HEIGHT_NAME, RANK_PVCP_G_THICKNESS_NAME, RANK_PVCP_THICKNESS_NAME,
|
||||||
|
RANK_PVCP_RABBET_NAME, RANK_PVCP_CAMERAS_NUM_NAME, RANK_PVCP_CAMERAS_POPULARITY_NAME]
|
||||||
|
to_template.update({'KEYS': keys})
|
||||||
|
for i in q:
|
||||||
|
try:
|
||||||
|
received_json = json.loads(i.sProfileDescription)
|
||||||
|
except json.decoder.JSONDecodeError:
|
||||||
|
continue
|
||||||
|
if KEY_RATING in received_json:
|
||||||
|
rating_real = True
|
||||||
|
r = received_json[KEY_RATING]
|
||||||
|
color = int(255 - normalize(i.fProfileRating) * 255)
|
||||||
|
rating_color = f"{color},255,{color}"
|
||||||
|
rating_color2 = False
|
||||||
|
elif KEY_RATING_VIRTUAL in received_json:
|
||||||
|
rating_real = False
|
||||||
|
r = received_json[KEY_RATING_VIRTUAL]
|
||||||
|
color = int(255 - normalize(i.fProfileRating) * 64)
|
||||||
|
color2 = int(220 - normalize(i.fProfileRating) * 127)
|
||||||
|
rating_color = f"{color},{color},{color}"
|
||||||
|
rating_color2 = f"{color2},{color2},{color2}"
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
# if keys == []:
|
||||||
|
# keys = sorted(r.keys())
|
||||||
|
# to_template.update({'KEYS': keys})
|
||||||
|
k_arr = []
|
||||||
|
for j in keys:
|
||||||
|
if rating_real: # Это рейтинг на профили, по которым есть ценник (зелененький)
|
||||||
|
clr = int(255 - r[j] * 255)
|
||||||
|
k_arr.append({"COLOR": f"{clr},255,{clr}", "VAL": r[j], "KEY": j})
|
||||||
|
else: # Это "потенциальный" рейтинг, без реальных ценовых предложений (серенький)
|
||||||
|
clr = int(255 - r[j] * 64)
|
||||||
|
k_arr.append({"COLOR": f"{clr},{clr},{clr}", "VAL": r[j], "KEY": j})
|
||||||
|
table.append({
|
||||||
|
"ID": i.id,
|
||||||
|
"R_REAL": rating_real,
|
||||||
|
"BRAND": i.sProfileManufacturer,
|
||||||
|
"BRAND_URL": pytils.translit.slugify(i.sProfileManufacturer),
|
||||||
|
"NAME": i.sProfileName,
|
||||||
|
"NAME_URL": pytils.translit.slugify(i.sProfileName),
|
||||||
|
"K_ARR": k_arr,
|
||||||
|
"RATING_STAR": get_rating_set_for_stars(i.fProfileRating),
|
||||||
|
"RATING_N": i.fProfileRating,
|
||||||
|
"RATING_COLOR": rating_color,
|
||||||
|
"RATING_COLOR2": rating_color2
|
||||||
|
})
|
||||||
|
|
||||||
|
# получаем данные для фрейма ценовых предложений
|
||||||
|
to_template.update({'TABLE': table})
|
||||||
|
to_template.update({'ticks': float(time() - time_start)})
|
||||||
|
response = render(request, template, to_template)
|
||||||
|
return response
|
||||||
50
public/static/js/sortable-table.js
Executable file
50
public/static/js/sortable-table.js
Executable file
@@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* Created by Sergei on 22.июл.2017.
|
||||||
|
* скрипт сортировки таблицы взят из: https://bootsnipp.com/snippets/4OZQx
|
||||||
|
*/
|
||||||
|
(function (document) {
|
||||||
|
let LightTableSorter = (function (Arr) {
|
||||||
|
let _th, _cellIndex, _order = '';
|
||||||
|
function _text(row) {
|
||||||
|
return row.cells.item(_cellIndex).getAttribute("data-sort").toLowerCase().replace(".", "");
|
||||||
|
}
|
||||||
|
function _sort(a, b) {
|
||||||
|
let va = _text(a), vb = _text(b), n = parseInt(va, 10);
|
||||||
|
if (n) va = n, vb = parseInt(vb, 10);
|
||||||
|
return va > vb ? 1 : va < vb ? -1 : 0;
|
||||||
|
}
|
||||||
|
function _toggle() {
|
||||||
|
let c = _order !== 'asc' ? 'asc' : 'desc';
|
||||||
|
_th.className = (_th.className.replace(_order, '') + ' ' + c).trim();
|
||||||
|
_order = c;
|
||||||
|
}
|
||||||
|
function _reset() {
|
||||||
|
_th.className = _th.className.replace('asc', '').replace('desc', '');
|
||||||
|
_order = '';
|
||||||
|
}
|
||||||
|
function onClickEvent(e) {
|
||||||
|
if (_th && _cellIndex !== e.target.cellIndex) _reset();
|
||||||
|
_th = e.target;
|
||||||
|
_cellIndex = _th.cellIndex;
|
||||||
|
let tbody = _th.offsetParent.getElementsByTagName('tbody')[0], rows = tbody.rows;
|
||||||
|
if (rows) {
|
||||||
|
rows = Arr.sort.call(Arr.slice.call(rows, 0), _sort);
|
||||||
|
if (_order === 'asc') Arr.reverse.call(rows);
|
||||||
|
_toggle();
|
||||||
|
tbody.innerHtml = '';
|
||||||
|
Arr.forEach.call(rows, function (row){tbody.appendChild(row);});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
init: function () {
|
||||||
|
let ths = document.querySelectorAll('table.rang>thead>tr>th');
|
||||||
|
Arr.forEach.call(ths, function (th) {th.onclick = onClickEvent;});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(Array.prototype);
|
||||||
|
if ($("div").is("#to_load"))
|
||||||
|
window.LightTableSorter = LightTableSorter;
|
||||||
|
else document.addEventListener('readystatechange', function(){
|
||||||
|
if (document.readyState === 'complete') LightTableSorter.init();
|
||||||
|
}, false);
|
||||||
|
})(document);
|
||||||
Reference in New Issue
Block a user