$(cattreeTables)
function Clear(Node){ //очищает элемент от всех дочерних элементов
var Child;
while (Child = Node.firstChild)
Node.removeChild(Child);
}
function GetText(Node){ //получает первый текстовый узел элемента (но не текст)
var Child;
var Children = Node.childNodes;
for (var i = 0; Child = Children[i]; i++)
if (Child.nodeType == 3) return Child;
}
function GetCatMembers(catmembers){ //приводит формат списка к старому виду после перехода на др. функцию API
var str, list = [];
for (i = 0; i < catmembers.length; i++){
str = catmembers[i].title;
if (str.indexOf('Категория:') === 0)
str = str.substr(10);
list.push(str);
}
return list;
}
function ExcludeCat(idx, list){ //исключает некоторые категории из списка
var extext, exlist, exind;
var Table = document.getElementById('cattreeTable' + idx);
if (extext = Table.getAttribute('data-exclude')){
exlist = extext.split('\\');
for (var i = 0; i < exlist.length; i++)
if ((exind = list.indexOf(exlist[i])) >= 0)
list.splice(exind,1);
}
return list;
}
function GetCat(ctTitle, idx, row, cat, cont, asyncHandler){ //получить категории и статьи через mw.api
var q = {
action: 'query',
format: 'json',
list: 'categorymembers',
cmtitle: 'Категория:'+ ctTitle,
cmlimit: 200,
cmprop: 'title'
}
if (cat)
q.cmtype = 'subcat';
else
q.cmtype = 'page';
if (cont)
q.cmcontinue = cont;
new mw.Api().get(q)
.done(function(data){
var list = GetCatMembers(data.query.categorymembers);
var cont;
if (cat)
list = ExcludeCat(idx, list);
if (data.continue)
cont = data.continue.cmcontinue;
asyncHandler(idx, list, cont);
} )
}
function FillCell(ctTitle, idx, toprow, row, cat, cont){ //заполнить ячейку категориями или статьями
var asyncFill = function(idx, list, cont){
var a;
var Table = document.getElementById('cattreeTable' + idx);
var Cell = Table.rows[row].cells[0];
Clear(Cell);
for (var i = 0; i < list.length; i++){
a = document.createElement('a');
if (cat){
a.href = '/wiki/' + encodeURIComponent('Категория:'+list[i]);
a.title = 'Категория:'+list[i];
a.onclick = clickCat;
}else{
a.href = '/wiki/' + encodeURIComponent(list[i]);
a.title = list[i];
}
a.appendChild(document.createTextNode(list[i]));
Cell.appendChild(a);
if (i < list.length - 1)
Cell.appendChild(document.createTextNode(' • '));
}
if (list.length){
Table.rows[row].style.display = Table.rows[0].style.display;
}else{
Table.rows[row].style.display = 'none';
}
if (cont){
var btntext = Table.getAttribute('data-moretext') || 'далее';
var btn = CreateButton(idx, null, btntext, null, 'float:right');
btn.firstChild.onclick = clickMore;
btn.dataTitle = ctTitle;
btn.dataCont = cont;
Cell.appendChild(btn);
}
if (row >= 0)
openNextLevel(idx, row);
}
if (!LocalFill(ctTitle, idx, toprow, row, cat))
GetCat(ctTitle, idx, row, cat, cont, asyncFill);
}
function LocalFill(ctTitle, idx, toprow, row, cat){ //заполнение статично указанными статьями
var Table = document.getElementById('cattreeTable' + idx);
var HCell = Table.rows[toprow].cells[0];
var Cell = Table.rows[row].cells[0];
var Tree = HCell.dataArtlist;
var TreeNode, subTree, a;
var list = [];
if (typeof Tree === 'undefined')
return false;
for (var i=0; TreeNode = Tree[i]; i++)
if (GetText(TreeNode.a).nodeValue == ctTitle){
subTree = TreeNode.subtree;
break;
}
if (cat)
Cell.dataArtlist = subTree;
for (i = 0; i < subTree.length; i++){
TreeNode = subTree[i];
if ((cat && TreeNode.subtree) || (!cat && (typeof TreeNode.subtree === 'undefined')))
list.push(TreeNode);
}
for (i = 0; i < list.length; i++){
a = list[i].a.cloneNode(true);
if (cat)
a.onclick = clickCat;
if (a.getAttribute('data-loadpage')){
LoadPage(a, Cell);
break;
}
if (i == 0){
Clear(Cell);
}
Cell.appendChild(a);
if (i < list.length - 1)
Cell.appendChild(document.createTextNode(' • '));
}
if (list.length){
Table.rows[row].style.display = Table.rows[0].style.display;
}else{
Table.rows[row].style.display = 'none';
}
if (row >= 0)
openNextLevel(idx, row);
return true;
}
function DecodeEntities(str){ //декодирует спецсимволы
div = document.createElement('div');
div.innerHTML = str;
return div.textContent;
}
function LoadPage(a, Cell){ //загружает в ячейку часть страницы ВП
var page = a.getAttribute('data-loadpage');
var Table = Cell.parentNode.parentNode.parentNode;
var strelementid = a.getAttribute('data-loadpage-outerelement') || Table.getAttribute('data-loadpage-outerelement');
strelementid = DecodeEntities(strelementid);
if (!strelementid.length)
strelementid = "body";
jQuery.ajax({
url: mw.config.get('wgScript') + '?' + $.param({title: page}),
dataType: 'html'
})
.done(function(html) {
var startpos = html.indexOf(strelementid);
if (~startpos){
var regexp = /\w+/g;
regexp.lastIndex = html.lastIndexOf("<", startpos) + 1;
var res = regexp.exec(html);
var oTag = res[0];
var cTag = '/' + oTag;
startpos = html.indexOf(">", startpos);
var endpos = startpos;
var lvl = 1;
while ( ~(endpos = html.indexOf("<", endpos + 1)) ){
if (html.indexOf(cTag, endpos + 1) == endpos + 1)
lvl--;
if (html.indexOf(oTag, endpos + 1) == endpos + 1)
lvl++;
if (!lvl)
break;
}
if (~endpos){
html = html.substring(startpos + 1, endpos);
a.insertAdjacentHTML('beforeEnd', html);
Clear(Cell);
Cell.appendChild(a);
}
}
});
}
function openNextLevel(idx, row){ //автоматически открывает некоторый следующий уровень при первом показе таблицы
var i, strpath, strsubcat;
var Table = document.getElementById('cattreeTable' + idx);
if (Table.hasAttribute('data-open')){
strpath = Table.getAttribute('data-open');
if ( ~(i = strpath.indexOf('\\')) ){
strsubcat = strpath.substring(0, i);
strpath = strpath.substring(i+1);
Table.setAttribute('data-open',strpath);
}else{
strsubcat = strpath;
Table.removeAttribute('data-open');
}
showSubtree(strsubcat, idx, row);
}
}
function clickCat(event){ // нажатие на категорию (открывает подуровень или сворачивает)
event = event || window.event;
var a = event.target || event.srcElement;
var Text = GetText(a);
var Row = a.parentNode.parentNode;
var row = Row.rowIndex;
var Table = Row.parentNode.parentNode;
var idx = Table.id.slice(12);
if (row){
showSubtree(Text.nodeValue, idx, row);
}else{
displayTable(idx, 0);
}
return false;
}
function clickMore(event){ //нажатие далее (загружает следующие 200)
event = event || window.event;
var btn = event.target || event.srcElement;
btn = btn.parentNode;
var Row = btn.parentNode.parentNode;
var row = Row.rowIndex;
var Table = Row.parentNode.parentNode;
var idx = Table.id.slice(12);
var cat = (row != (Table.rows.length - 1));
FillCell(btn.dataTitle, idx, 0, row, cat, btn.dataCont);
return false;
}
function CreateButton(idx, classname, btntext, href, csstext){ //создаёт «кнопку»
var btn = document.createElement('span');
btn.style.cssText = 'font-weight:normal; font-size:smaller; ' + csstext;
if (classname)
btn.id = classname + idx;
var a = document.createElement('a');
if (href)
a.href = href;
a.appendChild(document.createTextNode(btntext));
btn.appendChild(a);
return btn;
}
function CreateHLink(Text, idx){ //создаёт заголовок высшего уровня (впрочем, идентичный подзаголовкам)
var a = document.createElement('a');
a.href = '/wiki/' + encodeURIComponent('Категория:'+Text.nodeValue);
a.onclick = clickCat;
a.title = 'Категория:'+Text.nodeValue;
a.appendChild(Text);
return a;
}
function GetArt(Artlist, text){ //получить элемент А из списка с соотв. текстом
for (var i=0; i < Artlist.length; i++)
if (GetText(Artlist[i].a).nodeValue == text)
return Artlist[i].a;
return Artlist[Artlist.length - 1].a;
}
function cattreeTables(){ //вход
var Table, HRow, HCell, Text, a, btn, btntext, parentcat, listtext, idx = 0, list = [], artlist;
var Cattrees = document.getElementsByClassName('cattree')
var asyncTitlelist = function(idx, list){
var Table = document.getElementById('cattreeTable' + idx)
Table.dataCatlist = list
}
for (var i = 0; Table=Cattrees[i]; i++){
if (Table.tagName!='TABLE') continue;
if (!(HRow = Table.rows[0])) continue;
if (!(HCell = HRow.cells[0])) continue;
if (PrepareFullArticleList(HCell)){
Text = GetText(HCell);
artlist = HCell.dataArtlist;
a = GetArt(artlist, (Text) ? Text.nodeValue : null);
a.onclick = clickCat;
HCell.insertBefore(a,HCell.firstChild);
if (Text)
HCell.removeChild(Text);
}else{
Text = GetText(HCell);
artlist = null;
a = CreateHLink(Text, idx);
HCell.appendChild(a);
}
Table.id = 'cattreeTable' + idx;
if ((parentcat = Table.getAttribute('data-parent')) || (listtext = Table.getAttribute('data-catlist')) || (artlist && (artlist.length > 1))){
if (parentcat){
GetCat(parentcat, idx, -1, true, null, asyncTitlelist);
}else if(listtext){
Table.dataCatlist = listtext.split('\\');
}else{
for (var j = 0; j < artlist.length; j++)
list[j] = GetText(artlist[j].a).nodeValue;
Table.dataCatlist = list;
}
btntext = Table.getAttribute('data-prevtext') || 'пред.';
btn = CreateButton(idx, 'prevcatButton', btntext, 'javascript:nextHeader(' + idx + ', -1)', 'float:left');
HCell.appendChild(btn);
btntext = Table.getAttribute('data-nexttext') || 'след.';
btn = CreateButton(idx, 'nextcatButton', btntext, 'javascript:nextHeader(' + idx + ', 1)', 'float:right');
HCell.appendChild(btn);
}else{
btntext = Table.getAttribute('data-expandtext') || 'показать';
btn = CreateButton(idx, 'hidecatButton', btntext, 'javascript:displayTable(' + idx + ', 1)', 'float:right');
HCell.appendChild(btn);
}
Table.style.display = 'table';
if (!Table.classList.contains('collapsed'))
displayTable(idx, 0);
idx++
}
}
function PrepareFullArticleList(HCell){ //если имеется список статей, подготавливаем (используется вместо получения из категорий)
var Span, Child, Tree=[], TreeLevels=[Tree], TreeNode, TreeBranch, str, a;
for (var i = 0; Span = HCell.children[i]; i++){
if (Span.tagName == 'SPAN'){
for (var j = 0; Child = Span.childNodes[j]; j++){
if (Child.nodeType == 1){
TreeNode = new Object();
TreeNode.a = Child;
TreeLevels[TreeLevels.length-1].push(TreeNode);
}
if (Child.nodeType == 3){
str = Child.nodeValue;
if (~str.indexOf('(')){
TreeBranch = new Array();
TreeNode.subtree = TreeBranch;
TreeLevels.push(TreeBranch);
}
if (~str.indexOf(')'))
for (var k = 0; k < str.length; k++)
if (str[k] == ')'){
TreeBranch = TreeLevels.pop();
elementsToA(TreeBranch);
}
}
}
break;
}
}
elementsToA(Tree);
if (Tree.length)
HCell.dataArtlist = Tree;
return Tree.length;
}
function elementsToA(elements){ //преобразует элементы, использующиеся в качестве заголовков в А
var a;
for (var i = 0; i < elements.length; i++){
if ((elements[i].subtree) && (elements[i].a.tagName != 'A')){
a = document.createElement('a');
a.appendChild(GetText(elements[i].a));
elements[i].a = a;
}
}
}
function GetRowsCount(Table){ //считает количество непустых строк в таблице
var Cell, rowscount = 0;
for (var i = 1; i < Table.rows.length; i++){
Cell = Table.rows[i].cells[0];
if (Cell.firstChild)
rowscount++;
}
return rowscount;
}
function IsHidden(Table){ //скрыты строки кроме верхней
var Row;
var hidden = true;
for (var i = 1; Row = Table.rows[i]; i++)
if (Row.style.display != 'none'){
hidden = false;
break;
}
return hidden
}
function HasBold(Cell){ //в ячейке имеются жирные элементы (развёрнут подуровень)
var Child;
var bold = false;
for (var i = 0; Child = Cell.children[i]; i++){
if (Child.style.fontWeight == 'bold'){
bold = true;
break;
}
}
return bold;
}
function nextHeader(idx, step){ //скролинг заголовков высшего уровня
var Child, HCell, text, a, btn;
var Table = document.getElementById('cattreeTable' + idx);
HCell = Table.rows[0].cells[0];
Child = HCell.firstChild;
text = GetText(Child).nodeValue
var ind = Table.dataCatlist.indexOf(text);
var i = ind + step;
btn = document.getElementById('prevcatButton' + idx);
if (i <= 0){
i = 0;
btn.firstChild.disable = true;
}else
btn.firstChild.disable = false;
btn = document.getElementById('nextcatButton' + idx)
if (i >= Table.dataCatlist.length - 1){
i = Table.dataCatlist.length - 1;
btn.firstChild.disable = true;
}else
btn.firstChild.disable = false;
if (i != ind){
text = Table.dataCatlist[i];
if (HCell.dataArtlist){
a = GetArt(HCell.dataArtlist, text);
a.onclick = clickCat;
}else{
a = CreateHLink(document.createTextNode(text), idx);
}
HCell.insertBefore(a, Child);
HCell.removeChild(Child);
if (!IsHidden(Table))
showSubtree(text, idx, 0);
}
}
function ShowTable(Table, state){ //показывает или скрывает строки, кроме верхней
var Row;
for (var i = 1; Row = Table.rows[i]; i++)
if (state){
if (Row.cells[0].children.length)
Row.style.display = Table.rows[0].style.display
}else{
Row.style.display = 'none'
}
}
function displayTable(idx, mode){ //сворачивание и разворачивание таблицы
var Cell, btnstate, btntext, btn;
var Table = document.getElementById('cattreeTable' + idx);
var ctTitle = GetText(Table.rows[0].cells[0].firstChild).nodeValue;
var rowscount = GetRowsCount(Table);
var hidden = IsHidden(Table);
if (mode){
if (!rowscount){
btnstate = true;
showSubtree(ctTitle, idx, 0);
}else{
btnstate = (hidden);
ShowTable(Table, btnstate);
}
}else{
if ((HasBold(Table.rows[1].cells[0])) || (hidden)){
btnstate = true;
showSubtree(ctTitle, idx, 0);
}else{
btnstate = false;
ShowTable(Table, btnstate);
}
}
if (btn = document.getElementById('hidecatButton' + idx)){
if (btnstate)
btntext = Table.getAttribute('data-collapsetext') || 'свернуть';
else
btntext = Table.getAttribute('data-expandtext') || 'показать';
var Text = GetText(btn.firstChild);
Text.nodeValue = btntext;
}
}
function showSubtree(ctTitle, idx, toprow){ //вывести подуровень (строка заголовков и строка данных)
var Row, Cell, Child, Text;
var Table = document.getElementById('cattreeTable' + idx);
var nextrow = null;
var datarow = Table.rows.length-1;
if (datarow > 1){
nextrow = toprow + 1;
if ((datarow - nextrow) < 1){
Row = Table.insertRow(datarow++);
Row.style.cssText = Table.rows[1].style.cssText;
Row.style.display = 'none';
Cell = Row.insertCell(0);
Cell.style.cssText = Table.rows[1].cells[0].style.cssText;
}
}
if (toprow > 0){
Cell = Table.rows[toprow].cells[0];
for (var i = 0; Child = Cell.children[i]; i++){
Text = GetText(Child);
if ((Text) && (Text.nodeValue == ctTitle))
Child.style.fontWeight = 'bold';
else
Child.style.fontWeight = 'normal';
}
}
if (nextrow != null){
for (i = nextrow + 1; i < datarow; i++){
Table.rows[i].style.display = 'none';
Clear(Table.rows[i].cells[0]);
}
FillCell(ctTitle, idx, toprow, nextrow, true);
}
if (!Table.hasAttribute('data-open'))
FillCell(ctTitle, idx, toprow, datarow, false);
}