2 b7ab6d17 2025-07-18 jrmu JavaScript utilities for PmWiki
3 b7ab6d17 2025-07-18 jrmu (c) 2009-2022 Petko Yotov www.pmwiki.org/petko
4 b7ab6d17 2025-07-18 jrmu based on PmWiki addons DeObMail, AutoTOC and Ape
5 b7ab6d17 2025-07-18 jrmu licensed GNU GPLv2 or any more recent version released by the FSF.
7 b7ab6d17 2025-07-18 jrmu libsortable() "Sortable tables" adapted for PmWiki from
8 b7ab6d17 2025-07-18 jrmu a Public Domain event listener by github.com/tofsjonas
11 b7ab6d17 2025-07-18 jrmu (function(){
12 b7ab6d17 2025-07-18 jrmu function aE(el, ev, fn) {
13 b7ab6d17 2025-07-18 jrmu if(typeof el == 'string') el = dqsa(el);
14 b7ab6d17 2025-07-18 jrmu for(var i=0; i<el.length; i++) el[i].addEventListener(ev, fn);
16 b7ab6d17 2025-07-18 jrmu function dqs(str) { return document.querySelector(str); }
17 b7ab6d17 2025-07-18 jrmu function dqsa(str) { return document.querySelectorAll(str); }
18 b7ab6d17 2025-07-18 jrmu function tap(q, fn) { aE(q, 'click', fn); };
19 b7ab6d17 2025-07-18 jrmu function pf(x) {var y = parseFloat(x); return isNaN(y)? 0:y; }
20 b7ab6d17 2025-07-18 jrmu function zpad(n) {return (n<10)?"0"+n : n; }
21 b7ab6d17 2025-07-18 jrmu function adjbb(el, html) { el.insertAdjacentHTML('beforebegin', html); }
22 b7ab6d17 2025-07-18 jrmu function adjbe(el, html) { el.insertAdjacentHTML('beforeend', html); }
23 b7ab6d17 2025-07-18 jrmu function adjab(el, html) { el.insertAdjacentHTML('afterbegin', html); }
24 b7ab6d17 2025-07-18 jrmu function adjae(el, html) { el.insertAdjacentHTML('afterend', html); }
25 b7ab6d17 2025-07-18 jrmu function getLS(key, parse) {
26 b7ab6d17 2025-07-18 jrmu var x = window.localStorage.getItem(key)|| null;
27 b7ab6d17 2025-07-18 jrmu return parse ? JSON.parse(x) : x;}
28 b7ab6d17 2025-07-18 jrmu function setLS(key, value) {
29 b7ab6d17 2025-07-18 jrmu if (typeof value == 'object') value = JSON.stringify(value);
30 b7ab6d17 2025-07-18 jrmu window.localStorage.setItem(key, value);}
31 b7ab6d17 2025-07-18 jrmu function PHSC(x) { return x.replace(/[&]/g, '&').replace(/[<]/g, '<').replace(/[>]/g, '>'); }
33 b7ab6d17 2025-07-18 jrmu var __script__, wikitext;
34 b7ab6d17 2025-07-18 jrmu var log = console.log;
36 b7ab6d17 2025-07-18 jrmu function PmXMail() {
37 b7ab6d17 2025-07-18 jrmu var els = document.querySelectorAll('span._pmXmail');
38 b7ab6d17 2025-07-18 jrmu var LinkFmt = '<a href="%u" class="mail">%t</a>';
40 b7ab6d17 2025-07-18 jrmu for(var i=0; i<els.length; i++) {
41 b7ab6d17 2025-07-18 jrmu var x = els[i].querySelector('span._t');
42 b7ab6d17 2025-07-18 jrmu var txt = cb_mail(x.innerHTML);
43 b7ab6d17 2025-07-18 jrmu var y = els[i].querySelector('span._m');
44 b7ab6d17 2025-07-18 jrmu var url = cb_mail(y.innerHTML.replace(/^ *-> */, ''));
46 b7ab6d17 2025-07-18 jrmu if(!url) url = 'mailto:'+txt.replace(/^mailto:/, '');
48 b7ab6d17 2025-07-18 jrmu url = url.replace(/"/g, '%22').replace(/'/g, '%27');
49 b7ab6d17 2025-07-18 jrmu var html = LinkFmt.replace(/%u/g, url).replace(/%t/g, txt);
50 b7ab6d17 2025-07-18 jrmu els[i].innerHTML = html;
53 b7ab6d17 2025-07-18 jrmu function cb_mail(x){
54 b7ab6d17 2025-07-18 jrmu return x.replace( /<span class=(['"]?)_d\1>[^<]+<\/span>/ig, '.')
55 b7ab6d17 2025-07-18 jrmu .replace( /<span class=(['"]?)_a\1>[^<]+<\/span>/ig, '@');
58 b7ab6d17 2025-07-18 jrmu function is_toc_heading(el) {
59 b7ab6d17 2025-07-18 jrmu if(el.offsetParent === null) {return false;} // hidden
60 b7ab6d17 2025-07-18 jrmu if(el.closest('.notoc,.markup2')) {return false;}
61 b7ab6d17 2025-07-18 jrmu return true;
63 b7ab6d17 2025-07-18 jrmu function posy(el) {
64 b7ab6d17 2025-07-18 jrmu var top = 0;
65 b7ab6d17 2025-07-18 jrmu if (el.offsetParent) {
67 b7ab6d17 2025-07-18 jrmu top += el.offsetTop;
68 b7ab6d17 2025-07-18 jrmu } while (el = el.offsetParent);
73 b7ab6d17 2025-07-18 jrmu function any_id(h) {
74 b7ab6d17 2025-07-18 jrmu if(h.id) {return h.id;} // %id=anchor%
75 b7ab6d17 2025-07-18 jrmu var a = h.querySelector('a[id]'); // inline [[#anchor]]
76 b7ab6d17 2025-07-18 jrmu if(a && a.id) {return a.id;}
77 b7ab6d17 2025-07-18 jrmu var prev = h.previousElementSibling;
78 b7ab6d17 2025-07-18 jrmu if(prev) { // [[#anchor]] before !!heading
79 b7ab6d17 2025-07-18 jrmu var a = prev.querySelectorAll('a[id]');
80 b7ab6d17 2025-07-18 jrmu if(a.length) {
81 b7ab6d17 2025-07-18 jrmu last = a[a.length-1];
82 b7ab6d17 2025-07-18 jrmu if(last.id && ! last.nextElementSibling) {
83 b7ab6d17 2025-07-18 jrmu var atop = posy(last) + last.offsetHeight;
84 b7ab6d17 2025-07-18 jrmu var htop = posy(h);
85 b7ab6d17 2025-07-18 jrmu if( Math.abs(htop-atop)<20 ) {
86 b7ab6d17 2025-07-18 jrmu h.appendChild(last);
87 b7ab6d17 2025-07-18 jrmu return last.id;
92 b7ab6d17 2025-07-18 jrmu return false;
94 b7ab6d17 2025-07-18 jrmu function inittoggle() {
95 b7ab6d17 2025-07-18 jrmu var tnext = __script__.dataset.toggle;
96 b7ab6d17 2025-07-18 jrmu if(! tnext) { return; }
97 b7ab6d17 2025-07-18 jrmu var x = dqsa(tnext);
98 b7ab6d17 2025-07-18 jrmu if(! x.length) return;
99 b7ab6d17 2025-07-18 jrmu for(var i=0; i<x.length; i++) togglenext(x[i]);
100 b7ab6d17 2025-07-18 jrmu tap(tnext, togglenext);
101 b7ab6d17 2025-07-18 jrmu tap('.pmtoggleall', toggleall);
103 b7ab6d17 2025-07-18 jrmu function togglenext(z) {
104 b7ab6d17 2025-07-18 jrmu var el = z.type == 'click' ? this : z;
105 b7ab6d17 2025-07-18 jrmu var attr = el.dataset.pmtoggle=='closed' ? 'open' : 'closed';
106 b7ab6d17 2025-07-18 jrmu el.dataset.pmtoggle = attr;
108 b7ab6d17 2025-07-18 jrmu function toggleall(){
109 b7ab6d17 2025-07-18 jrmu var curr = this.dataset.pmtoggleall;
110 b7ab6d17 2025-07-18 jrmu if(!curr) curr = 'closed';
111 b7ab6d17 2025-07-18 jrmu var toggles = dqsa('*[data-pmtoggle="'+curr+'"]');
112 b7ab6d17 2025-07-18 jrmu var next = curr=='closed' ? 'open' : 'closed';
113 b7ab6d17 2025-07-18 jrmu for(var i=0; i<toggles.length; i++) {
114 b7ab6d17 2025-07-18 jrmu toggles[i].dataset.pmtoggle = next;
116 b7ab6d17 2025-07-18 jrmu var all = dqsa('.pmtoggleall');
117 b7ab6d17 2025-07-18 jrmu for(var i=0; i<all.length; i++) {
118 b7ab6d17 2025-07-18 jrmu all[i].dataset.pmtoggleall = next;
122 b7ab6d17 2025-07-18 jrmu function autotoc() {
123 b7ab6d17 2025-07-18 jrmu if(dqs('.noPmTOC')) { return; } // (:notoc:) in page
124 b7ab6d17 2025-07-18 jrmu var dtoc = __script__.dataset.pmtoc;
125 b7ab6d17 2025-07-18 jrmu try {dtoc = JSON.parse(dtoc);} catch(e) {dtoc = false;}
126 b7ab6d17 2025-07-18 jrmu if(! dtoc) { return; } // error
128 b7ab6d17 2025-07-18 jrmu if(! dtoc.Enable || !dtoc.MaxLevel) { return; } // disabled
130 b7ab6d17 2025-07-18 jrmu if(dtoc.NumberedHeadings) {
131 b7ab6d17 2025-07-18 jrmu var specs = dtoc.NumberedHeadings.toString().split(/\./g);
132 b7ab6d17 2025-07-18 jrmu for(var i=0; i<specs.length; i++) {
133 b7ab6d17 2025-07-18 jrmu if(specs[i].match(/^[1AI]$/i)) numheadspec[i] = specs[i];
137 b7ab6d17 2025-07-18 jrmu var query = [];
138 b7ab6d17 2025-07-18 jrmu for(var i=1; i<=dtoc.MaxLevel; i++) {
139 b7ab6d17 2025-07-18 jrmu query.push('h'+i);
141 b7ab6d17 2025-07-18 jrmu if(dtoc.EnableQMarkup) query.push('p.question');
142 b7ab6d17 2025-07-18 jrmu var pageheadings = wikitext.querySelectorAll(query.join(','));
143 b7ab6d17 2025-07-18 jrmu if(!pageheadings.length) { return; }
145 b7ab6d17 2025-07-18 jrmu var toc_headings = [ ];
146 b7ab6d17 2025-07-18 jrmu var minlevel = 1000, hcache = [ ];
147 b7ab6d17 2025-07-18 jrmu for(var i=0; i<pageheadings.length; i++) {
148 b7ab6d17 2025-07-18 jrmu var h = pageheadings[i];
149 b7ab6d17 2025-07-18 jrmu if(! is_toc_heading(h)) {continue;}
150 b7ab6d17 2025-07-18 jrmu toc_headings.push(h);
152 b7ab6d17 2025-07-18 jrmu if(! toc_headings.length) return;
154 b7ab6d17 2025-07-18 jrmu var tocdiv = dqs('.PmTOCdiv');
155 b7ab6d17 2025-07-18 jrmu var shouldmaketoc = ( tocdiv || (toc_headings.length >= dtoc.MinNumber && dtoc.MinNumber != -1)) ? 1:0;
156 b7ab6d17 2025-07-18 jrmu if(!dtoc.NumberedHeadings && !shouldmaketoc) return;
158 b7ab6d17 2025-07-18 jrmu for(var i=0; i<toc_headings.length; i++) {
159 b7ab6d17 2025-07-18 jrmu var h = toc_headings[i];
160 b7ab6d17 2025-07-18 jrmu var level = pf(h.tagName.substring(1));
161 b7ab6d17 2025-07-18 jrmu if(! level) level = 6;
162 b7ab6d17 2025-07-18 jrmu minlevel = Math.min(minlevel, level);
163 b7ab6d17 2025-07-18 jrmu var id = any_id(h);
164 b7ab6d17 2025-07-18 jrmu hcache.push([h, level, id]);
167 b7ab6d17 2025-07-18 jrmu prevlevel = 0;
168 b7ab6d17 2025-07-18 jrmu var html = '';
169 b7ab6d17 2025-07-18 jrmu for(var i=0; i<hcache.length; i++) {
170 b7ab6d17 2025-07-18 jrmu var hc = hcache[i];
171 b7ab6d17 2025-07-18 jrmu var actual_level = hc[1] - minlevel;
172 b7ab6d17 2025-07-18 jrmu // if(actual_level>prevlevel+1) actual_level = prevlevel+1;
173 b7ab6d17 2025-07-18 jrmu // prevlevel = actual_level;
175 b7ab6d17 2025-07-18 jrmu var currnb = numberheadings(actual_level);
176 b7ab6d17 2025-07-18 jrmu if(! hc[2]) {
177 b7ab6d17 2025-07-18 jrmu hc[2] = 'toc-'+currnb.replace(/\.+$/g, '');
178 b7ab6d17 2025-07-18 jrmu hc[0].id = hc[2];
180 b7ab6d17 2025-07-18 jrmu if(dtoc.NumberedHeadings && currnb.length) adjab(hc[0], currnb+' ');
182 b7ab6d17 2025-07-18 jrmu if(! shouldmaketoc) { continue; }
183 b7ab6d17 2025-07-18 jrmu var txt = hc[0].textContent.trim().replace(/</g, '<');
184 b7ab6d17 2025-07-18 jrmu var sectionedit = hc[0].querySelector('.sectionedit');
185 b7ab6d17 2025-07-18 jrmu if(sectionedit) {
186 b7ab6d17 2025-07-18 jrmu var selength = sectionedit.textContent.length;
187 b7ab6d17 2025-07-18 jrmu txt = txt.slice(0, -selength);
190 b7ab6d17 2025-07-18 jrmu html += '<a class="pmtoc-indent'+ actual_level
191 b7ab6d17 2025-07-18 jrmu + '" href="#'+hc[2]+'">' + txt + '</a>\n';
192 b7ab6d17 2025-07-18 jrmu if(dtoc.EnableBacklinks)
193 b7ab6d17 2025-07-18 jrmu adjbe(hc[0], ' <a class="back-arrow" href="#_toc">↑</a>');
197 b7ab6d17 2025-07-18 jrmu if(! shouldmaketoc) return;
199 b7ab6d17 2025-07-18 jrmu html = "<b>"+dtoc.contents+"</b> "
200 b7ab6d17 2025-07-18 jrmu +"[<input type='checkbox' id='PmTOCchk'><label for='PmTOCchk'>"
201 b7ab6d17 2025-07-18 jrmu +"<span class='pmtoc-show'>"+dtoc.show+"</span>"
202 b7ab6d17 2025-07-18 jrmu +"<span class='pmtoc-hide'>"+dtoc.hide+"</span></label>]"
203 b7ab6d17 2025-07-18 jrmu +"<div class='PmTOCtable'>" + html + "</div>";
205 b7ab6d17 2025-07-18 jrmu if(!tocdiv) {
206 b7ab6d17 2025-07-18 jrmu var wrap = "<div class='PmTOCdiv'></div>";
207 b7ab6d17 2025-07-18 jrmu if(dtoc.ParentElement && dqs(dtoc.ParentElement)) {
208 b7ab6d17 2025-07-18 jrmu adjab(dqs(dtoc.ParentElement), wrap);
211 b7ab6d17 2025-07-18 jrmu adjbb(hcache[0][0], wrap);
213 b7ab6d17 2025-07-18 jrmu tocdiv = dqs('.PmTOCdiv');
216 b7ab6d17 2025-07-18 jrmu if(!tocdiv) return; // error?
217 b7ab6d17 2025-07-18 jrmu tocdiv.className += " frame";
218 b7ab6d17 2025-07-18 jrmu tocdiv.id = '_toc';
220 b7ab6d17 2025-07-18 jrmu tocdiv.innerHTML = html;
222 b7ab6d17 2025-07-18 jrmu if(getLS('closeTOC')) { dqs('#PmTOCchk').checked = true; }
223 b7ab6d17 2025-07-18 jrmu aE('#PmTOCchk', 'change', function(e){
224 b7ab6d17 2025-07-18 jrmu setLS('closeTOC', this.checked ? "close" : '');
227 b7ab6d17 2025-07-18 jrmu var hh = location.hash;
228 b7ab6d17 2025-07-18 jrmu if(hh.length>1) {
229 b7ab6d17 2025-07-18 jrmu var cc = document.getElementById(hh.substring(1));
230 b7ab6d17 2025-07-18 jrmu if(cc) cc.scrollIntoView();
234 b7ab6d17 2025-07-18 jrmu var numhead = [0, 0, 0, 0, 0, 0, 0];
235 b7ab6d17 2025-07-18 jrmu var numheadspec = '1 1 1 1 1 1 1'.split(/ /g);
236 b7ab6d17 2025-07-18 jrmu function numhead_alpha(n, upper) {
237 b7ab6d17 2025-07-18 jrmu if(!n) return '_';
238 b7ab6d17 2025-07-18 jrmu var alpha = '', mod, start = upper=='A' ? 65 : 97;
239 b7ab6d17 2025-07-18 jrmu while (n>0) {
240 b7ab6d17 2025-07-18 jrmu mod = (n-1)%26;
241 b7ab6d17 2025-07-18 jrmu alpha = String.fromCharCode(start + mod) + '' + alpha;
242 b7ab6d17 2025-07-18 jrmu n = (n-mod)/26 | 0;
244 b7ab6d17 2025-07-18 jrmu return alpha;
246 b7ab6d17 2025-07-18 jrmu function numhead_roman(n, upper) {
247 b7ab6d17 2025-07-18 jrmu if(!n) return '_';
248 b7ab6d17 2025-07-18 jrmu // partially based on http://blog.stevenlevithan.com/?p=65#comment-16107
249 b7ab6d17 2025-07-18 jrmu var lst = [ [1000,'M'], [900,'CM'], [500,'D'], [400,'CD'], [100,'C'], [90,'XC'],
250 b7ab6d17 2025-07-18 jrmu [50,'L'], [40,'XL'], [10,'X'], [9,'IX'], [5,'V'], [4,'IV'], [1,'I'] ];
251 b7ab6d17 2025-07-18 jrmu var roman = '';
252 b7ab6d17 2025-07-18 jrmu for(var i=0; i<lst.length; i++) {
253 b7ab6d17 2025-07-18 jrmu while(n>=lst[i][0]) {
254 b7ab6d17 2025-07-18 jrmu roman += lst[i][1];
255 b7ab6d17 2025-07-18 jrmu n -= lst[i][0];
258 b7ab6d17 2025-07-18 jrmu return (upper == 'I') ? roman : roman.toLowerCase();
261 b7ab6d17 2025-07-18 jrmu function numberheadings(n) {
262 b7ab6d17 2025-07-18 jrmu if(n<numhead[6]) for(var j=numhead[6]; j>n; j--) numhead[j]=0;
263 b7ab6d17 2025-07-18 jrmu numhead[6]=n;
264 b7ab6d17 2025-07-18 jrmu numhead[n]++;
265 b7ab6d17 2025-07-18 jrmu var qq = '';
266 b7ab6d17 2025-07-18 jrmu for (var j=0; j<=n; j++) {
267 b7ab6d17 2025-07-18 jrmu var curr = numhead[j];
268 b7ab6d17 2025-07-18 jrmu var currspec = numheadspec[j];
269 b7ab6d17 2025-07-18 jrmu if(currspec.match(/a/i)) { curr = numhead_alpha(curr, currspec); }
270 b7ab6d17 2025-07-18 jrmu else if(currspec.match(/i/i)) { curr = numhead_roman(curr, currspec); }
272 b7ab6d17 2025-07-18 jrmu qq+=curr+".";
277 b7ab6d17 2025-07-18 jrmu function makesortable() {
278 b7ab6d17 2025-07-18 jrmu if(! pf(__script__.dataset.sortable)) return;
279 b7ab6d17 2025-07-18 jrmu var tables = dqsa('table.sortable,table.sortable-footer');
280 b7ab6d17 2025-07-18 jrmu for(var i=0; i<tables.length; i++) {
281 b7ab6d17 2025-07-18 jrmu // non-pmwiki-core table, already ready
282 b7ab6d17 2025-07-18 jrmu if(tables[i].querySelector('thead')) continue;
284 b7ab6d17 2025-07-18 jrmu tables[i].classList.add('sortable'); // for .sortable-footer
286 b7ab6d17 2025-07-18 jrmu var thead = document.createElement('thead');
287 b7ab6d17 2025-07-18 jrmu tables[i].insertBefore(thead, tables[i].firstChild);
289 b7ab6d17 2025-07-18 jrmu var rows = tables[i].querySelectorAll('tr');
290 b7ab6d17 2025-07-18 jrmu thead.appendChild(rows[0]);
291 b7ab6d17 2025-07-18 jrmu var tbody = tables[i].querySelector('tbody');
292 b7ab6d17 2025-07-18 jrmu if(! tbody) {
293 b7ab6d17 2025-07-18 jrmu tbody = tables[i].appendChild(document.createElement('tbody'));
294 b7ab6d17 2025-07-18 jrmu for(var r=1; r<rows.length; r++) tbody.appendChild(rows[r]);
296 b7ab6d17 2025-07-18 jrmu if(tables[i].className.match(/sortable-footer/)) {
297 b7ab6d17 2025-07-18 jrmu var tfoot = tables[i].appendChild(document.createElement('tfoot'));
298 b7ab6d17 2025-07-18 jrmu tfoot.appendChild(rows[rows.length-1]);
300 b7ab6d17 2025-07-18 jrmu mkdatasort(rows);
302 b7ab6d17 2025-07-18 jrmu libsortable();
304 b7ab6d17 2025-07-18 jrmu function mkdatasort(rows) {
305 b7ab6d17 2025-07-18 jrmu var hcells = rows[0].querySelectorAll('th,td');
306 b7ab6d17 2025-07-18 jrmu var specialsort = [], span;
307 b7ab6d17 2025-07-18 jrmu for(var i=0; i<hcells.length; i++) {
308 b7ab6d17 2025-07-18 jrmu sortspan = hcells[i].querySelector('.sort-number,.sort-number-us,.sort-date');
309 b7ab6d17 2025-07-18 jrmu if(sortspan) specialsort[i] = sortspan.className;
311 b7ab6d17 2025-07-18 jrmu if(! specialsort.length) return;
312 b7ab6d17 2025-07-18 jrmu for(var i=1; i<rows.length; i++) {
313 b7ab6d17 2025-07-18 jrmu var cells = rows[i].querySelectorAll('td,th');
315 b7ab6d17 2025-07-18 jrmu for(var j=0; j<cells.length && j<specialsort.length; j++) {
316 b7ab6d17 2025-07-18 jrmu if(! specialsort[j]) continue;
317 b7ab6d17 2025-07-18 jrmu var t = cells[j].innerText, ds = '';
318 b7ab6d17 2025-07-18 jrmu if(specialsort[j] == 'sort-number-us') {ds = t.replace(/[^-.\d]+/g, ''); }
319 b7ab6d17 2025-07-18 jrmu else if(specialsort[j] == 'sort-number') {ds = t.replace(/[^-,\d]+/g, '').replace(/,/g, '.'); }
320 b7ab6d17 2025-07-18 jrmu else if(specialsort[j] == 'sort-date') {ds = new Date(t).getTime(); }
321 b7ab6d17 2025-07-18 jrmu if(ds) cells[j].setAttribute('data-sort', ds);
325 b7ab6d17 2025-07-18 jrmu function libsortable(){
326 b7ab6d17 2025-07-18 jrmu // adapted from Public Domain code by github.com/tofsjonas
327 b7ab6d17 2025-07-18 jrmu function getValue(obj) {
328 b7ab6d17 2025-07-18 jrmu obj = obj.cells[column_index];
329 b7ab6d17 2025-07-18 jrmu return obj.getAttribute('data-sort') || obj.innerText;
331 b7ab6d17 2025-07-18 jrmu function reclassify(element, cname) {
332 b7ab6d17 2025-07-18 jrmu element.classList.remove('dir-u', 'dir-d');
333 b7ab6d17 2025-07-18 jrmu if(cname) element.classList.add(cname);
335 b7ab6d17 2025-07-18 jrmu var column_index;
336 b7ab6d17 2025-07-18 jrmu document.addEventListener('click', function(e) {
337 b7ab6d17 2025-07-18 jrmu if(e.target.closest('a')) return; // links
338 b7ab6d17 2025-07-18 jrmu var element = e.target.closest('th');
339 b7ab6d17 2025-07-18 jrmu if (! element) return;
340 b7ab6d17 2025-07-18 jrmu var table = element.offsetParent;
341 b7ab6d17 2025-07-18 jrmu if (!table.classList.contains('sortable')) return;
343 b7ab6d17 2025-07-18 jrmu var cells = element.parentNode.cells;
344 b7ab6d17 2025-07-18 jrmu for (var i = 0; i < cells.length; i++) {
345 b7ab6d17 2025-07-18 jrmu if (cells[i] === element) {
346 b7ab6d17 2025-07-18 jrmu column_index = i;
348 b7ab6d17 2025-07-18 jrmu reclassify(cells[i], '');
351 b7ab6d17 2025-07-18 jrmu var cname = 'dir-d', reverse = false;
352 b7ab6d17 2025-07-18 jrmu if (element.classList.contains(cname)) {
353 b7ab6d17 2025-07-18 jrmu cname = 'dir-u';
354 b7ab6d17 2025-07-18 jrmu reverse = true;
356 b7ab6d17 2025-07-18 jrmu reclassify(element, cname);
357 b7ab6d17 2025-07-18 jrmu var tbody = table.tBodies[0];
358 b7ab6d17 2025-07-18 jrmu var rows = [];
359 b7ab6d17 2025-07-18 jrmu for(var r=0; r<tbody.rows.length; r++) rows.push(tbody.rows[r]);
361 b7ab6d17 2025-07-18 jrmu rows.sort(function(x, y) {
362 b7ab6d17 2025-07-18 jrmu var a = getValue(reverse? y:x),
363 b7ab6d17 2025-07-18 jrmu b = getValue(reverse? x:y);
364 b7ab6d17 2025-07-18 jrmu var c = a.localeCompare(b, undefined, {numeric: true, sensitivity: 'base'}),
366 b7ab6d17 2025-07-18 jrmu return isNaN(d) ? c : d;
368 b7ab6d17 2025-07-18 jrmu for (i = 0; i < rows.length; i++) {
369 b7ab6d17 2025-07-18 jrmu tbody.appendChild(rows[i]);
374 b7ab6d17 2025-07-18 jrmu function highlight_pre() {
375 b7ab6d17 2025-07-18 jrmu if(!__script__.dataset.highlight) return;
376 b7ab6d17 2025-07-18 jrmu if (typeof hljs == 'undefined') return;
378 b7ab6d17 2025-07-18 jrmu var x = dqsa('.highlight,.hlt');
380 b7ab6d17 2025-07-18 jrmu for(var i=0; i<x.length; i++) {
381 b7ab6d17 2025-07-18 jrmu if(x[i].className.match(/(^| )(pm|pmwiki)( |$)/)) { continue;} // core highlighter
382 b7ab6d17 2025-07-18 jrmu var pre = Array.from(x[i].querySelectorAll('pre,code'));
383 b7ab6d17 2025-07-18 jrmu var n = x[i].nextElementSibling;
384 b7ab6d17 2025-07-18 jrmu if (n && n.tagName == 'PRE') pre.push(n);
385 b7ab6d17 2025-07-18 jrmu for(var j=0; j<pre.length; j++) {
386 b7ab6d17 2025-07-18 jrmu pre[j].className += ' ' + x[i].className;
387 b7ab6d17 2025-07-18 jrmu var varlinks = pre[j].querySelectorAll('a.varlink');
388 b7ab6d17 2025-07-18 jrmu var vararray = {};
389 b7ab6d17 2025-07-18 jrmu for(var v=0; v<varlinks.length; v++) {
390 b7ab6d17 2025-07-18 jrmu vararray[varlinks[v].textContent] = varlinks[v].href;
393 b7ab6d17 2025-07-18 jrmu if(pre[j].children) pre[j].textContent = pre[j].textContent;
395 b7ab6d17 2025-07-18 jrmu hljs.highlightElement(pre[j]);
396 b7ab6d17 2025-07-18 jrmu var hlvars = pre[j].querySelectorAll('span.hljs-variable');
397 b7ab6d17 2025-07-18 jrmu for(var v=0; v<hlvars.length; v++) {
398 b7ab6d17 2025-07-18 jrmu var hlvar = hlvars[v].textContent;
399 b7ab6d17 2025-07-18 jrmu if(vararray.hasOwnProperty(hlvar)) {
400 b7ab6d17 2025-07-18 jrmu hlvars[v].innerHTML = '<a class="varlink" href="'+vararray[hlvar]+'">'+hlvar+'</a>';
407 b7ab6d17 2025-07-18 jrmu var Now, ltmode, daymonth, pagename;
408 b7ab6d17 2025-07-18 jrmu function fmtLocalTime(stamp) {
409 b7ab6d17 2025-07-18 jrmu var d = new Date(stamp*1000);
410 b7ab6d17 2025-07-18 jrmu var tooltip = PHSC(d.toLocaleString());
411 b7ab6d17 2025-07-18 jrmu if(ltmode == 2)
412 b7ab6d17 2025-07-18 jrmu return [tooltip];
413 b7ab6d17 2025-07-18 jrmu if(Now-d < 24*3600000)
414 b7ab6d17 2025-07-18 jrmu return [zpad(d.getHours()) + ':'+ zpad(d.getMinutes()), tooltip];
415 b7ab6d17 2025-07-18 jrmu var D = zpad(d.getDate()), M = zpad(d.getMonth()+1);
416 b7ab6d17 2025-07-18 jrmu var thedate = daymonth.replace(/%d/, D).replace(/%m/, M);
417 b7ab6d17 2025-07-18 jrmu if(Now-d < 334*24*3600000) return [thedate, tooltip];
418 b7ab6d17 2025-07-18 jrmu return [thedate + '/' + d.getFullYear(), tooltip];
421 b7ab6d17 2025-07-18 jrmu function localTimes() {
422 b7ab6d17 2025-07-18 jrmu ltmode = pf(__script__.dataset.localtimes);
423 b7ab6d17 2025-07-18 jrmu if(! ltmode) return;
424 b7ab6d17 2025-07-18 jrmu if(ltmode>=11) {
425 b7ab6d17 2025-07-18 jrmu var days = Math.floor(ltmode/10);
426 b7ab6d17 2025-07-18 jrmu ltmode = ltmode%10;
428 b7ab6d17 2025-07-18 jrmu else var days = 3;
429 b7ab6d17 2025-07-18 jrmu Now = new Date();
430 b7ab6d17 2025-07-18 jrmu pagename = __script__.dataset.fullname;
431 b7ab6d17 2025-07-18 jrmu var seenstamp = getLS('seenstamp', true);
432 b7ab6d17 2025-07-18 jrmu if(!seenstamp) seenstamp = {};
433 b7ab6d17 2025-07-18 jrmu var previous = seenstamp[pagename];
435 b7ab6d17 2025-07-18 jrmu var times = dqsa('time[datetime]');
437 b7ab6d17 2025-07-18 jrmu daymonth = new Date(2021, 11, 26, 17)
438 b7ab6d17 2025-07-18 jrmu .toLocaleDateString().match(/26.*12/)? '%d/%m': '%m/%d';
440 b7ab6d17 2025-07-18 jrmu var h72 = Now.getTime()/1000-days*24*3600;
442 b7ab6d17 2025-07-18 jrmu for(var i=0; i<times.length; i++) {
443 b7ab6d17 2025-07-18 jrmu var itemdate = new Date(times[i].dateTime);
444 b7ab6d17 2025-07-18 jrmu var stamp = Math.floor(itemdate.getTime()/1000);
446 b7ab6d17 2025-07-18 jrmu var li = times[i].closest('li');
447 b7ab6d17 2025-07-18 jrmu if (!li || !li.innerHTML.match(/<\/a> \. \. \. /)) {
448 b7ab6d17 2025-07-18 jrmu var x = fmtLocalTime(stamp);
449 b7ab6d17 2025-07-18 jrmu times[i].innerHTML = x[0];
450 b7ab6d17 2025-07-18 jrmu times[i].title = x[1] ? x[1]: itemdate.textContent;
453 b7ab6d17 2025-07-18 jrmu var link = li.querySelector('a');
454 b7ab6d17 2025-07-18 jrmu if(link.className.match(/createlinktext|wikilink|selflink/)) {
455 b7ab6d17 2025-07-18 jrmu var diff = link.href + '?action=diff#diff' + stamp;
456 b7ab6d17 2025-07-18 jrmu if(stamp >= h72) {
457 b7ab6d17 2025-07-18 jrmu var h = link.href + '?action=diff&fmt=rclist';
458 b7ab6d17 2025-07-18 jrmu adjbe(li, ' <b class="rcplus" data-url="'+h+'">+</b>');
461 b7ab6d17 2025-07-18 jrmu // recent uploads, other? we want to know when the link becomes "visited"
462 b7ab6d17 2025-07-18 jrmu else diff = link.href + '#diff' + stamp;
463 b7ab6d17 2025-07-18 jrmu times[i].innerHTML = '<a href="'+diff+'">'+times[i].innerHTML+'</a>';
466 b7ab6d17 2025-07-18 jrmu var difflinks = dqsa('a[href*="#diff"]'), diffcnt = 0;
467 b7ab6d17 2025-07-18 jrmu for(var i=0; i<difflinks.length; i++) {
468 b7ab6d17 2025-07-18 jrmu var link = difflinks[i];
469 b7ab6d17 2025-07-18 jrmu if(link.hostname != location.hostname) continue;
470 b7ab6d17 2025-07-18 jrmu var a = link.href.match(/[#]diff(\d+)$/);
471 b7ab6d17 2025-07-18 jrmu if(!a) continue;
473 b7ab6d17 2025-07-18 jrmu stamp = parseInt(a[1]);
474 b7ab6d17 2025-07-18 jrmu var x = fmtLocalTime(stamp);
476 b7ab6d17 2025-07-18 jrmu link.innerHTML = x[0];
477 b7ab6d17 2025-07-18 jrmu link.setAttribute('title', x[1] ? x[1]: link.textContent);
479 b7ab6d17 2025-07-18 jrmu var par = link.closest('li');
480 b7ab6d17 2025-07-18 jrmu if(!par) continue;
481 b7ab6d17 2025-07-18 jrmu par.insertBefore(link, par.firstChild);
482 b7ab6d17 2025-07-18 jrmu adjae(link, " ");
483 b7ab6d17 2025-07-18 jrmu if(previous && stamp>previous) par.classList.add('rcnew');
485 b7ab6d17 2025-07-18 jrmu if(!diffcnt) return;
486 b7ab6d17 2025-07-18 jrmu var pagetitle = dqs('#wikititle h1, h1.pagetitle');
487 b7ab6d17 2025-07-18 jrmu if(pagetitle) {
488 b7ab6d17 2025-07-18 jrmu var time = zpad(Now.getHours()) + ':'+ zpad(Now.getMinutes());
489 b7ab6d17 2025-07-18 jrmu adjbe(pagetitle, ' <span class="rcreload" title="Click to reload">'+time+'</span>');
490 b7ab6d17 2025-07-18 jrmu tap('.rcreload', function(){location.reload();});
492 b7ab6d17 2025-07-18 jrmu aE('.rcnew', 'mouseup', function(e){
493 b7ab6d17 2025-07-18 jrmu if(e.which == 2) this.classList.remove('rcnew');
495 b7ab6d17 2025-07-18 jrmu tap('.rcplus', function(e){
496 b7ab6d17 2025-07-18 jrmu var plus = this;
497 b7ab6d17 2025-07-18 jrmu plus.style.display = 'none';
498 b7ab6d17 2025-07-18 jrmu var basehref = plus.dataset.url.replace(/&fmt=rclist/, '#diff')
499 b7ab6d17 2025-07-18 jrmu .replace(/[&]/g, '&');
500 b7ab6d17 2025-07-18 jrmu var fmt = '<p class="outdent"><a href="'+basehref+'%d" title="%T">%t</a> %s</p>\n';
501 b7ab6d17 2025-07-18 jrmu fetch(plus.dataset.url)
502 b7ab6d17 2025-07-18 jrmu .then(function(resp){return resp.text();})
503 b7ab6d17 2025-07-18 jrmu .then(function(text){
504 b7ab6d17 2025-07-18 jrmu var lines = text.split(/\n/g);
505 b7ab6d17 2025-07-18 jrmu var out = '';
506 b7ab6d17 2025-07-18 jrmu for(var i=0; i<lines.length; i++) {
507 b7ab6d17 2025-07-18 jrmu a = lines[i].match(/^(\d+):(.*)$/);
508 b7ab6d17 2025-07-18 jrmu if(!a) continue;
509 b7ab6d17 2025-07-18 jrmu var time = fmtLocalTime(pf(a[1]));
510 b7ab6d17 2025-07-18 jrmu out += fmt.replace(/%d/, a[1]).replace(/%T/, time[1])
511 b7ab6d17 2025-07-18 jrmu .replace(/%t/, time[0]).replace(/%s/, a[2]);
513 b7ab6d17 2025-07-18 jrmu if(out) adjae(plus, out);
515 b7ab6d17 2025-07-18 jrmu .catch(log);
517 b7ab6d17 2025-07-18 jrmu if(dqs('form[name="authform"]') || location.href.match(/action=/)) return;
518 b7ab6d17 2025-07-18 jrmu seenstamp[pagename] = Math.floor(Now.getTime()/1000);
519 b7ab6d17 2025-07-18 jrmu setLS('seenstamp', seenstamp);
522 b7ab6d17 2025-07-18 jrmu function ready(){
523 b7ab6d17 2025-07-18 jrmu __script__ = dqs('script[src*="pmwiki-utils.js"]');
524 b7ab6d17 2025-07-18 jrmu wikitext = document.getElementById('wikitext');
525 b7ab6d17 2025-07-18 jrmu var fn = [autotoc, inittoggle, PmXMail, localTimes, highlight_pre, makesortable];
526 b7ab6d17 2025-07-18 jrmu fn.forEach(function(a){a();});
528 b7ab6d17 2025-07-18 jrmu if( document.readyState !== 'loading' ) ready();
529 b7ab6d17 2025-07-18 jrmu else window.addEventListener('DOMContentLoaded', ready);