1 | /*
|
---|
2 |
|
---|
3 | Greenstone 3 'Client-side transformer'
|
---|
4 | Performs client-side transformations of XSLT, using HTML5 local storage (simulated if the browser doesn't support it).
|
---|
5 |
|
---|
6 | Currently only supports Firefox 3 and greater, since it's the only browser (at the time of writing) that can do this properly.
|
---|
7 |
|
---|
8 | @author Steven McTainsh
|
---|
9 | @date 14/02/2011
|
---|
10 |
|
---|
11 | */
|
---|
12 |
|
---|
13 | /* These URLs and file paths are fetched dynamically */
|
---|
14 | //var gsweb = ""; // The file path to the Greenstone 3 web directory
|
---|
15 | //var gsurl = ""; // The root URL for this Greenstone 3 installation
|
---|
16 |
|
---|
17 | /* Misc. switches and paths */
|
---|
18 | var keyUrl = ''; // Used across methods to build up query string for text retrieval (client-side transformed version)
|
---|
19 | var on = true; // Set to false to disable operation
|
---|
20 | var debug = true;
|
---|
21 |
|
---|
22 | var index = 0; // Used for query array (to keep track of number of elements)
|
---|
23 | var deferredEls = new Array(); // Elements to defer text retrieval for until later
|
---|
24 | var queryArr = new Array(); // Text to query for (the text for the corresponding deferred element)
|
---|
25 |
|
---|
26 | function notSupported() {
|
---|
27 | // Set not supported cookie here
|
---|
28 | document.cookie = 'supportsXSLT=false; expires=0; path=/';
|
---|
29 | // Fall back to server version
|
---|
30 | var location = window.location.search.substring(1);
|
---|
31 | if(location == '') {
|
---|
32 | // Start with a question mark
|
---|
33 | location = window.location + "?o=server";
|
---|
34 | } else {
|
---|
35 | // Start with an ampersand
|
---|
36 | location = window.location + "&o=server";
|
---|
37 | }
|
---|
38 | window.location = location;
|
---|
39 | }
|
---|
40 |
|
---|
41 | /*
|
---|
42 | $(document).ready(function() {
|
---|
43 | console.log("Client-side XSLT: Document is ready");
|
---|
44 |
|
---|
45 | if (isSupported()) {
|
---|
46 | transform(false);
|
---|
47 | }
|
---|
48 | else {
|
---|
49 | notSupported();
|
---|
50 | }
|
---|
51 | });
|
---|
52 | */
|
---|
53 |
|
---|
54 |
|
---|
55 | var onSaxonLoad = function() {
|
---|
56 |
|
---|
57 | try {
|
---|
58 | var rooturl = window.location.pathname;
|
---|
59 | var queryStr = window.location.search.substring(1);
|
---|
60 | queryStr = queryStr.replace(/o=.*?(&|$)/g,"");
|
---|
61 | if (queryStr != '') {
|
---|
62 | queryStr += "&";
|
---|
63 | }
|
---|
64 | queryStr += "o=clientside";
|
---|
65 |
|
---|
66 | console.log("*** rooturl = " + rooturl);
|
---|
67 | console.log("*** queryStr = " + queryStr);
|
---|
68 |
|
---|
69 | var skindoc = "";
|
---|
70 | var xmldoc = "";
|
---|
71 |
|
---|
72 | $.get(rooturl + "?" + queryStr, function(data) {
|
---|
73 |
|
---|
74 | //dataStr = dataStr.replace(/gs3:id/g, "gs3id");
|
---|
75 |
|
---|
76 | //data = parseFromString(dataStr, "text/xml");
|
---|
77 |
|
---|
78 | var toplevel_children = $(data).children().eq(0).children();
|
---|
79 | var skindoc = toplevel_children[0];
|
---|
80 | var xmldoc = toplevel_children[1];
|
---|
81 |
|
---|
82 |
|
---|
83 | var site_name = $('xsltparams>param[name=site_name]', xmldoc).text();
|
---|
84 | var library_name = $('xsltparams>param[name=library_name]', xmldoc).text();
|
---|
85 | var interface_name = $('xsltparams>param[name=interface_name]', xmldoc).text();
|
---|
86 |
|
---|
87 | //// Convert temporarily to text here
|
---|
88 | skindoc = convertToString(skindoc);
|
---|
89 | xmldoc = convertToString(xmldoc);
|
---|
90 |
|
---|
91 | //// This could just be done on the server (later)
|
---|
92 | ////data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" /*+ "<?xml-stylesheet type=\"text/xsl\" href=\"" + skinurl + "\"?>\r\n"*/ + data;
|
---|
93 | //// replace all!
|
---|
94 | //// Be careful with regex syntax and the use of special characters!
|
---|
95 | //skindoc = skindoc.replace(/util\:exists\(\$meta, ''\)/g, "$meta!=''"); // For now - use regex instead
|
---|
96 | //skindoc = skindoc.replace(/%3A/g, ":"); // undo colon escaping
|
---|
97 |
|
---|
98 | //skindoc = skindoc.replace(/util\:.+?\(\.*?\)/g, "true");
|
---|
99 |
|
---|
100 | skindoc = skindoc.replace(/<xslt:stylesheet\s+/,"<xslt:stylesheet xmlns:ixsl=\"http://saxonica.com/ns/interactiveXSLT\" xmlns:js=\"http://saxonica.com/ns/globalJS\" ");
|
---|
101 | //extension-element-prefixes="ixsl" exclude-result-prefixes="xs xd d js"
|
---|
102 | skindoc = skindoc.replace(/extension-element-prefixes="(.*?)"/,"extension-element-prefixes=\"$1 ixsl\"");
|
---|
103 | //skindoc = skindoc.replace(/exclude-result-prefixes="(.*?)"/,"exclude-result-prefixes=\"$1 js\"");
|
---|
104 |
|
---|
105 |
|
---|
106 | skindoc = skindoc.replace(/util\:exists\(\$meta, ''\)/g, "$meta!=''"); // For now - use regex instead
|
---|
107 | skindoc = skindoc.replace(/util:replace\((.*?)\)/g, "replace($1)"); // exists in XSLT 2.0
|
---|
108 | skindoc = skindoc.replace(/util:storeString\((.+?),(.+)?\)/g, "$1=$2");
|
---|
109 | skindoc = skindoc.replace(/util:getString\((.+?)\)/g, "$1");
|
---|
110 | skindoc = skindoc.replace(/util:getDetailFromDate\((.+?),.+?,.+?\)/g, "$1");
|
---|
111 |
|
---|
112 | //skindoc = skindoc.replace(/util:getNumberedItem\(([^,]+),([^,]+)\)$/,"js:getNumberedItem($1,$2)"); // never tested
|
---|
113 |
|
---|
114 | //skindoc = skindoc.replace(/\{\{/,"\\{");
|
---|
115 | //skindoc = skindoc.replace(/\}\}/,"\\}");
|
---|
116 | //skindoc = skindoc.replace(/"js:[^"]+"/g, "js:console.log('foo')");
|
---|
117 |
|
---|
118 | // Convert to XML
|
---|
119 | xmldoc = parseFromString(xmldoc, "text/xml");
|
---|
120 | skindoc = parseFromString(skindoc, "text/xml");
|
---|
121 |
|
---|
122 | var output = '';
|
---|
123 | /*
|
---|
124 | var params = { 'library_name': library_name, 'interface_name': interface_name };
|
---|
125 | var proc = Saxon.run( {
|
---|
126 | stylesheet: skindoc,
|
---|
127 | source: xmldoc,
|
---|
128 | parameters: params
|
---|
129 | });
|
---|
130 | */
|
---|
131 |
|
---|
132 | /*
|
---|
133 | var xml = Saxon.requestXML("http://localhost:8383/greenstone3/mozarts-library/collection/digital-music-stand/page/about?o=xml");
|
---|
134 | var xsl = Saxon.requestXML("http://localhost:8383/greenstone3/mozarts-library/collection/digital-music-stand/page/about?o=skinandlibdocfinal");
|
---|
135 | */
|
---|
136 | var proc = Saxon.newXSLT20Processor(skindoc);
|
---|
137 |
|
---|
138 | proc.setParameter(null, 'library_name', library_name);
|
---|
139 | proc.setParameter(null, 'interface_name', interface_name);
|
---|
140 | proc.setParameter(null, 'site_name', site_name);
|
---|
141 |
|
---|
142 | result = proc.transformToDocument(xmldoc);
|
---|
143 | xmlSer = new XMLSerializer();
|
---|
144 | output = xmlSer.serializeToString(result);
|
---|
145 |
|
---|
146 | var doc = document.open();
|
---|
147 | doc.write(output);
|
---|
148 | doc.close();
|
---|
149 |
|
---|
150 | document.cookie = 'supportsXSLT=true; expires=0; path=/';
|
---|
151 |
|
---|
152 |
|
---|
153 |
|
---|
154 | }, 'xml');
|
---|
155 | }
|
---|
156 | catch (e) {
|
---|
157 | if(trial) {
|
---|
158 | notSupportedCookie();
|
---|
159 | }
|
---|
160 | else {
|
---|
161 | notSupported();
|
---|
162 | }
|
---|
163 | }
|
---|
164 | }
|
---|
165 |
|
---|
166 |
|
---|
167 |
|
---|
168 |
|
---|
169 | function transform(trial) {
|
---|
170 |
|
---|
171 | //alert("transform(): trial = " + trial);
|
---|
172 |
|
---|
173 | try {
|
---|
174 | var rooturl = window.location.pathname;
|
---|
175 | var queryStr = window.location.search.substring(1);
|
---|
176 | queryStr = queryStr.replace(/o=.*?(&|$)/g,"");
|
---|
177 | if (queryStr != '') {
|
---|
178 | queryStr += "&";
|
---|
179 | }
|
---|
180 | queryStr += "o=clientside";
|
---|
181 |
|
---|
182 | console.log("*** rooturl = " + rooturl);
|
---|
183 | console.log("*** queryStr = " + queryStr);
|
---|
184 |
|
---|
185 | var skindoc = "";
|
---|
186 | var xmldoc = "";
|
---|
187 |
|
---|
188 | $.get(rooturl + "?" + queryStr, function(dataStr) {
|
---|
189 | //dataStr = dataStr.trim();
|
---|
190 | dataStr = dataStr.replace(/gs3:id/g, "gs3id");
|
---|
191 | //dataStr = dataStr.replace(/&/g,"&");
|
---|
192 | //dataStr = dataStr.replace(/&quot;/g,""");
|
---|
193 | //dataStr = dataStr.replace(/&lt;/g,"<");
|
---|
194 | //dataStr = dataStr.replace(/&gt;/g,">");
|
---|
195 | //dataStr = dataStr.replace(/&amp;/g,"&");
|
---|
196 |
|
---|
197 | data = parseFromString(dataStr, "text/xml");
|
---|
198 |
|
---|
199 | var toplevel_children = $(data).children().eq(0).children();
|
---|
200 | var skindoc = toplevel_children[0];
|
---|
201 | var xmldoc = toplevel_children[1];
|
---|
202 |
|
---|
203 |
|
---|
204 | //gsurl = $($(xmldoc).find("metadata[name=siteURL]")[0]).text();
|
---|
205 | //gsurl = $(xmldoc).find("pageRequest").attr("baseURL");
|
---|
206 | var site_name = $('xsltparams>param[name=site_name]', xmldoc).text();
|
---|
207 | var library_name = $('xsltparams>param[name=library_name]', xmldoc).text();
|
---|
208 | var interface_name = $('xsltparams>param[name=interface_name]', xmldoc).text();
|
---|
209 |
|
---|
210 | //gsurl = $(xmldoc).find("pageRequest").attr("baseURL") + site_name;
|
---|
211 | //gsweb = new RegExp($($(xmldoc).find("param[name=filepath]")[0]).text().replace(/\\/g, "\\\\"), "g");
|
---|
212 |
|
---|
213 | //// Convert temporarily to text here
|
---|
214 | skindoc = convertToString(skindoc);
|
---|
215 | xmldoc = convertToString(xmldoc);
|
---|
216 |
|
---|
217 | //// This could just be done on the server (later)
|
---|
218 | ////data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" /*+ "<?xml-stylesheet type=\"text/xsl\" href=\"" + skinurl + "\"?>\r\n"*/ + data;
|
---|
219 | //// replace all!
|
---|
220 | //// Be careful with regex syntax and the use of special characters!
|
---|
221 | //skindoc = skindoc.replace(/util\:exists\(\$meta, ''\)/g, "$meta!=''"); // For now - use regex instead
|
---|
222 | //skindoc = skindoc.replace(/%3A/g, ":"); // undo colon escaping
|
---|
223 |
|
---|
224 | //skindoc = skindoc.replace(/util\:.+?\(\.*?\)/g, "true");
|
---|
225 |
|
---|
226 | skindoc = skindoc.replace(/util\:exists\(\$meta, ''\)/g, "$meta!=''"); // For now - use regex instead
|
---|
227 | skindoc = skindoc.replace(/util:storeString\((.+?),(.+)?\)/g, "$1=$2");
|
---|
228 | skindoc = skindoc.replace(/util:getString\((.+?)\)/g, "$1");
|
---|
229 | skindoc = skindoc.replace(/util:getDetailFromDate\((.+?),.+?,.+?\)/g, "$1");
|
---|
230 |
|
---|
231 |
|
---|
232 | // Convert to XML
|
---|
233 | xmldoc = parseFromString(xmldoc, "text/xml");
|
---|
234 | skindoc = parseFromString(skindoc, "text/xml");
|
---|
235 |
|
---|
236 | var output = '';
|
---|
237 |
|
---|
238 | // And post-process...
|
---|
239 | if(window.ActiveXObject) {
|
---|
240 | // IE
|
---|
241 | var procFactory = new ActiveXObject("MSXML2.XSLTemplate");
|
---|
242 | procFactory.stylesheet = skindoc;
|
---|
243 | var proc = procFactory.createProcessor();
|
---|
244 | proc.input = xmldoc;
|
---|
245 |
|
---|
246 | proc.addParameter('library_name', library_name);
|
---|
247 | proc.addParameter('interface_name', interface_name);
|
---|
248 |
|
---|
249 | proc.transform();
|
---|
250 | output = proc.output;
|
---|
251 | }
|
---|
252 | else {
|
---|
253 | // Firefox, Chrome ...
|
---|
254 | xsltProc = new XSLTProcessor();
|
---|
255 | // The leading slash is oh-so important here
|
---|
256 | xsltProc.setParameter(null, 'library_name', library_name);
|
---|
257 | xsltProc.setParameter(null, 'interface_name', interface_name);
|
---|
258 | try {
|
---|
259 | xsltProc.importStylesheet(skindoc);
|
---|
260 | }
|
---|
261 | catch(e) {
|
---|
262 | alert("Malformed importStyle sheet:" + e.message + "\n======\nSee web browser console for more details");
|
---|
263 | // Look for util: of java:
|
---|
264 | if (debug) {
|
---|
265 | console.error("Stylesheet:\n" + skindoc.documentElement.outerHTML);
|
---|
266 | }
|
---|
267 | }
|
---|
268 |
|
---|
269 | //
|
---|
270 | try {
|
---|
271 | result = xsltProc.transformToDocument(xmldoc);
|
---|
272 | xmlSer = new XMLSerializer();
|
---|
273 | output = xmlSer.serializeToString(result);
|
---|
274 | }
|
---|
275 | catch(e) {
|
---|
276 | alert("XSL Transform failed:" + e.message + "\n======\nSee web browser console for more details");
|
---|
277 | console.error("doc:\n" + convertToString(xmldoc) + "\n========\nStylesheet:\n" + convertToString(skindoc));
|
---|
278 | }
|
---|
279 | }
|
---|
280 |
|
---|
281 | var doc = document.open();
|
---|
282 | doc.write(output);
|
---|
283 | doc.close();
|
---|
284 |
|
---|
285 | document.cookie = 'supportsXSLT=true; expires=0; path=/';
|
---|
286 |
|
---|
287 | }, 'text');
|
---|
288 | }
|
---|
289 | catch (e) {
|
---|
290 | if(trial) {
|
---|
291 | notSupportedCookie();
|
---|
292 | }
|
---|
293 | else {
|
---|
294 | notSupported();
|
---|
295 | }
|
---|
296 | }
|
---|
297 | }
|
---|
298 |
|
---|
299 | function notSupportedCookie() {
|
---|
300 | document.cookie = 'supportsXSLT=false; expires=0; path=/';
|
---|
301 | }
|
---|
302 |
|
---|
303 |
|
---|
304 | // Method equivalent to PHP's in_array method
|
---|
305 | function contains(array, value) {
|
---|
306 |
|
---|
307 | for(var val in array)
|
---|
308 | if(array[val] == value)
|
---|
309 | return true;
|
---|
310 |
|
---|
311 | return false;
|
---|
312 | }
|
---|
313 |
|
---|
314 | // Method equivalent to PHP's own
|
---|
315 | function print_r(arr) {
|
---|
316 |
|
---|
317 | var result = "";
|
---|
318 |
|
---|
319 | for(var a in arr) {
|
---|
320 | result += a + " => " + arr[a] + "\r\n";
|
---|
321 | }
|
---|
322 |
|
---|
323 | return result;
|
---|
324 | }
|
---|
325 |
|
---|
326 | function convertToString(content) {
|
---|
327 | try {
|
---|
328 | // If this fails, it's another indication that the browser doesn't have the support we need
|
---|
329 | if(typeof XMLSerializer != 'undefined') {
|
---|
330 | return (new XMLSerializer()).serializeToString(content);
|
---|
331 | } else {
|
---|
332 | return content.xml;
|
---|
333 | }
|
---|
334 | }
|
---|
335 | catch (e) {
|
---|
336 | notSupported();
|
---|
337 | }
|
---|
338 | }
|
---|
339 |
|
---|
340 | function parseFromString(content, contentType) {
|
---|
341 | try {
|
---|
342 | var retobj;
|
---|
343 |
|
---|
344 | if(typeof window.DOMParser != 'undefined') {
|
---|
345 | // Firefox, Chrome
|
---|
346 | retobj = (new DOMParser()).parseFromString(content, contentType);
|
---|
347 | } else {
|
---|
348 | // IE
|
---|
349 | var retobj = new ActiveXObject("Microsoft.XMLDOM");
|
---|
350 | retobj.async = "false";
|
---|
351 | retobj.loadXML(content);
|
---|
352 | }
|
---|
353 |
|
---|
354 | return retobj;
|
---|
355 | }
|
---|
356 | catch(e) {
|
---|
357 | var obj = new ActiveXObject('MSXML.DomDocument');
|
---|
358 | obj.async = false; obj.loadXML(content);
|
---|
359 | return obj;
|
---|
360 | }
|
---|
361 | }
|
---|
362 |
|
---|
363 | function isSupported() {
|
---|
364 |
|
---|
365 | return true;
|
---|
366 | // change test below to simple XML + XSL Transform
|
---|
367 |
|
---|
368 | /*
|
---|
369 | // Are cookies enabled?
|
---|
370 | if(navigator.cookieEnabled && typeof navigator.cookieEnabled != 'undefined') {
|
---|
371 | // Is there a cookie?
|
---|
372 | if(document.cookie.indexOf('supportsXSLT=') > -1) {
|
---|
373 | // Cookie exists - don't try the transformation, as the server will
|
---|
374 | // read the cookie and determine which version to serve up.
|
---|
375 | // If it happens to be client-side, allow transformation to proceed
|
---|
376 | return (document.cookie.indexOf('supportsXSLT=true') > -1);
|
---|
377 | } else {
|
---|
378 | // Cookie doesn't exist - test!
|
---|
379 | transform(true);
|
---|
380 | applyText(true);
|
---|
381 | return (document.cookie.indexOf('supportsXSLT=true') > -1);
|
---|
382 | }
|
---|
383 | } else {
|
---|
384 | return false;
|
---|
385 | }
|
---|
386 | */
|
---|
387 | }
|
---|
388 |
|
---|
389 | /* Simulating web storage for browsers that don't support it */
|
---|
390 | /* Credit: http://www.thewojogroup.com/2010/01/simulating-html5-local-storage/ */
|
---|
391 | (function(){var k=this;if(!k.localStorage&&navigator.cookieEnabled){var x="storageData_",y="++",z="::",l=function(a,c,b){var e=new Date;e.setTime(e.getTime()+b);b="; expires="+e.toGMTString();document.cookie=a+"="+c+b+"; path=/"},h=function(a){a=a+"=";for(var c=document.cookie.split(";"),b=0,e=c.length;b<e;b++){for(var d=c[b];d.charAt(0)==" ";)d=d.substring(1,d.length);if(d.indexOf(a)===0)return d.substring(a.length,d.length)}return null},m=function(a){l(a,"",-1)},i=function(){for(var a="",c=0;h(y+c)!==null;)a+=h(y+
|
---|
392 | c++);return a==""?[]:a.split(y)},n=function(a){for(var c=Math.ceil(a.length/4E3),b=0;b<c||h(y+b)!==null;){b<c?l(y+b,a.substr(b*4E3,(b+1)*4E3>a.length?a.length-b*4E3:4E3),2592E3):m(y+b);b++}},f=k.localStorage={length:0,setItem:function(a,c){var b=i(),e=0,d=b.length,g=false;for(e=0;e<d;e++){var j=b[e].split(z);if(j[0]==a){j[1]=c;g=true;b[e]=j.join(z);e=d}}if(!g){b.push(a+z+c.replace(/::/g,": :").replace(/\+\+/g,"+ +"));this.a.push(a);this.length++}n(b.join(y))},
|
---|
393 | getItem:function(a){var c=i(),b=0,e=c.length;for(b=0;b<e;b++){var d=c[b].split(z);if(d[0]==a&&d[1])return d[1]}return null},removeItem:function(a){var c=i(),b=0,e=c.length,d=false,g=[];for(b=0;b<e;b++)if(c[b].split(z)[0]!=a)g.push(c[b]);else d=true;if(d){n(g.join(y));o()}},clear:function(){for(var a=0;h(y+a)!==null;)m(y+a++);this.a=[];this.length=0},key:function(a){return a<this.length?this.a[a]:null},a:[]},o=function(){f.a=i();for(var a=0;f.a[a];)f.a[a]=f.a[a++].split(z)[0];
|
---|
394 | f.length=f.a.length};o()}})();
|
---|