xref: /template/mikio/assets/mikio.js (revision 1dbcd10a8d1342e83dc26b8ab6e9048ff719acc7)
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    mikioCSS: false,
13    stickyItems: [],
14    stickyOffset: 0,
15    stickyIndex: 2010,
16    darkMode: 'light',
17
18    ready: function () {
19        var self = this;
20
21        this.initDarkMode();
22        this.addToggleClick('mikio-sidebar-toggle', 'mikio-sidebar-collapse');
23        this.addToggleClick('mikio-navbar-toggle', 'mikio-navbar-collapse');
24        this.addDropdownClick('mikio-nav-dropdown', 'mikio-dropdown');
25        this.indexmenuPatch();
26		this.typeahead();
27
28        var updateStickyItems = function () {
29            window.removeEventListener('scroll', updateStickyScroll);
30
31            var stickyElements = document.getElementsByClassName('mikio-sticky');
32            self.stickyItems = [];
33            if (stickyElements && stickyElements.length > 0) {
34                var stickyOffset = stickyElements[0].offsetTop;
35                var stickyHeightCount = stickyOffset;
36
37                [].forEach.call(stickyElements, (item) => {
38                    var top = stickyOffset;
39                    if (item.offsetTop - stickyHeightCount > stickyHeightCount) {
40                        top = stickyHeightCount;
41                    }
42
43                    self.stickyItems.push({ element: item, offsetYTop: top, debugItemTop: item.offsetTop, debugOffset: stickyOffset, debugHeight: stickyHeightCount });
44                    stickyHeightCount += item.offsetHeight;
45                });
46
47                window.addEventListener('scroll', updateStickyScroll);
48                updateStickyScroll();
49            }
50        };
51
52        var updateStickyScroll = function () {
53            self.stickyItems.forEach((item) => {
54                if (window.pageYOffset > item.offsetYTop) {
55                    if (item.element.style.position != 'fixed') {
56                        var site = document.getElementById('dokuwiki__site');
57                        site.style.paddingTop = ((parseInt(site.style.paddingTop) || 0) + item.element.offsetHeight) + 'px';
58
59                        item.element.style.position = 'fixed';
60                        item.element.style.top = self.stickyOffset + 'px';
61                        item.element.style.zIndex = self.stickyIndex;
62
63                        self.stickyOffset += item.element.offsetHeight;
64                        self.stickyIndex--;
65                    }
66                } else {
67                    if (item.element.style.position == 'fixed') {
68                        var site = document.getElementById('dokuwiki__site');
69                        site.style.paddingTop = ((parseInt(site.style.paddingTop) || 0) - item.element.offsetHeight) + 'px';
70                        self.stickyOffset -= item.element.offsetHeight;
71                        self.stickyIndex++;
72
73                        item.element.style.position = 'relative';
74                        item.element.style.top = null;
75                        item.element.style.zIndex = null;
76                    }
77                }
78            });
79        };
80
81        updateStickyItems();
82
83        window.onresize = function () {
84            if (!this.queueResize) {
85                this.queueResize = true;
86                window.setTimeout(function () {
87                    this.queueResize = false;
88                    Array.from(document.getElementsByClassName('mikio-dropdown')).forEach(function (elem) {
89                        if (!elem.classList.contains('closed')) {
90                            elem.classList.add('closed');
91                        }
92                    });
93
94                    updateStickyItems();
95                }, 100);
96            }
97        };
98
99        // Mikio-Dropdown - Click
100        Array.from(document.getElementsByClassName('mikio-dropdown')).forEach(function (elem) {
101            elem.addEventListener('click', function (event) {
102                event.stopPropagation();
103            });
104        });
105
106        // Mikio-Dropdown - Close when clicked outside dropdown
107        Array.from(document.getElementsByTagName('body')).forEach(function (elem) {
108            elem.addEventListener('click', function (event) {
109                Array.from(document.getElementsByClassName('mikio-dropdown')).forEach(function (elem) {
110                    if (!elem.classList.contains('closed')) {
111                        elem.classList.add('closed');
112                    }
113                });
114            });
115        });
116
117        // Mikio-Navbar-Toggle - Fix
118        Array.from(document.getElementsByClassName('mikio-navbar-toggle')).forEach(function (elem) {
119            elem.classList.add('closed');
120        });
121
122        // Mikio-Dropdown - Fix
123        Array.from(document.getElementsByClassName('mikio-dropdown')).forEach(function (elem) {
124            elem.classList.add('closed');
125        });
126
127        // Input File - Cleanup
128        Array.from(document.querySelectorAll('input[type=file]')).forEach(function (elem) {
129            var style = window.getComputedStyle(elem);
130
131            if (style.display != 'none') {
132                var parentElem = elem.parentElement;
133                var fileRect = elem.getBoundingClientRect();
134                var parentRect = parentElem.getBoundingClientRect();
135                var spanElem = document.createElement('span');
136
137                elem.style.opacity = 0;
138                parentElem.style.position = 'relative';
139                spanElem.innerHTML = 'Choose file...';
140                spanElem.classList.add('mikio-input-file');
141                spanElem.style.left = Math.floor(fileRect.left - parentRect.left) + 'px';
142                spanElem.style.width = Math.floor(fileRect.right - fileRect.left) + 'px';
143                mikio.insertAfter(spanElem, elem);
144
145                spanElem.addEventListener('click', function (event) {
146                    if (event.target.parentElement.tagName.toLowerCase() != 'label') {
147                        let sibling = mikio.getPrevSibling(event.target, 'input');
148                        if (typeof sibling !== 'undefined') {
149                            sibling.click();
150                        }
151                    }
152                });
153
154                elem.addEventListener('change', function () {
155                    if (this.files.length > 0) {
156                        let mikioInput = mikio.getNextSibling(this, '.mikio-input-file');
157                        if (typeof mikioInput !== 'undefined') {
158                            mikioInput.innerHTML = this.files[0].name;
159                        }
160                    }
161                });
162            }
163        });
164
165        // Input - Span (Placeholder) clear when typing
166        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) {
167            if (elem.value.length != 0) {
168                var sibling = mikio.getPrevSibling(elem, 'span');
169                if (sibling) {
170                    sibling.style.display = 'none';
171                }
172            }
173
174            elem.addEventListener('keydown', function (event) {
175                var sibling = mikio.getPrevSibling(event.target, 'span');
176
177                setTimeout(function () {
178                    if (sibling) {
179                        if (event.target.value != '') {
180                            sibling.style.display = 'none';
181                        } else {
182                            sibling.style.display = 'block';
183                        }
184                    }
185                }, 50);
186            });
187        });
188
189        // Admin - Exit button
190        Array.from(document.querySelectorAll('a[rel="exit-admin"]')).forEach(function (elem) {
191            elem.addEventListener('click', function (event) {
192                event.preventDefault();
193
194                var href = window.location.protocol + "//" + window.location.host + "/" + window.location.pathname;
195
196                var params = window.location.search;
197                if (params !== '') {
198                    params = params.substr(1).split('&');
199                    if (params.length > 1) {
200                        href += '?';
201                        params.forEach(function (p) {
202                            if (p.substring(0, 3) == 'id=') {
203                                href += p;
204                            }
205                        });
206                    }
207                }
208
209                window.location = href;
210            });
211        });
212
213        // Admin - Back button
214        Array.from(document.querySelectorAll('a[rel="exit-page"]')).forEach(function (elem) {
215            elem.addEventListener('click', function (event) {
216                event.preventDefault();
217
218                var href = window.location.protocol + "//" + window.location.host + "/" + window.location.pathname;
219
220                var params = window.location.search;
221                if (params != '') {
222                    params = params.substr(1).split('&');
223                    if (params.length > 1) {
224                        href += '?';
225                        params.forEach(function (p) {
226                            if (p.substring(0, 5) != 'page=') {
227                                href += p + '&';
228                            }
229                        });
230                    }
231                }
232
233                window.location = href;
234            });
235        });
236
237        // Admin - Resize large text blocks in tasks
238        Array.from(document.querySelectorAll('.admin_tasks span.prompt')).forEach(function (elem) {
239            if (elem.offsetHeight > 48) {
240                elem.style.fontSize = '80%';
241            }
242        });
243
244        // Media Manager - ui-resizable is always auto
245        var mediaChangedObserver = new MutationObserver(function (mutationsList) {
246            for (let mutation of mutationsList) {
247                if (mutation.type === 'childList') {
248                    if (mutation.addedNodes) {
249                        mutation.addedNodes.forEach(function (node) {
250                            if (node.nodeName == 'LI') {
251
252                            }
253                        });
254                    }
255                }
256
257                if (mutation.type === 'attributes' && mutation.attributeName == 'style' && mutation.target && mutation.target.style.height) {
258                    mutation.target.style.height = '';
259                }
260            }
261        });
262
263        var target = document.getElementById('mediamanager__page');
264        if (target) {
265            mediaChangedObserver.observe(target, { attributes: true, childList: true, subtree: true });
266        }
267
268        // Media Manager - file click
269        Array.from(document.querySelectorAll('#mediamanager__page .filelist')).forEach(function (elem) {
270            elem.addEventListener('click', function (event) {
271                var liElem = event.target.closest('li');
272                if (liElem && event.target.closest('ul.thumbs')) {
273                    var aElem = liElem.querySelector('dd.name a');
274                    if (aElem) aElem.click();
275                }
276            });
277        });
278
279        // Popup Media Manager - clean file info
280        var mediaPopupFileInfoClean = function (elem) {
281            var file = { resolution: '', date: '', time: '', size: '' };
282
283            var infoElem = elem.querySelector('span.info');
284            if (infoElem) {
285                var infoText = infoElem.innerText.replace(/(<[^>]*>|[\(\)])/g, '');
286                var detail = infoText.split(' ');
287                while (detail.length < 4) {
288                    detail.unshift('');
289                }
290
291                infoElem.innerHTML = detail[0] + '<br>' + detail[1] + ' ' + detail[2] + '<br>' + detail[3];
292            }
293
294            Array.from(elem.querySelectorAll('img')).forEach(function (elem) {
295                elem.removeAttribute('width');
296                elem.removeAttribute('height');
297            });
298        }
299
300        var mediaPopupObserver = new MutationObserver(function (mutationsList) {
301            for (let mutation of mutationsList) {
302                if (mutation.type === 'childList') {
303                    if (mutation.addedNodes) {
304                        mutation.addedNodes.forEach(function (node) {
305                            if (node.nodeName == 'DIV') {
306                                mediaPopupFileInfoClean(node);
307                            }
308                        });
309                    }
310                }
311            }
312        });
313
314        var target = document.getElementById('media__content');
315        if (target) {
316            Array.from(target.querySelectorAll('div.odd, div.even')).forEach(function (elem) {
317                mediaPopupFileInfoClean(elem);
318            });
319
320            mediaPopupObserver.observe(target, { attributes: false, childList: true });
321        }
322
323        if (typeof mikioFooterRun === "function") mikioFooterRun();
324
325        var mediaChangedObserver = new MutationObserver(function (mutationsList) {
326            for (let mutation of mutationsList) {
327                if (mutation.type === 'attributes' && mutation.attributeName == 'href') {
328                    if (self.mikioCSS != false) {
329                        var elem = self.mikioCSS;
330                        var prev = elem.href;
331
332                        setTimeout(function () {
333                            var url = new URL(prev);
334                            var params = url.searchParams;
335                            params.set('seed', new Date().getTime());
336                            url.search = params.toString();
337                            elem.href = url.toString();
338                        }, 500);
339                    }
340                }
341            }
342        });
343
344        var linkElements = document.getElementsByTagName('link');
345        for (let element of linkElements) {
346            if (element.rel == 'stylesheet' && element.href) {
347                if (element.href.includes('/lib/exe/css.php')) {
348                    mediaChangedObserver.observe(element, { attributes: true, childList: true, subtree: true });
349                } else if (element.href.includes('/lib/tpl/mikio/css.php')) {
350                    this.mikioCSS = element;
351                }
352            }
353        }
354    },
355
356    initDarkMode: function () {
357        // document.getElementsByTagName('body')[0].style.background='red';
358        let setting = this.getCookie('lightDarkToggle');
359        if (setting == 'dark' || setting == 'light') {
360            this.darkMode = setting;
361        }
362
363        var self = this;
364        this.addEventListenerByClassName('mikio-darklight-button', 'click', function (event) {
365            event.preventDefault();
366            event.stopPropagation();
367
368            if(self.darkMode == 'dark') {
369                self.darkMode = 'light';
370            } else {
371                self.darkMode = 'dark';
372            }
373
374            self.updateDarkMode();
375        });
376
377        this.updateDarkMode();
378    },
379
380    updateDarkMode: function () {
381        if (this.darkMode == 'dark') {
382            document.body.classList.add('mikio-dark');
383            document.body.classList.remove('mikio-light');
384            this.setCookie('lightDarkToggle', 'dark');
385        } else {
386            document.body.classList.add('mikio-light');
387            document.body.classList.remove('mikio-dark');
388            this.setCookie('lightDarkToggle', 'light');
389        }
390    },
391
392    insertAfter: function (newNode, existingNode) {
393        existingNode.parentNode.insertBefore(newNode, existingNode.nextSibling);
394    },
395
396    addToggleClick: function (elemToggle, elemCollapse) {
397        this.addEventListenerByClassName(elemToggle, 'click', function (event) {
398            event.preventDefault();
399            event.stopPropagation();
400            let nextSibling = mikio.getNextSibling(this, '.' + elemCollapse);
401
402            if (typeof nextSibling !== 'undefined') {
403                mikio.toggleCollapse(this, nextSibling);
404            }
405        });
406    },
407
408    addDropdownClick: function (elemToggle, elemCollapse) {
409        this.addEventListenerByClassName(elemToggle, 'click', function (event) {
410            event.preventDefault();
411            event.stopPropagation();
412
413            var dropdown = this.querySelector('.' + elemCollapse);
414            if (dropdown) {
415                mikio.toggleDropdown(dropdown);
416            }
417        });
418    },
419
420    addEventListenerByClassName: function (className, eventType, callback) {
421        Array.from(document.getElementsByClassName(className)).forEach(function (elem) {
422            elem.addEventListener(eventType, callback);
423        });
424    },
425
426    getNextSibling: function (elem, selector) {
427        var sibling = elem.nextElementSibling;
428
429        while (sibling) {
430            if (sibling.matches(selector)) return sibling;
431            sibling = sibling.nextElementSibling;
432        }
433    },
434
435    getPrevSibling: function (elem, selector) {
436        var sibling = elem.previousElementSibling;
437
438        while (sibling) {
439            if (sibling.matches(selector)) return sibling;
440            sibling = sibling.previousElementSibling;
441        }
442    },
443
444    toggleCollapse: function (objToggle, objCollapse) {
445        if (objToggle.classList.contains('closed')) {
446            objToggle.classList.remove('closed');
447            objToggle.classList.add('open');
448            var height = objCollapse.offsetHeight;
449            objCollapse.style.overflow = 'hidden';
450            objCollapse.style.height = 0;
451            objCollapse.style.paddingTop = 0;
452            objCollapse.style.paddingBottom = 0;
453            objCollapse.style.marginTop = 0;
454            objCollapse.style.marginBottom = 0;
455            objCollapse.offsetHeight;
456            objCollapse.style.boxSizing = 'border-box';
457            objCollapse.style.transitionProperty = "height, margin, padding";
458            objCollapse.style.transitionDuration = '500ms';
459            objCollapse.style.height = height + 'px';
460            objCollapse.style.removeProperty('padding-top');
461            objCollapse.style.removeProperty('padding-bottom');
462            objCollapse.style.removeProperty('margin-top');
463            objCollapse.style.removeProperty('margin-bottom');
464            window.setTimeout(function () {
465                objCollapse.style.removeProperty('height');
466                objCollapse.style.removeProperty('overflow');
467                objCollapse.style.removeProperty('transition-duration');
468                objCollapse.style.removeProperty('transition-property');
469                objCollapse.style.removeProperty('box-sizing');
470            }, 500);
471        } else {
472            objCollapse.style.transitionProperty = 'height, margin, padding';
473            objCollapse.style.transitionDuration = '500ms';
474            objCollapse.style.boxSizing = 'border-box';
475            objCollapse.style.height = objCollapse.offsetHeight + 'px';
476            objCollapse.offsetHeight;
477            objCollapse.style.overflow = 'hidden';
478            objCollapse.style.height = 0;
479            objCollapse.style.paddingTop = 0;
480            objCollapse.style.paddingBottom = 0;
481            objCollapse.style.marginTop = 0;
482            objCollapse.style.marginBottom = 0;
483            window.setTimeout(function () {
484                objToggle.classList.add('closed');
485                objToggle.classList.remove('open');
486                objCollapse.style.removeProperty('height');
487                objCollapse.style.removeProperty('padding-top');
488                objCollapse.style.removeProperty('padding-bottom');
489                objCollapse.style.removeProperty('margin-top');
490                objCollapse.style.removeProperty('margin-bottom');
491                objCollapse.style.removeProperty('overflow');
492                objCollapse.style.removeProperty('transition-duration');
493                objCollapse.style.removeProperty('transition-property');
494                objCollapse.style.removeProperty('box-sizing');
495            }, 500);
496        }
497    },
498
499
500    toggleDropdown: function (objToggle) {
501        if (objToggle.classList.contains('closed')) {
502            objToggle.classList.remove('closed');
503        } else {
504            objToggle.classList.add('closed');
505        }
506
507        Array.from(document.getElementsByClassName('mikio-dropdown')).forEach(function (elem) {
508            if (!elem.classList.contains('closed') && elem != objToggle) {
509                elem.classList.add('closed');
510            }
511        });
512    },
513
514    setHeroSubTitle: function (str) {
515        Array.from(document.getElementsByClassName('mikio-hero-subtitle')).forEach(function (elem) {
516            elem.innerHTML = str;
517        });
518    },
519
520    setHeroImage: function (str) {
521        var heroImages = document.getElementsByClassName('mikio-hero-image');
522
523        if (heroImages.length > 0) {
524            Array.from(document.getElementsByClassName('mikio-hero-image')).forEach(function (elem) {
525                elem.style.backgroundImage = 'url(\'' + str + '\')';
526                elem.classList.add('mikio-hero-image-resize');
527            });
528        } else {
529            Array.from(document.getElementsByClassName('mikio-hero-text')).forEach(function (elem) {
530                elem.insertAdjacentHTML('afterend', '<div class="mikio-hero-image mikio-hero-image-resize" style="background-image:url(\'' + str + '\');"></div>');
531            });
532        }
533    },
534
535    setHeroColor: function (str) {
536        var colors = str.trim().replace(/ +(?= )/g, '').split(/(?!\(.*)\s(?![^(]*?\))/g);
537        if (colors.length > 0 && colors[0] != '') {
538            Array.from(document.getElementsByClassName('mikio-hero')).forEach(function (elem) {
539                elem.style.backgroundColor = colors[0];
540            });
541
542            if (colors.length > 1) {
543                Array.from(document.getElementsByClassName('mikio-hero-title')).forEach(function (elem) {
544                    elem.style.color = colors[1];
545                });
546            }
547
548            if (colors.length > 2) {
549                Array.from(document.getElementsByClassName('mikio-hero-subtitle')).forEach(function (elem) {
550                    elem.style.color = colors[2];
551                });
552            }
553
554            if (colors.length > 3) {
555                Array.from(document.getElementsByClassName('mikio-hero')).forEach(function (parentElem) {
556                    Array.from(parentElem.querySelectorAll('.mikio-breadcrumbs ul li a')).forEach(function (elem) {
557                        elem.style.color = colors[3];
558                    });
559
560                    Array.from(parentElem.querySelectorAll('.mikio-breadcrumbs ul li, .mikio-breadcrumbs ul li a')).forEach(function (elem) {
561                        elem.style.color = colors[3];
562                        elem.onmouseover = function () { this.style.color = (colors.length > 4 ? colors[4] : 'initial'); };
563                        elem.onmouseout = function () { this.style.color = colors[3]; };
564                    });
565                });
566            }
567        }
568    },
569
570    setTags: function (str) {
571        Array.from(document.getElementsByClassName('mikio-tags')).forEach(function (elem) {
572            elem.innerHTML = str;
573        });
574    },
575
576    hidePart: function (part) {
577        var selectorArray = {
578            topheader: '.mikio-page-topheader',
579            header: '.mikio-page-header',
580            contentheader: '.mikio-page-contentheader',
581            contentfooter: '.mikio-page-contentfooter',
582            sidebarheader: '.mikio-sidebar-left .mikio-sidebar-header',
583            sidebarfooter: '.mikio-sidebar-left .mikio-sidebar-footer',
584            rightsidebarheader: '.mikio-sidebar-right .mikio-sidebar-header',
585            rightsidebarfooter: '.mikio-sidebar-right .mikio-sidebar-footer',
586            footer: '.mikio-footer',
587            bottomfooter: '.mikio-page-bottomfooter',
588            navbar: '.mikio-navbar',
589            hero: '.mikio-hero'
590        };
591
592        if (selectorArray.hasOwnProperty(part)) {
593            Array.from(document.querySelectorAll(selectorArray[part])).forEach(function (elem) {
594                elem.style.display = 'none';
595            });
596        }
597    },
598
599    indexmenuPatch: function () {
600        window.setTimeout(function () {
601            Array.from(document.querySelectorAll('a.navSel')).forEach(function (elem) {
602                let prev = mikio.getPrevSibling(elem, 'img');
603                if (prev) {
604                    prev.style.opacity = 1;
605                }
606            });
607        }, 50);
608
609
610        document.addEventListener('mouseover', function (event) {
611            const indexmenuClasses = ['nodeUrl', 'nodeSel', 'node'];
612            if ([...event.target.classList].some(className => indexmenuClasses.indexOf(className) !== -1)) {
613                let prev = mikio.getPrevSibling(event.target, 'img');
614                if (prev) {
615                    prev.style.opacity = 1;
616                }
617            }
618        });
619
620        document.addEventListener('mouseout', function (event) {
621            const indexmenuClasses = ['nodeUrl', 'nodeSel', 'node'];
622            if ([...event.target.classList].some(className => indexmenuClasses.indexOf(className) !== -1)) {
623                let prev = mikio.getPrevSibling(event.target, 'img');
624                if (prev) {
625                    prev.style.opacity = '';
626                }
627            }
628        });
629    },
630
631   // Add typeahead support for quick seach. Taken from bootstrap3 theme.
632    typeahead: function () {
633
634        jQuery(".search_typeahead").typeahead({
635
636            source: function (query, process) {
637
638                return jQuery.post(DOKU_BASE + 'lib/exe/ajax.php',
639                    {
640                        call: 'qsearch',
641                        q: encodeURI(query)
642                    },
643                    function (data) {
644
645                        var results = [];
646
647                        jQuery(data).find('a').each(function () {
648
649                            var page = jQuery(this);
650
651                            results.push({
652                                name: page.text(),
653                                href: page.attr('href'),
654                                title: page.attr('title'),
655                                category: page.attr('title').replace(/:/g, ' : '),
656                            });
657
658                        });
659
660                        return process(results);
661
662                    });
663            },
664
665            itemLink: function (item) {
666                return item.href;
667            },
668
669            itemTitle: function (item) {
670                return item.title;
671            },
672
673            followLinkOnSelect: true,
674            autoSelect: false,
675            items: 10,
676            fitToElement: true,
677            delay: 500,
678			theme: 'bootstrap4',
679
680        });
681    },
682
683    getCookie: function(cname) {
684        let name = cname + "=";
685        let decodedCookie = decodeURIComponent(document.cookie);
686        let ca = decodedCookie.split(';');
687        for (let i = 0; i < ca.length; i++) {
688            let c = ca[i];
689            while (c.charAt(0) == ' ') {
690                c = c.substring(1);
691            }
692            if (c.indexOf(name) == 0) {
693                return c.substring(name.length, c.length);
694            }
695        }
696        return "";
697    },
698
699    setCookie: function(cname, cvalue, exdays) {
700        const d = new Date();
701        d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
702        let expires = "expires=" + d.toUTCString();
703        document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
704    },
705
706    clearCookie: function(cname) {
707        document.cookie = cname + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/";
708    }
709};
710
711if (document.readyState != 'loading') {
712    mikio.ready();
713} else {
714    document.addEventListener('DOMContentLoaded', function () { mikio.ready() });
715    document.getElementsByTagName('html')[0].style.background = 'green';
716}
717