1/**
2 * Jokuwiki - a tool for managing javascript widgets
3 *
4 * Jokuwiki is intended to provide a framework (initially for Dokuwiki) to
5 * 1) isolate widgets from having to deal with dependencies (widget declared before dependencies available)
6 * 2) handle a strict Content Security Policy (i.e. no inline scripts)
7 * 3) non-standard content loading techniques (e.g. pjax)
8 *
9 * For simplicity the PJax page initializaton plugin is appended below
10 */
11var jokuwiki=
12{
13        widgets: [],            /* contains a list of [widgetname]=initFunction */
14        failcount: 0,           /* limits frequent re-running after failures */
15        urls: [],               /* maintains a list of script URLs loaded or about to be loaded */
16        iters: 0,               /* track number of times worklist has been scanned */
17        pjaxloads: 0,           /* count of times jokuwiki has been initialised */
18        attempts: 10,           /* maximum number of attempts at runQueue per init invocation */
19        maxPjax: 200,           /* max number of consecutive pjax loads before a full page load */
20        pjaxContainer: 'pjax_content',  /* element ID used for pjax container (optional -see disablePjax below) */
21/**
22 * init should be called when the page is loaded or content injected
23 */
24        init: function () {
25                jokuwiki.iters=0;
26                jokuwiki.failcount=0;
27                jokuwiki.pjaxloads++;
28                jokuwiki.attempts=10;
29                jokuwiki.runQueue();
30        },
31/**
32 * private method
33 *
34 * scans the DOM for widgets to invoke
35 * automatically reschedules itself for stuff which throws an exception
36 */
37        runQueue: function () {
38                if (jQuery.pjax && jokuwiki.pjaxloads>jokuwiki.maxPjax) {
39                    jokuwiki.disablePjax();
40                }
41                jokuwiki.iters++;
42                console.log(jokuwiki.iters + "(" + jokuwiki.pjaxloads + ") jokuwiki.runQueue iteration");
43                var els=jQuery("[data-jw]");
44                var success=false;
45                for(var i=0; i<els.length; i++) {
46                        success=false;
47                        try {
48                            payload=jQuery.parseJSON(els[i].getAttribute('data-jw'));
49                            jokuwiki.widgets[payload.jokuwiki](payload.data);
50                            success=true;
51                        } catch(e) {
52                            jokuwiki.failcount++;
53                            console.log(jokuwiki.iters + "(" + jokuwiki.pjaxloads + ") Error processing " + els[i].getAttribute('data-jw'));
54                        }
55                        console.log(jokuwiki.iters + "(" + jokuwiki.pjaxloads + ") still here - success = " + success);
56                        if (success) {
57                            /* our work here is done - remove from the list */
58                            console.log(jokuwiki.iters + "(" + jokuwiki.pjaxloads + ') removing' + els[i].id + ' from jokuwiki queue');
59                            els[i].removeAttribute('data-jw');
60                        }
61                }
62                if (jQuery("[data-jw]").length && --jokuwiki.attempts) {
63                        /* try to process the failed ones later */
64                    console.log(jokuwiki.iters + "(" + jokuwiki.pjaxloads + ") scheduling for another go");
65                    setTimeout(jokuwiki.runQueue, 200 + Math.min(jokuwiki.iters*100,1000));
66                }
67        },
68/**
69 * public method for creating mappings between widgetnames and initfunctions
70 * @param string widgetname - the 'name' attribute of the widget
71 * @param function handler - the function to call (with the data from the parsed json) to invoke
72 * @param string url - optional url to load (will only be loaded once)
73 */
74        register: function (widgetname, handler, url) {
75            if (url) {
76                jokuwiki.loadScript(url);
77            }
78            jokuwiki.widgets[widgetname]=handler;
79        },
80/**
81 * public method for deleting mappings between widgetnames and initfunctions
82 * @param string widgetname - the 'name' attribute of the widget
83 *
84 * Not really sure why this is here.
85 * Note that this does not remove any scripts which have been added
86 */
87        unregister: function (name) {               /* removes mapping between names and initFunctions */
88            delete jokuwiki.widgets[name];
89        },
90/**
91 * public method for loading a script asynchnronously
92 * @param string url
93 *
94 * There are some issues with jQuery's getScript, notably
95 * it doesn't intrinsically prevent the same script being
96 * injected multiple times
97 */
98        loadScript: function (url) {
99                if (!jokuwiki.urls[url]) {
100                        jokuwiki.urls[url]=1;
101                        jQuery(document).ready(function () {
102                                var script = document.createElement("script");
103                                script.type = "text/javascript";
104                                script.src = url;
105                                document.body.appendChild(script);
106                        });
107                }
108
109        },
110/**
111 * public method to allow full page loads/break pjax loading
112 *
113 */
114        disablePjax: function () {             /* do a full page load occasionally to clean up leaks */
115            try {
116                console.log(jokuwiki.iters + "(" + jokuwiki.pjaxloads + ') next page should be full reload');
117                document.getElementById(jokuwiki.pjaxContainer).id='DoNotReload';
118            } catch (e) { console.log('....or not');}
119        }
120};
121
122// --------- initialize the jokuwiki -------
123
124/* for full page load */
125jQuery(document).ready(jokuwiki.init);
126/* for pjax load */
127jQuery(document).on('pjax:success', jokuwiki.init);
128
129/* -------- register handler to update title ---- */
130/* NB has no dependencies therefore run in its own try....catch */
131/* - if it doesn't work the first time then it aint gonna work! */
132jokuwiki.register('pjaxTitle', function(jw) {
133    try {
134        document.title=jw.title;
135    } catch (e) {
136    }
137});
138
139/* ------------ add a widget -------- */
140jokuwiki.register('slideshow',function (jw) {
141           var i = new fadeSlideShow(jw);
142}, 'res/fader.js');
143
144/* ------ consol.log hack ---------- */
145if (!window.console) console = {log: function() {}};
146
147