xref: /template/mikio/assets/mikio.js (revision c9c2db91c8925461d29460f9425e45faad7d4908)
1/**
2 * DokuWiki Mikio Template Javascript
3 *
4 * @link    http://dokuwiki.org/template:mikio
5 * @author  James Collins <james.collins@outlook.com.au>
6 * @license GPLv2 (http://www.gnu.org/licenses/gpl-2.0.html)
7 */
8"use strict";
9
10var mikio = {
11    queueResize: false,
12
13    ready: function() {
14        this.addToggleClick('mikio-sidebar-toggle', 'mikio-sidebar-collapse');
15        this.addToggleClick('mikio-navbar-toggle', 'mikio-navbar-collapse');
16        this.addDropdownClick('mikio-nav-dropdown', 'mikio-dropdown');
17
18        window.onresize = function() {
19            if(!this.queueResize) {
20                this.queueResize = true;
21                window.setTimeout(function() {
22                    this.queueResize = false;
23                    Array.from(document.getElementsByClassName('mikio-dropdown')).forEach(function(elem) {
24                        if(!elem.classList.contains('closed')) {
25                            elem.classList.add('closed');
26                        }
27                    });
28                }, 100);
29            }
30        };
31
32        // Mikio-Dropdown - Click
33        Array.from(document.getElementsByClassName('mikio-dropdown')).forEach(function(elem) {
34            elem.addEventListener('click', function(event) {
35                event.stopPropagation();
36            });
37        });
38
39        // Mikio-Dropdown - Close when clicked outside dropdown
40        Array.from(document.getElementsByTagName('body')).forEach(function(elem) {
41            elem.addEventListener('click', function(event) {
42                Array.from(document.getElementsByClassName('mikio-dropdown')).forEach(function(elem) {
43                    if(!elem.classList.contains('closed')) {
44                        elem.classList.add('closed');
45                    }
46                });
47            });
48        });
49
50        // Mikio-Navbar-Toggle - Fix
51        Array.from(document.getElementsByClassName('mikio-navbar-toggle')).forEach(function(elem) {
52            elem.classList.add('closed');
53        });
54
55        // Mikio-Dropdown - Fix
56        Array.from(document.getElementsByClassName('mikio-dropdown')).forEach(function(elem) {
57            elem.classList.add('closed');
58        });
59
60        // Input File - Cleanup
61        Array.from(document.querySelectorAll('input[type=file]')).forEach(function(elem) {
62            var style = window.getComputedStyle(elem);
63
64            if(style.display != 'none') {
65                var parentElem = elem.parentElement;
66                var fileRect = elem.getBoundingClientRect();
67                var parentRect = parentElem.getBoundingClientRect();
68                var spanElem = document.createElement('span');
69
70                elem.style.opacity = 0;
71                parentElem.style.position = 'relative';
72                spanElem.innerHTML = 'Choose file...';
73                spanElem.classList.add('mikio-input-file');
74                spanElem.style.left = Math.floor(fileRect.left - parentRect.left) + 'px';
75                spanElem.style.width = Math.floor(fileRect.right - fileRect.left) + 'px';
76                mikio.insertAfter(spanElem, elem);
77
78                spanElem.addEventListener('click', function(event) {
79                    if(event.target.parentElement.tagName.toLowerCase() != 'label') {
80                        let sibling = mikio.getPrevSibling(event.target, 'input');
81                        if(typeof sibling !== 'undefined') {
82                            sibling.click();
83                        }
84                    }
85                });
86
87                elem.addEventListener('change', function() {
88                    if(this.files.length > 0) {
89                        let mikioInput = mikio.getNextSibling(this, '.mikio-input-file');
90                        if(typeof mikioInput !== 'undefined') {
91                            mikioInput.innerHTML = this.files[0].name;
92                        }
93                    }
94                });
95            }
96        });
97
98        // Input - Span (Placeholder) clear when typing
99        Array.from(document.querySelectorAll('.mikio.dokuwiki .mode_login fieldset label.block input.edit, .mikio.dokuwiki .mode_denied fieldset label.block input.edit')).forEach(function(elem) {
100            elem.addEventListener('keydown', function(event) {
101                console.log(event.key);
102                var sibling = mikio.getPrevSibling(event.target, 'span');
103
104                setTimeout(function() {
105                    if(sibling) {
106                        if(event.target.value != '') {
107                            sibling.style.display = 'none';
108                        } else {
109                            sibling.style.display = 'block';
110                        }
111                    }
112                }, 50);
113            });
114        });
115
116        // Admin - Exit button
117        Array.from(document.querySelectorAll('a[rel="exit-admin"]')).forEach(function(elem) {
118            elem.addEventListener('click', function(event) {
119                event.preventDefault();
120
121                var href = window.location.protocol + "//" + window.location.host + "/" + window.location.pathname;
122
123                var params = window.location.search;
124                if(params !== '') {
125                    params = params.substr(1).split('&');
126                    if(params.length > 1) {
127                        href += '?';
128                        params.forEach(function(p) {
129                            if(p.substring(0, 3) == 'id=') {
130                                href += p;
131                            }
132                        });
133                    }
134                }
135
136                window.location = href;
137            });
138        });
139
140        // Admin - Back button
141        Array.from(document.querySelectorAll('a[rel="exit-page"]')).forEach(function(elem) {
142            elem.addEventListener('click', function(event) {
143                event.preventDefault();
144
145                var href = window.location.protocol + "//" + window.location.host + "/" + window.location.pathname;
146
147                var params = window.location.search;
148                if(params != '') {
149                    params = params.substr(1).split('&');
150                    if(params.length > 1) {
151                        href += '?';
152                        params.forEach(function(p) {
153                            if(p.substring(0, 5) != 'page=') {
154                                href += p + '&';
155                            }
156                        });
157                    }
158                }
159
160                window.location = href;
161            });
162        });
163
164        // Admin - Resize large text blocks in tasks
165        Array.from(document.querySelectorAll('.admin_tasks span.prompt')).forEach(function(elem) {
166            if(elem.offsetHeight > 48) {
167                elem.style.fontSize = '80%';
168            }
169        });
170
171        // Media Manager - ui-resizable is always auto
172        var mediaChangedObserver = new MutationObserver(function(mutationsList) {
173            for(let mutation of mutationsList) {
174                if (mutation.type === 'childList') {
175                    if(mutation.addedNodes) {
176                        mutation.addedNodes.forEach(function(node) {
177                            if(node.nodeName == 'LI') {
178
179                            }
180                        });
181                    }
182                }
183
184                if (mutation.type === 'attributes' && mutation.attributeName == 'style' && mutation.target && mutation.target.style.height) {
185                    mutation.target.style.height = '';
186                }
187            }
188        });
189
190        var target = document.getElementById('mediamanager__page');
191        if(target) {
192            mediaChangedObserver.observe(target, {attributes: true, childList: true, subtree: true});
193        }
194
195        // Media Manager - file click
196        Array.from(document.querySelectorAll('#mediamanager__page .filelist')).forEach(function(elem) {
197            elem.addEventListener('click', function(event) {
198                var liElem = event.target.closest('li');
199                if(liElem && event.target.closest('ul.thumbs')) {
200                    var aElem = liElem.querySelector('dd.name a');
201                    if(aElem) aElem.click();
202                }
203            });
204        });
205
206        // Popup Media Manager - clean file info
207        var mediaPopupFileInfoClean = function(elem) {
208            var file = {resolution: '', date: '', time: '', size: ''};
209
210            var infoElem = elem.querySelector('span.info');
211            if(infoElem) {
212                var infoText = infoElem.innerText.replace(/(<[^>]*>|[\(\)])/g, '');
213                var detail = infoText.split(' ');
214                while(detail.length < 4) {
215                    detail.unshift('');
216                }
217
218                infoElem.innerHTML = detail[0] + '<br>' + detail[1] + ' ' + detail[2] + '<br>' + detail[3];
219            }
220
221            console.log('there');
222            Array.from(elem.querySelectorAll('img')).forEach(function(elem) {
223                elem.removeAttribute('width');
224                elem.removeAttribute('height');
225            });
226        }
227
228        var mediaPopupObserver = new MutationObserver(function(mutationsList) {
229            for(let mutation of mutationsList) {
230                if (mutation.type === 'childList') {
231                    if(mutation.addedNodes) {
232                        mutation.addedNodes.forEach(function(node) {
233                            if(node.nodeName == 'DIV') {
234                                mediaPopupFileInfoClean(node);
235                            }
236                        });
237                    }
238                }
239            }
240        });
241
242        var target = document.getElementById('media__content');
243        if(target) {
244            Array.from(target.querySelectorAll('div.odd, div.even')).forEach(function(elem) {
245                mediaPopupFileInfoClean(elem);
246            });
247
248            mediaPopupObserver.observe(target, {attributes: false, childList: true});
249        }
250
251        if(typeof mikioFooterRun === "function") mikioFooterRun();
252    },
253
254    insertAfter: function(newNode, existingNode) {
255        existingNode.parentNode.insertBefore(newNode, existingNode.nextSibling);
256    },
257
258    addToggleClick: function(elemToggle, elemCollapse) {
259        this.addEventListenerByClassName(elemToggle, 'click', function(event) {
260            event.preventDefault();
261            event.stopPropagation();
262            let nextSibling = mikio.getNextSibling(this, '.' + elemCollapse);
263
264            if(typeof nextSibling !== 'undefined') {
265                mikio.toggleCollapse(this, nextSibling);
266            }
267        });
268    },
269
270    addDropdownClick: function(elemToggle, elemCollapse) {
271        this.addEventListenerByClassName(elemToggle, 'click', function(event) {
272            event.preventDefault();
273            event.stopPropagation();
274
275            var dropdown = this.querySelector('.' + elemCollapse);
276            if(dropdown) {
277                mikio.toggleDropdown(dropdown);
278            }
279        });
280    },
281
282    addEventListenerByClassName: function(className, eventType, callback) {
283        Array.from(document.getElementsByClassName(className)).forEach(function(elem) {
284            elem.addEventListener(eventType, callback);
285        });
286    },
287
288    getNextSibling: function(elem, selector) {
289        var sibling = elem.nextElementSibling;
290
291        while (sibling) {
292            if (sibling.matches(selector)) return sibling;
293            sibling = sibling.nextElementSibling;
294        }
295    },
296
297    getPrevSibling: function(elem, selector) {
298        var sibling = elem.previousElementSibling;
299
300        while (sibling) {
301            if (sibling.matches(selector)) return sibling;
302            sibling = sibling.previousElementSibling;
303        }
304    },
305
306    toggleCollapse: function(objToggle, objCollapse) {
307        if(objToggle.classList.contains('closed')) {
308            objToggle.classList.remove('closed');
309            var height = objCollapse.offsetHeight;
310            objCollapse.style.overflow = 'hidden';
311            objCollapse.style.height = 0;
312            objCollapse.style.paddingTop = 0;
313            objCollapse.style.paddingBottom = 0;
314            objCollapse.style.marginTop = 0;
315            objCollapse.style.marginBottom = 0;
316            objCollapse.offsetHeight;
317            objCollapse.style.boxSizing = 'border-box';
318            objCollapse.style.transitionProperty = "height, margin, padding";
319            objCollapse.style.transitionDuration = '500ms';
320            objCollapse.style.height = height + 'px';
321            objCollapse.style.removeProperty('padding-top');
322            objCollapse.style.removeProperty('padding-bottom');
323            objCollapse.style.removeProperty('margin-top');
324            objCollapse.style.removeProperty('margin-bottom');
325            window.setTimeout(function() {
326                objCollapse.style.removeProperty('height');
327                objCollapse.style.removeProperty('overflow');
328                objCollapse.style.removeProperty('transition-duration');
329                objCollapse.style.removeProperty('transition-property');
330                objCollapse.style.removeProperty('box-sizing');
331            }, 500);
332        } else {
333            objCollapse.style.transitionProperty = 'height, margin, padding';
334            objCollapse.style.transitionDuration = '500ms';
335            objCollapse.style.boxSizing = 'border-box';
336            objCollapse.style.height = objCollapse.offsetHeight + 'px';
337            objCollapse.offsetHeight;
338            objCollapse.style.overflow = 'hidden';
339            objCollapse.style.height = 0;
340            objCollapse.style.paddingTop = 0;
341            objCollapse.style.paddingBottom = 0;
342            objCollapse.style.marginTop = 0;
343            objCollapse.style.marginBottom = 0;
344            window.setTimeout(function() {
345                objToggle.classList.add('closed');
346                objCollapse.style.removeProperty('height');
347                objCollapse.style.removeProperty('padding-top');
348                objCollapse.style.removeProperty('padding-bottom');
349                objCollapse.style.removeProperty('margin-top');
350                objCollapse.style.removeProperty('margin-bottom');
351                objCollapse.style.removeProperty('overflow');
352                objCollapse.style.removeProperty('transition-duration');
353                objCollapse.style.removeProperty('transition-property');
354                objCollapse.style.removeProperty('box-sizing');
355            }, 500);
356        }
357    },
358
359
360    toggleDropdown: function(objToggle) {
361        if(objToggle.classList.contains('closed')) {
362            objToggle.classList.remove('closed');
363        } else {
364            objToggle.classList.add('closed');
365        }
366
367        Array.from(document.getElementsByClassName('mikio-dropdown')).forEach(function(elem) {
368            if(!elem.classList.contains('closed') && elem != objToggle) {
369                elem.classList.add('closed');
370            }
371        });
372    },
373
374    setHeroSubTitle: function(str) {
375        Array.from(document.getElementsByClassName('mikio-hero-subtitle')).forEach(function(elem) {
376            elem.innerHTML = str;
377        });
378    },
379
380    setHeroImage: function(str) {
381        var heroImages = document.getElementsByClassName('mikio-hero-image');
382
383        if(heroImages.length > 0) {
384            Array.from(document.getElementsByClassName('mikio-hero-image')).forEach(function(elem) {
385                elem.style.backgroundImage = 'url(\'' + str + '\')';
386                elem.classList.add('mikio-hero-image-resize');
387            });
388        } else {
389            Array.from(document.getElementsByClassName('mikio-hero-text')).forEach(function(elem) {
390                elem.insertAdjacentHTML('afterend', '<div class="mikio-hero-image mikio-hero-image-resize" style="background-image:url(\'' + str + '\');"></div>');
391            });
392        }
393    },
394
395    setHeroColor: function(str) {
396        var colors = str.trim().replace(/ +(?= )/g,'').split(/(?!\(.*)\s(?![^(]*?\))/g);
397        if(colors.length > 0 && colors[0] != '') {
398            Array.from(document.getElementsByClassName('mikio-hero')).forEach(function(elem) {
399                elem.style.backgroundColor = colors[0];
400            });
401
402            if(colors.length > 1) {
403                Array.from(document.getElementsByClassName('mikio-hero-title')).forEach(function(elem) {
404                    elem.style.color = colors[1];
405                });
406            }
407
408            if(colors.length > 2) {
409                Array.from(document.getElementsByClassName('mikio-hero-subtitle')).forEach(function(elem) {
410                    elem.style.color = colors[2];
411                });
412            }
413
414            if(colors.length > 3) {
415                Array.from(document.getElementsByClassName('mikio-hero')).forEach(function(parentElem) {
416                    Array.from(parentElem.querySelectorAll('.mikio-breadcrumbs ul li a')).forEach(function(elem) {
417                        elem.style.color = colors[3];
418                    });
419
420                    Array.from(parentElem.querySelectorAll('.mikio-breadcrumbs ul li, .mikio-breadcrumbs ul li a')).forEach(function(elem) {
421                        elem.style.color = colors[3];
422                        elem.onmouseover = function() { this.style.color = (colors.length > 4 ? colors[4] : 'initial'); };
423                        elem.onmouseout = function() { this.style.color = colors[3]; };
424                    });
425                });
426            }
427        }
428    },
429
430    setTags: function(str) {
431        Array.from(document.getElementsByClassName('mikio-tags')).forEach(function(elem) {
432            elem.innerHTML = str;
433        });
434    }
435};
436
437
438if(document.readyState != 'loading') {
439    mikio.ready();
440} else {
441    document.addEventListener('DOMContentLoaded', function() { mikio.ready() });
442}
443