README.md
1## Description ##
2
3Jokuwiki is a framework for integrating javascript in Dokuwiki. That is to say, it is mostly a set of rules about writing code, and a small amount of bundled code. It is intended to make your dokuwiki site:
4 * faster
5 * more secure
6 * and allow for pure javascript based plugins
7
8## Installation ##
9Download the zip file and unzip in the plugins directory or install via the plugin manager.
10
11## Usage ##
12
13```html
14<jw name='jwHelloWorld'
15 id='greetingDiv' style='width:100px;height=40px' noscript='Javascript is disabled'
16 data='{ "say" : "Hello World" }'
17 ></jw>
18```
19The example above requires the jwHelloWorld plugin to run. This plugin will be available on the same site where you sourced this package.
20
21The Jokuwiki opening tag has a number of attributes:
22* **name** (required) e.g. `name='jwPluginName'`
23* **id** (optional) e.g. `id='myHtmlElementId'`
24* **data** (required) e.g. `data='{ "formatting" : "JSON", "wellFormedJSON" : true, "pi" : 3.1415926, "myArray" : [ ] }'`
25
26The attributes *must* be enclosed in *single* quotes. The **name** attribute should reference a Jokuwiki capable plugin and is also the class of the div element created to contain the plugin. The **id** attribute is optional and maps directly to the id of the div element. If it is omitted a unique id will be generated. The **style** attribute allows for the class CSS to be overridden if the site configuration allows for inline HTML. The **noscript** element is written inside noscript tags. If inline HTML is enabled in the config, then the noscript content is sent to the browser as is (i.e. may contain HTML markup). If the configuration does not allow for HTML, then it is filtered by htmlentities.
27
28The data attribute must contain a valid JSON string. This should not have a propery 'id' at the root level. The id of the containing div is added to the JSON string and the contents passed to the initiator for the javascript.
29
30Additional content may be added between the opening and closing jw tags. This will be parsed by Dokuwiki and hence may contain the usual markup.
31
32The jwHelloWorld example at the start of the USAGE section will be sent to the browser as:
33```html
34<div id='greetingDiv'
35 class='jwHelloWorld'
36 style='width:100px;height=40px'
37 data-jw='
38 {
39 "jokuwiki" : "jwHelloWorld",
40 "data": {
41 "id" : "greetingDiv"
42 "say" : "Hello World"
43 }
44 }'
45 >
46 <noscript>Javascript is disabled</noscript>
47 </div>
48```
49
50Not exactly rocket science so far!
51
52The Javascript from the jwHelloworld plugin will then use this data to render a speech bubble callout on the page.
53
54Note that due to the structure of the Dokuwiki plugin system, jwHelloworld must
55be installed as seperate plugin and is not bundled here - but is available on the same site as Jokuwiki itself.
56
57## Speed enhancement ##
58
59 - Since processing of the content (arguments to the initiator) is deferred, the javascript need not be loaded before the Jokuwiki tag is declared in the html - i.e. script tags can be moved to the bottom, and/or use the defer/async tags or be loaded via AJAX. In short, the page is not blocked loading javascript content.
60 - Even without the overhead of jQuery, the amount of content which is different between individual pages is often less than 50% of the data downloaded from the server. Jokuwiki provides hooks to integrate [PJAX](https://github.com/defunkt/jquery-pjax) into templates and thereby reducing the total traffic on page transitions. See [startPjax](https://github.com/symcbean/startPjax) for an example implementation.
61 - Actually, halving the content size isn't really a //great// performance saving - with HTTP it's all about the latency. But eliminating the need to re-fetch (even from cache), re-parse and re-compile the javascript on each page (along with parsing the CSS) does represent a big performance boost - on a bare installation of Weatherwax on my development machine this saves between 250 and 350 milliseconds per page load.
62
63## Security Enhancement ##
64
65Allowing inline javascript is a big security risk. Adopting a strict [Content Security Policy](https://developer.chrome.com/extensions/contentSecurityPolicy.html), rejecting inline javascript //and inline CSS// almost completely eliminates cross-site scripting vulnerabilities. Note that the versions of Dokuwiki up to, and including Weatherwax inject inline Javascript to define variables including JSINFO and SIG.
66
67## Compatible Templates ##
68
69Jokuwiki should be compatible with all templates, however the additional functionality jokuwiki was designed to support (much faster page loading, better security) require a template which is jokuwiki aware.
70
71PJAX page loading and Content Security Policy support requires changes to the template - and Jokuwiki simplifies the implementation of these changes. The starterPjax template is a demonstration of PJAX and CSP capable template using Jokuwiki; the template defines the PJAX container Div and also injects a Jokuwiki widget to update the page title.
72
73## Source code and installation ##
74
75
76## Versions ##
77
78 * **2013-06-24** : First version.
79
80## ToDo ##
81
82 * Add a built-in widget to initialize Dokuwiki variables
83 * Add an AJAX save/load interface for arbitrary JSON data - serverside and clientside
84 * Add a JSON editor in the Dokuwiki editor
85
86
87## Discussion ##
88### Writing a compatible plugin ###
89#### Javascript ####
90Your plugin has to tell Jokuwiki how it is invoked, hence the script.js for your plugin must register itself, e.g.
91```javascript
92function jwMyPlugin_initiator(data)
93{
94 var el=document.getElementById(data.id);
95 el.innerHTML += 'Hello World';
96}
97
98if (jokuwiki) {
99 jokuwiki.register('jwMyPlugin', jwMyPlugin_initiator);
100}
101```
102
103The .register method takes 3 parameters:
104 * the plugin name (by convention, jokuwiki plugins start with 'jw' but this is not required)
105 * a function to call. To comply with a strict Content Security Policy this must be a function - but can be an anonymous function. This has a single argument - the data object declared inside the JSON string.
106 * a URL of a javascript file to load asynchronously
107Since the loading of a new content via PJAX will not trigger a onload event for the window, you should not attempt to attach your own handler for this directly nor via the jQuery.ready function: in both cases the lists of actions are fired once and cleared down after executing once. When a page transition occurs, either via a full page load or via a PJAX fetch, Jokuwiki will invoke the initiators for the widgets.
108
109Related to this, Jokuwiki implements it's own asynchronous script loader. Unlike the jQuery.script method, this ensures that each script is only loaded/incorporated once into the current page *once*.
110
111To accommodate the asynchronous loading (and potentially out-of-sequence loading) of additional code from the server, Jokuwiki will try to initiate each widget several times. If the called method throws an exception or the initiator is not registered, Jokuwiki will put it back into the list of widgets it needs to initiate. If it does not throw an exception, or an internal timer expires, the widget will be removed from the queue.
112
113#### PHP code ####
114The Jokuwiki plugin intentionally provides no mechanism for directly populating the JSON data field. This should be implemented by your syntax.php plugin, which then writes a Jokuwiki HTML widget based on the parameters it parses.
115### Include a schema ###
116Although this has yet to be implemented, I would urge you to include a [JSON Schema](http://json-schema.org/|JSON schema) describing the data payload for your jwPlugin. At some point in the future I hope to add a form based editor for widgets, most likely [onde](http://exavolt.github.io/onde/). There are online tools, e.g. [[http://www.jsonschema.net/index.html]] for generating schemas from sample JSON documents.
117
118### Plugins outside the PJAX container ###
119Jokuwiki capable plugins can be placed outside the PJAX container, however these must have an explicit id declared.
120