source: main/trunk/greenstone3/web/interfaces/default/transform/layouts/webswing-collage.xsl@ 38966

Last change on this file since 38966 was 38965, checked in by anupama, 6 weeks ago

Some clean up.

File size: 17.6 KB
Line 
1<?xml version="1.0" encoding="UTF-8"?>
2<xsl:stylesheet version="1.0"
3 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
4 xmlns:java="http://xml.apache.org/xslt/java"
5 xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
6 xmlns:gslib="http://www.greenstone.org/skinning"
7 xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat"
8 extension-element-prefixes="java util"
9 exclude-result-prefixes="java util gsf">
10
11 <xsl:template name="webswing-embed-collage">
12 <link rel="stylesheet" href="/webswing-server/css/style.css" />
13 <div id="webswing-collage" class="webswing-element" data-webswing-instance="webswingInstance0" style="width: 800px; height: 400px;">
14
15 <div id="loading" class="ws-modal-container">
16 <div class="ws-login">
17 <div class="ws-login-content">
18 <div class="ws-spinner">
19 <div class="ws-spinner-dot-1"><xsl:comment>filler</xsl:comment></div>
20 <div class="ws-spinner-dot-2"><xsl:comment>filler</xsl:comment></div>
21 </div>
22 </div>
23 </div>
24 </div>
25
26 </div>
27
28 <gsf:script>
29 // https://www.webswing.org/docs/23.2/configure/applet.html
30 // https://www.webswing.org/docs/23.2/configure/swing.html
31 // https://www.webswing.org/docs/23.2/integrate/javascript-api?_h=customArgs%2Cargs#usage-with-customization-and-options
32 // https://www.webswing.org/docs/23.2/integrate/embed.html
33 // https://www.webswing.org/docs/20.1/integrate/urlparams.html
34 // https://www.webswing.org/docs/23.2/integrate/urlparams.html
35 // https://www.webswing.org/docs/20.1/integrate/customize.html
36 // https://www.webswing.org/docs/2.7/integrate/embed.html
37
38 var webswingInstance0 = {
39 options: {
40 autoStart: true,
41 //appletParams: {"collection":"smallbea", "library":"library"},
42 connectionUrl:'/webswing-server/collage',
43
44 customization: function(injector) {
45 injector.services.base.handleActionEvent = function(actionName, data, binaryData) {
46 //console.log("WebSwing actionEvent callback handler: called with actionName = " + actionName);
47
48 if (actionName === "openURL") {
49 var url = data;
50 // check if a target tab/window name has been specified
51 // TODO: Any better way of passing > 1 string between Java and JavaScript?
52 var index = url.indexOf(" - ");
53 if (index !== -1) {
54 var target = url.substring(index+3); // skip past " - " to get target name
55 url = url.substring(0, index);
56 // Note that target window name is not the same as target window title
57 // https://stackoverflow.com/questions/8051811/how-to-show-window-title-using-window-open
58 window.open(url, target);
59 } else {
60 window.open(url, '_blank');
61 }
62 } else if (actionName == "javaToWebswingJSConsoleLog") {
63 console.log("Got message from java:\n" + data);
64 }
65
66 }
67 }
68
69
70 }
71 };
72
73
74 // The applet jar files can just remain in web/applet where they are compiled up
75
76 if(!webswingInstance0.options.args) {
77 webswingInstance0.options.args="";
78 }
79
80 var verbosity = 3;
81 var appletEl = document.getElementById("collage-applet-element");
82
83 // Fill up webswingParams JSON record with non-dynamic values and other vals
84 // that may perhaps not be set on the applet element, to use as fallback
85 var webswingParams = {
86 //"webswing":1, // set in webswing.config.in to discourage editing
87 "verbosity": verbosity,
88 "gsdlversion":3,
89 "maxDepth": 500,
90 "maxDisplay": 25,
91 "refreshDelay": 1500,
92 "isJava2":"auto",
93 "bgcolor":"#96c29a"
94 };
95
96 if(!appletEl &amp;&amp; verbosity >= 4) {
97 console.log("No collage-applet-element on page. Using webswing params vals from pageResponse/XSLT.");
98 }
99
100 // The entirely javascript way of setting our webswing app parameters
101 // (does not read the parameters set on the applet element)
102
103 //https://stackoverflow.com/questions/25203124/how-to-get-base-url-with-jquery-or-javascript
104 var baseURL;
105 if(gs.requestInformation.baseURL) {
106 baseURL = window.location.protocol + gs.requestInformation.baseURL; // contains servlet
107 } else { // will this else block ever again need to be used?
108 baseURL = window.location.origin+window.location.pathname;
109 // webswingInstance0.options.args += "\"" + baseURL+ "?a=a&amp;rt=d&amp;s=GsdlCollageApplet&amp;c=smallbea\"";
110 var servlet_index = baseURL.indexOf("/"+gs.xsltParams.library_name);
111 if(servlet_index > 0) {
112 baseURL = baseURL.substring(0, servlet_index+1);
113 }
114 }
115
116 //var gs3CollImgPath = gs.xsltParams.library_name + "/sites/" + gs.xsltParams.site_name + "/collect/" + gs.cgiParams.c;
117 var gs3CollBrowsePath = gs.xsltParams.library_name + "/collection/" + gs.cgiParams.c + "/browse/" + gs.cgiParams.cl; // cl is classifier, e.g "CL3"
118
119 webswingParams["baseurl"] = baseURL;
120 webswingParams["collection"] = gs.cgiParams.c;
121 webswingParams["library"] = gs.xsltParams.library_name;
122 webswingParams["documentroot"] = gs.xsltParams.servlet_context;
123 webswingParams["hrefMustHave"] = gs3CollBrowsePath;
124 webswingParams["imageMustNotHave"] = "interfaces/";
125 webswingParams["imageType"] = ".jpg%.png";
126 webswingParams["classifier"] = gs.cgiParams.cl + ".1";
127
128
129 if(appletEl) { // get all available webswing config settings from applet element
130 if(verbosity >= 4) {
131 console.log("collage-applet-element on page, using its params where available.");
132 }
133 // If using the inactive/deprecated applet element as shim, instead of javascript
134 // working out the webswing config params from the pageRequest or XSLT variables:
135 // Get the webswing configuration arguments from the lingering applet html element,
136 // as a GS3 library designer may know to how to customize applet parameters
137 // better than they know javascript or how to construct webswing parameters.
138
139 // Now get the param subelements of the applet element
140 for (var webswingParam of Object.keys(webswingParams)) {
141 var querySelectorStr = "param[name='"+webswingParam+"']";
142 var appletParam = appletEl.querySelector(querySelectorStr);
143 if(appletParam) { // if this parameter was set on the applet
144 webswingParams[webswingParam] = appletParam.value;
145 } else {
146 if(verbosity>=3) {
147 console.log("Applet element doesn't supply param: " + webswingParam + ". Using fallback: " + webswingParams[webswingParam]);
148 }
149 }
150 }
151
152 }
153 verbosity = webswingParams["verbosity"]; // so JavaScript logging obeys user-supplied verbosity
154
155 // Special case: width and height are attributes of the applet tag not subelements
156 // and may need parsing.
157 // Control the width and height of the Java application launched with webswing by
158 // passing the width and height params set on the webswing element, unless an applet
159 // element is available. In that case try to get the dimensions from the applet tag.
160 // https://stackoverflow.com/questions/21851633/get-height-from-style-attribute
161 var w = appletEl ? appletEl.getAttribute("width") : document.getElementById("webswing-collage").style.width;
162 var h = appletEl ? appletEl.getAttribute("height") : document.getElementById("webswing-collage").style.height;
163 webswingParams["width"] = stripUnitOffAttribute("px", w);
164 webswingParams["height"] = stripUnitOffAttribute("px", h);
165
166 // Webswing only uses the width and height set on the webswing-collage element
167 // Override this with any dimensions set on any applet element, as that is user-controlled
168 // from GLI. style.setProperty failed without the important parameter to force the setting.
169 // https://stackoverflow.com/questions/5191478/changing-element-style-attribute-dynamically-using-javascript
170 document.getElementById("webswing-collage").style.setProperty("width", webswingParams["width"] + "px", "important");
171 document.getElementById("webswing-collage").style.setProperty("height", webswingParams["height"] + "px", "important");
172
173 if(verbosity >= 3) {
174 console.log("@@@ Final verbosity: " + webswingParams["verbosity"]
175 + ", width: " + webswingParams["width"] + ", height: " + webswingParams["height"]);
176 }
177 // Having collected all the webswingParams, we can finally build up the single webswing customArgs string
178 var _args = "";
179 for (var webswingParam of Object.keys(webswingParams)) {
180 _args += "--" + webswingParam + " \"" + webswingParams[webswingParam] + "\" "; // space at end to precede next arg
181 }
182 webswingInstance0.options.args += _args.substring(0, _args.length-1); // remove extra space at end
183
184
185 // Set to false if running the webswing instance as a webswing application. This has
186 // nothing to do with if the applet element exists on the page: it can be on the page
187 // and you can still decide to run GsdlCollage as a webswing application. If switching
188 // between running as application and applet, remember to adjust webswing.config.in
189 // Either way, since we still push the deprecated applet element onto the page, we can use
190 // it as a shim: use JavaScript to read its configuration params and pass them to webswing.
191
192 var isWebswingRunAsApplet = true;
193
194 // When run as webswing applet (instead of as webswing application), the webswing var
195 // customargs becomes assigned as the value of key "xtraParams" in webswing.config.in
196 // and is a string of key-value pairs. And our Java code is able to successfully
197 // receive these key-valye pairs in the form k1::v1;;k2::v2;; (URL form of key-value
198 // pairs is not easy to pass in from JavaScript through webswing into Java).
199
200 if(isWebswingRunAsApplet) {
201 var xtraParams = webswingInstance0.options.args;
202 var hyphens_index = xtraParams.indexOf("--");
203 var spaceAfterKey = -1;
204 while(hyphens_index >= 0) {
205 // Locate start of value in each key-value pair
206 spaceAfterKey = xtraParams.indexOf(" ", hyphens_index);
207 if(spaceAfterKey >= 0) {
208 // insert (splice in) the key-value internal separator,creating "key::value"
209 xtraParams = [xtraParams.slice(0, spaceAfterKey), "::", xtraParams.slice(spaceAfterKey+1)].join('');
210 }
211 hyphens_index = xtraParams.indexOf("--", hyphens_index+2);
212 }
213 // now add separator *between* each key-value pairs with ;;
214 xtraParams = xtraParams.replaceAll(" --", ";;");
215 webswingInstance0.options.args = xtraParams.substring(2);
216 }
217
218 if(verbosity >= 4) {
219 console.log("args: " + webswingInstance0.options.args);
220 }
221
222 function getParam(name) {
223 name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
224 var results = new RegExp("[\\?&amp;]" + name + "=([^&amp;#]*)").exec(location.href);
225 return results == null ? null : decodeURIComponent(results[1]);
226 }
227
228 function stripUnitOffAttribute(unit, attr) {
229 // common code, regardless of whether we use the applet element as a shim or not
230 var suffixIndex = 0;
231 if(attr) {
232 suffixIndex = attr.indexOf(unit);
233 if(suffixIndex>0) {
234 attr = attr.substring(0, suffixIndex);
235 }
236 }
237 return attr;
238 }
239 </gsf:script>
240
241
242 <script data-webswing-global-var="webswing">
243 <xsl:text disable-output-escaping="yes">
244 var unloaded = false;
245
246 (function (window, document) {
247 var loader = function () {
248
249 unloaded = false; // reset state, because we are reloading the webswing app
250
251 var baseUrl = '/webswing-server/collage';
252 baseUrl = baseUrl.indexOf("/", baseUrl.length - 1) !== -1 ? baseUrl : (baseUrl + "/");
253 var xmlhttp = new XMLHttpRequest();
254 xmlhttp.onreadystatechange = function () {
255 if (xmlhttp.readyState == XMLHttpRequest.DONE) {
256 var version = xmlhttp.status == 200 ? xmlhttp.responseText : "undefined";
257 var script = document.createElement("script"),
258 tag = document.getElementsByTagName("script")[0];
259 script.src = baseUrl + "javascript/webswing-embed.js?version=" + version;
260 tag.parentNode.insertBefore(script, tag);
261 }
262 };
263 xmlhttp.open("GET", baseUrl + "rest/version", true);
264 xmlhttp.send();
265 };
266
267 var navigatingAway = function () {
268 if(verbosity >= 4) {
269 console.log("*** navigatingAway called");
270 }
271
272 // Multiple eventlisteners are registered to call navigatingAway, as not all are
273 // triggered in all contexts (desktop vs mobile vs older browsers)
274 // https://developer.mozilla.org/en-US/docs/Web/API/Window/unload_event
275 // We work with multiple eventlisteners to ensure we cleanup webswing collage app when
276 // user navigates away from page. But we should only do the cleanup once, even if *all*
277 // event handlers got triggered. We use the unloaded var to ensure we cleanup only once
278 if(!unloaded) {
279
280 // Sadly, sending messages to Java from JavaScript using the webswing API does not
281 // work for us.
282 // So we do not succeed in calling our handler in Java for our custom action
283 // navigatingAway or even testJavaCall, like this (Java does not get the message):
284 //
285 // if(typeof webswingInstance0.setControl === 'function') {
286 // Allow sending user events to swing application
287 // https://www.webswing.org/docs/20.2/integrate/embed.html
288 // webswingInstance0.setControl(true);
289 //
290 // console.log("@@@ Asking webswing to stop the collage application");
291 // webswingInstance0.performAction({actionName: "navigatingAway"});
292 /// webswingInstance0.performAction({actionName: "testJavaCall"});
293 // // unload only once even if multiple listeners call navigatingAway() callback
294 // unloaded = true;
295 // }
296 //
297 // Fortunately the official webswing kill() function on the webswing
298 // instance is successfully sent and detected on the Java end.
299 // In fact, the behaviour on kill() is a little more complicated:
300 // kill() is able to stop the GsdlCollageApplet when collage runs as an
301 // application, because the default webswing behaviour is to generate a
302 // WindowClosing event, which GsdlCollage is written to respond to when run as an
303 // application).
304 // When GsdlCollageApplet is run as an applet, it cannot detect and respond to
305 // the regular WindowClosing event and the Java end needs to implement the webswing
306 // shutdown-handler to cleanly stop and exit.
307
308 if(typeof webswingInstance0.kill === 'function') { // it should exist
309 if(verbosity >= 3) {
310 console.log("@@@ Telling webswing to stop the collage application/applet");
311 }
312 webswingInstance0.kill();
313 unloaded = true; // do not unload again, if multiple listeners call navigatingAway() callback function
314 if(verbosity >= 4) {
315 console.log("@@@@ unloaded");
316 }
317 } // else cannot call method that does not exist
318 } else {
319 if(verbosity >= 4) {
320 console.log("@@@@ already unloaded.");
321 }
322 }
323
324 };
325 window.addEventListener ? window.addEventListener("load", loader, false) : window.attachEvent("onload", loader);
326
327
328 // When the user navigates away from this page or reloads it, we want to
329 // shutdown the webswing Java application/applet.
330
331 // https://developer.mozilla.org/en-US/docs/Web/API/Window/unload_event
332 // unload is discouraged as it is not always supported (some mobile devices),
333 // so we listen for pagehide events too. Visibilitychange events happen on minimising the
334 // window or another tab getting focus. So do not stop the app on mere visibilitychange.
335 // https://dev.to/amersikira/top-3-ways-to-easily-detect-when-a-user-leaves-a-page-using-javascript-2ce4
336
337 // Pagehide is also fired when user presses back button: https://developer.mozilla.org/en-US/docs/Web/API/Window/pagehide_event
338 // https://stackoverflow.com/questions/15925251/trigger-an-event-when-user-navigates-away
339
340 // Order of registering listeners may matter and be useful:
341 // https://stackoverflow.com/questions/31852179/javascript-event-listeners-firing-order
342 // https://stackoverflow.com/questions/2706109/are-javascript-dom-event-handlers-called-in-order-of-registration
343 // https://medium.com/@olofbaage/javascript-essentials-all-you-need-to-know-about-event-listeners-8ed889bffb8d
344 // Event support detection
345 // https://stackoverflow.com/questions/158673/onbeforeunload-support-detection
346 // https://stackoverflow.com/questions/2877393/detecting-support-for-a-given-javascript-event
347 // http://perfectionkills.com/detecting-event-support-without-browser-sniffing
348
349 // Does onUnload not leave enough time to get webswing to shutdown? OnBeforeUnload works
350 // https://caniuse.com/?search=beforeunload
351
352 window.addEventListener ? window.addEventListener("beforeunload", navigatingAway, false) : window.attachEvent("onbeforeunload", navigatingAway);
353 window.addEventListener ? window.addEventListener("pagehide", navigatingAway, false) : window.attachEvent("onpagehide", navigatingAway);
354 //window.addEventListener ? window.addEventListener("visibilitychange", navigatingAway, false) : window.attachEvent("onvisibilitychange", navigatingAway);
355
356 })(window, document);
357 </xsl:text>
358 </script>
359
360 </xsl:template>
361
362</xsl:stylesheet>
Note: See TracBrowser for help on using the repository browser.