Dự án JavaFX miễn phí

1 /*
2  * Copyright (c)
2006, 2017, Oracle and/or its affiliates. All rights reserved.
3  * ORACLE PROPRIETARY/CONFIDENTIAL. Use
is subject to license terms.
4  */
5
6 /**
7   The Java Deployment Toolkit
is a utility to deploy Java content in
8   the browser
as applets or applications using the right version of Java.
9   If needed it can initiate an upgrade of user
's system to install required
10   components of Java platform.
11   <p>
12   Note that some of the Deployment Toolkit methods may not be fully operational
if
13   used before web page body
is loaded (because DT native plugins could not be instantiated).
14   If you intend to use it before web page DOM tree
is ready then dtjava.js
15   needs to be loaded inside the body element of the page and before use of other DT APIs.
16
17   @module java/deployment_toolkit
18 */

19 var
dtjava = function() {
20     function notNull(o) {
21         
return (o != undefined && o != null);
22     }
23
24     function isDef(fn) {
25         
return (fn != null && typeof fn != "undefined");
26     }
27
28     
//return true if any of patterns from query list is found in the given string
29     function containsAny(lst, str) {
30         
for (var q = 0; q < lst.length; q++) {
31             
if (str.indexOf(lst[q]) != -1) {
32                 
return true;
33             }
34         }
35         
return false;
36     }
37
38     
/* Location of static web content - images, javascript files. */
39     
var jscodebase = (function () {
40         
// <script> elements are added to the DOM and run synchronously,
41         
// the currently running script will also be the last element in the array
42         
var scripts = document.getElementsByTagName("script");
43         
var src = scripts[scripts.length - 1].getAttribute("src");
44         
return src ? src.substring(0, src.lastIndexOf('/') + 1) : "";
45     })();
46
47     
//set to true to disable FX auto install (before release)
48     
var noFXAutoInstall = false;
49
50     
// page has no body yet, postpone plugin installation
51     postponeNativePluginInstallation =
false;
52
53     
// JRE version we start to have JRE and FX true co-bundle
54     
var minJRECobundleVersion = "1.7.0_06";
55
56     
//aliases
57     
var d = document;
58     
var w = window;
59
60     
var cbDone = false; //done with onload callbacks
61     
var domInternalCb = []; //list of internal callbacks
62     
var domCb = []; //list of callbacks
63     
var ua = null;
64
65
66     
// Add internal function to be called on DOM ready event.
67     
// These functions will be called before functions added by addOnDomReady().
68     
// Used to do internal initialization (installing native plug-in) to avoid
69     
// race condition with user requests.
70     function addOnDomReadyInternal(fn) {
71         
if (cbDone) {
72             fn();
73         }
else {
74             domInternalCb[domInternalCb.length] = fn;
75         }
76     }
77
78     
// add function to be called on DOM ready event
79     function addOnDomReady(fn) {
80         
if (cbDone) {
81             fn();
82         }
else {
83             domCb[domCb.length] = fn;
84         }
85     }
86
87     
//invoke pending onload callbacks
88     function invokeCallbacks() {
89         
if (!cbDone) {
90             
//swfoject.js tests whether DOM is actually ready first
91             
// in order to not fire too early. Use same heuristic
92             
try {
93                 
var t = d.getElementsByTagName("body")[0].appendChild(
94                     d.createElement(
"div"));
95                 t.parentNode.removeChild(t);
96             }
catch (e) {
97                 
return;
98             }
99             cbDone =
true;
100             
for (var i = 0; i < domInternalCb.length; i++) {
101                 domInternalCb[i]();
102             }
103             
for (var i = 0; i < domCb.length; i++) {
104                 domCb[i]();
105             }
106         }
107     }
108
109     
//cross browser onload support.
110     
//Derived from swfobject.js
111     function addOnload(fn) {
112         
if (isDef(w.addEventListener)) {
113             w.addEventListener(
"load", fn, false);
114         }
else if (isDef(d.addEventListener)) {
115             d.addEventListener(
"load", fn, false);
116         }
else if (isDef(w.attachEvent)) {
117             w.attachEvent(
"onload", fn);
118             
//TODO: swfobject also keeps references to the listeners to detach them on onload
119             
// to avoid memory leaks ...
120         }
else if (typeof w.onload == "function") {
121             
var fnOld = w.onload;
122             w.onload = function() {
123                 fnOld();
124                 fn();
125             };
126         }
else {
127             w.onload = fn;
128         }
129     }
130
131     function detectEnv() {
132         
var dom = isDef(d.getElementById) && isDef(d.getElementsByTagName) && isDef(d.createElement);
133         
var u = navigator.userAgent.toLowerCase(),
134             p = navigator.platform.toLowerCase();
135
136         
//NB: may need to be refined as some user agent may contain strings related to other browsers
137         
// (e.g. Chrome has both Safari and mozilla, Safari also has mozilla
138         
var windows = p ? /win/.test(p) : /win/.test(u),
139             mac = p ? /mac/.test(p) : /mac/.test(u),
140             linux = p ? /linux/.test(p) : /linux/.test(u),
141             chrome = /chrome/.test(u),
142             
// get webkit version or false if not webkit
143             webkit = !chrome && /webkit/.test(u) ?
144                 parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,
"$1")) : false,
145             opera = /opera/.test(u),
146             cputype =
null,
147             osVersion =
null;
148
149         
var ie = false;
150         
try {
151             
//Used to be using trick from
152             
// http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html
153             
//ie = !+"\v1",
154             
//but it does not work with IE9 in standards mode
155             
//Reverting to alternative - use execScript
156             ie = isDef(window.execScript);
157             
// IE 11 does not support execScript any more and no exception is thrown, so lets use more naive test.
158             
// http://msdn.microsoft.com/en-us/library/ie/bg182625(v=vs.85).aspx
159             
if (!ie) { // We do not want to overwrite if ie was detected above.
160                 ie = (navigator.userAgent.match(/Trident/i) !=
null);
161             }
162         }
catch (ee) {
163             
//if javafx app is in the iframe and content of main window is coming from other domain
164             
// then some browsers may restrict access to outer window properties,
165             
// e.g. FF can throw exception for top.execScript (see RT-17885)
166             
//We could revert to more naive test, e.g. test user agent for "MSIE " string
167             
// but so far IE does not seem to throw exception => if we get here it is not IE anyways
168             ie =
false;
169         }
170
171         
var edge = false;
172         
var noActiveX = false;
173         edge = (navigator.userAgent.match(/Edge/i) !=
null);
174
175         
// If IE and Windows 8 or Windows 8.1 then check for Metro mode
176         
if(ie && navigator.userAgent.match(/Windows NT 6\.[23]/i) != null) {
177             
try {
178                 
// try to create a known ActiveX object
179                 
new ActiveXObject("htmlfile");
180             }
catch(e) {
181         
// ActiveX is disabled or not supported.
182                 noActiveX =
true;
183             }
184         }
185
186         
if(edge || noActiveX) {
187             ie =
false;
188     }
189
190
191         
//we are not required to detect everything and can leave values null as
192         
// long as we later treat them accordingly.
193         
//We use "cputype" to detect if given hardware is supported,
194         
// e.g. we do not support PPC or iPhone/iPad despite they are running Mac OS
195         
//We use "osVersion" to detect if Java/JavaFX can be installed on this OS
196         
// e.g. Oracle Java for Mac requires 10.7.3
197         
if (mac) {
198             
if ((p && /intel/.test(p)) || /intel/.test(u)) {
199                 cputype =
"intel";
200             }
201             
//looking for things like 10_7, 10_6_8, 10.4 in the user agent
202             
var t = u.match(/mac os x (10[0-9_\.]+)/);
203             
//normalize to "." separators
204             osVersion = notNull(t) ? t[
0].replace("mac os x ","").replace(/_/g, ".") : null;
205         }
206
207         
// trim() is not supported by IE10 and before
208         
if(typeof String.prototype.trim !== 'function') {
209            String.prototype.trim = function() {
210                
return this.replace(/^\s+|\s+$/g, '');
211            }
212         }
213
214         
// startsWith() is not supported by IE
215         
if(typeof String.prototype.startsWith !== 'function') {
216            String.prototype.startsWith = function(searchString, position) {
217                position = position ||
0;
218                
return this.indexOf(searchString, position) === position;
219            }
220         }
221
222
223         
// Check mime types. Works with netscape family browsers and checks latest installed plugin only
224         
var mm = navigator.mimeTypes;
225         
var jre = null;
226         
var deploy = null;
227         
var fx = null;
228         
var override = false;
229
230         
if (typeof __dtjavaTestHook__ !== 'undefined' &&
231             __dtjavaTestHook__ !=
null &&
232             __dtjavaTestHook__.jre !=
null &&
233             __dtjavaTestHook__.jfx !=
null &&
234             __dtjavaTestHook__.deploy !=
null) {
235             jre = __dtjavaTestHook__.jre;
236             deploy = __dtjavaTestHook__.deploy;
237             fx = __dtjavaTestHook__.jfx;
238             
override = true;
239         }
240         
else {
241             
//Cache configuration from plugin mimetypes
242             
//It is only available for NPAPI browsers
243             
for (var t = 0; t < mm.length; t++) {
244                 
// The jpi-version is the JRE version.
245                 
var m = navigator.mimeTypes[t].type;
246                 
if (m.indexOf("application/x-java-applet;version") != -1 && m.indexOf('=') != -1) {
247                     
var v = m.substring(m.indexOf('=') + 1);
248                     
// Use the existing version comparison mechanism to ensure that
249                     
// the latest JRE is selected ( "versionA"<="VersionB" equals to
250                     
// versionCheck("versionA+","versionB") returns "true")
251                     
if(jre == null || versionCheck(jre + "+", v)){
252             jre = v;
253                 }
254                 }
255                 
//Supported for 7u6 or later
256                 
if (m.indexOf("application/x-java-applet;deploy") != -1 && m.indexOf('=') != -1) {
257                     deploy = m.substring(m.indexOf(
'=') + 1);
258                 }
259                 
//javafx version for cobundled javafx (7u6+)
260                 
if (m.indexOf("application/x-java-applet;javafx") != -1 && m.indexOf('=') != -1) {
261                     fx = m.substring(m.indexOf(
'=') + 1);
262                 }
263             }
264         }
265
266        
var firefox = (navigator.userAgent.match(/Firefox/i) != null);
267
268        
var noPluginWebBrowser = edge || chrome || noActiveX || (firefox && (jre == null));
269
270
271         
return {haveDom:dom, wk:webkit, ie:ie, win:windows,
272                 linux:linux, mac:mac, op: opera, chrome:chrome, edge:edge,
273                 jre:jre, deploy:deploy, fx:fx, noPluginWebBrowser:noPluginWebBrowser,
274                 cputype: cputype, osVersion: osVersion,
override: override};
275     }
276
277    function showMessageBox() {
278         
var message = 'Java Plug-in is not supported by this browser. <a href="https://java.com/dt-redirect">More info</a>';
279         
var mbStyle = 'background-color: #ffffce;text-align: left;border: solid 1px #f0c000; padding: 1.65em 1.65em .75em 0.5em; font-family: Helvetica, Arial, sans-serif; font-size: 75%; bottom:0; left:0; right:0; position:fixed; margin:auto; opacity:0.9; width:400px;';
280         
var messageStyle = "border: .85px; margin:-2.2em 0 0.55em 2.5em;";
281         
var closeButtonStyle = "margin-left:10px;font-weight:bold;float:right;font-size:22px;line-height:20px;cursor:pointer;color:red;"
282         
var messageBox = '<span style="'+ closeButtonStyle +'" onclick="this.parentElement.style.display=\'none\';">&times;</span><img src="https://java.com/js/alert_16.png"><div style="'+ messageStyle +'"><p>'+ message + '</p>';
283
284
285         
var divTag = document.createElement("div");
286         divTag.id =
"messagebox";
287         divTag.setAttribute(
'style', mbStyle);
288         divTag.innerHTML = messageBox;
289         document.body.appendChild(divTag);
290
291     }
292     
//partially derived from swfobject.js
293     
var initDone = false;
294
295     function init() {
296         
if (typeof __dtjavaTestHook__ !== 'undefined') {
297           jre =
null;
298           jfx =
null;
299           deploy =
null;
300
301           
if ((__dtjavaTestHook__ != null) && (__dtjavaTestHook__.args != null)) {
302               jre = __dtjavaTestHook__.args.jre;
303               jfx = __dtjavaTestHook__.args.jfx;
304               deploy = __dtjavaTestHook__.args.deploy;
305           }
306
307           
if ((window.location.href.indexOf('http://localhost') == 0) ||
308              (window.location.href.indexOf(
'file:///') == 0)) {
309              __dtjavaTestHook__ = {
310                 detectEnv: detectEnv,
311                 Version: Version,
312                 checkFXSupport: checkFXSupport,
313                 versionCheck: versionCheck,
314                 versionCheckFX: versionCheckFX,
315                 jre: jre,
316                 jfx: jfx,
317                 deploy: deploy
318              };
319           }
320         }
321
322         
if (initDone) return;
323
324         ua = detectEnv();
325         
if (!ua.haveDom) {
326             
return;
327         }
328
329         
//NB: dtjava.js can be added dynamically and init() can be called after
330         
// document onload event is fired
331         
if (( isDef(d.readyState) && d.readyState == "complete") ||
332             (!isDef(d.readyState) &&
333                 (d.getElementsByTagName(
"body")[0] || d.body))) {
334             invokeCallbacks();
335         }
336
337         
if (!cbDone) {
338             
if (isDef(d.addEventListener)) {
339                 d.addEventListener(
"DOMContentLoaded",
340                     invokeCallbacks,
false);
341             }
342             
if (ua.ie && ua.win) {
343                 
// http://msdn.microsoft.com/en-us/library/ie/ms536343(v=vs.85).aspx
344                 
// attachEvent is not supported by IE 11.
345                 
if (isDef(d.addEventListener)) {
346                     d.addEventListener(
"onreadystatechange", function() {
347                         
if (d.readyState == "complete") {
348                             d.removeEventListener(
"onreadystatechange", arguments.callee, false);
349                             invokeCallbacks();
350                         }
351                     },
false);
352                 }
else {
353                     d.attachEvent(
"onreadystatechange", function() {
354                         
if (d.readyState == "complete") {
355                             d.detachEvent(
"onreadystatechange", arguments.callee);
356                             invokeCallbacks();
357                         }
358                     });
359                 }
360                 
if (w == top) { // if not inside an iframe
361                     (function() {
362                         
if (cbDone) {
363                             
return;
364                         }
365                         
//AI: what for??
366                         
try {
367                             d.documentElement.doScroll(
"left");
368                         }
catch(e) {
369                             setTimeout(arguments.callee,
0);
370                             
return;
371                         }
372                         invokeCallbacks();
373                     })();
374                 }
375             }
376             
if (ua.wk) {
377                 (function() {
378                     
if (cbDone) {
379                         
return;
380                     }
381                     
if (!/loaded|complete/.test(d.readyState)) {
382                         setTimeout(arguments.callee,
0);
383                         
return;
384                     }
385                     invokeCallbacks();
386                 })();
387             }
388             addOnload(invokeCallbacks);
389         }
390         
//only try to install native plugin if we do not have DTLite
391         
//Practically this means we are running NPAPI browser on Windows
392         
//(Chrome or FF) and recent JRE (7u4+?)
393         
if (!haveDTLite()) {
394             installNativePlugin();
395         }
396     }
397
398    function getAbsoluteUrl(jnlp){
399         
var absoluteUrl;
400         
if(isAbsoluteUrl(jnlp)) {
401             absoluteUrl = jnlp;
402         }
else {
403             
var location = window.location.href;
404             
var pos = location.lastIndexOf('/');
405             
var docbase = pos > -1 ? location.substring(0, pos + 1) : location + '/';
406         absoluteUrl = docbase + jnlp;
407         }
408         
return absoluteUrl;
409     }
410
411     function launchWithJnlpProtocol(jnlp) {
412         document.location=
"jnlp:"+ getAbsoluteUrl(jnlp);
413     }
414
415
416     function isAbsoluteUrl(url){
417        
var protocols = ["http://", "https://", "file://"];
418        
for (var i=0; i < protocols.length; i++){
419          
if(url.toLowerCase().startsWith(protocols[i])){
420             
return true;;
421      }
422        }
423        
return false;
424      }
425
426
427     
/**
428      This
class provides details on why current platform does not meet
429      application platform requirements. Note that severe problems are
430      reported immediately and therefore full check may be not performed and
431      some (unrelated to fatal problem)
432      methods may provide
false positive answers.
433      <p>
434      If multiple components
do not match then worst status is reported.
435      Application need to repeat checks
on each individual component
436      
if it want to find out all details.
437
438      @
class PlatformMismatchEvent
439      @
for dtjava
440      */

441     function PlatformMismatchEvent(a) {
442
443         
//expect to get all parameters needed
444         
for (var p in a) {
445             
this[p] = a[p];
446         }
447
448         
/**
449          * @method toString
450          * @
return {string}
451          * Returns
string replesentation of event. Useful for debugging.
452          */

453         
this.toString = function() {
454             
return "MISMATCH [os=" + this.os + ", browser=" + this.browser
455                 +
", jre=" + this.jre + ", fx=" + this.fx
456                 +
", relaunch=" + this.relaunch + ", platform="
457                 +
this.platform + "]";
458         };
459
460         
/**
461          @method isUnsupportedPlatform
462          @
return {boolean}
463          Returns
true if this platform (OS/hardware) is not supported in a way
464          to satisfy all platfrom requirements.
465          (E.g. page
is viewed on iPhone or JavaFX 2.0 application on Solaris.)
466          <p>
467          Note that
this does not include browser match data.
468          If platform
is unsupported then application can not be
469          launched and user need to use another platform to view it.
470          */

471
472         
this.isUnsupportedPlatform = function() {
473             
return this.os;
474         };
475
476         
/**
477          @method isUnsupportedBrowser
478          @
return {boolean}
479          Returns
true if error is because current browser is not supported.
480          <p>
481          If
true is returned and isRelaunchNeeded() returns true too then
482          there are known supported browsers browsers
for this platform.
483          (but they are not necessary installed
on end user system)
484          */

485         
this.isUnsupportedBrowser = function() {
486             
return this.browser;
487         };
488
489         
/**
490          @method jreStatus
491          @
return {string}
492
493          Returns
"ok" if error was not due to missing JRE.
494          Otherwise
return error code characterizing the problem:
495          <ul>
496          <li> none - no JRE were detected
on the system
497          <li> old - some version of JRE was detected but it does not match platform requirements
498          <li> oldplugin - matching JRE found but it
is configured to use deprecated Java plugin that
499          does not support Java applets
500          <ul>
501          <p>
502          canAutoInstall() and isRelaunchNeeded() can be used to
503          
get more details on how seamless user' install experience will be.
504          */

505         
this.jreStatus = function() {
506             
return this.jre;
507         };
508
509         
/**
510          * @method jreInstallerURL
511          * @param {
string} locale (optional) Locale to be used for installation web page
512          * @
return {string}
513          *
514          * Return URL of page to visit to install required version of Java.
515          * If matching java runtime
is already installed or not officially supported
516          * then
return value is null.
517          */

518         
this.jreInstallerURL = function(locale) {
519             
if (!this.os && (this.jre == "old" || this.jre == "none")) {
520                 
return getJreUrl(locale);
521             }
522             
return null;
523         };
524
525         
/**
526          @method javafxStatus
527          @
return {string}
528
529          Returns
"ok" if error was not due to missing JavaFX.
530          Otherwise
return error code characterizing the problem:
531          <ul>
532          <li> none - no JavaFX runtime
is detected on the system
533          <li> old - some version of JavaFX runtime iss detected but it does not match platform requirements
534          <li> disabled - matching JavaFX
is detected but it is disabled
535          <li> unsupported - JavaFX
is not supported on this platform
536          <ul>
537          <p>
538          canAutoInstall() and isRelaunchNeeded() can be used to
539          
get more details on how seamless user' install experience will be.
540          */

541         
this.javafxStatus = function() {
542             
return this.fx;
543         };
544
545         
/**
546          * @method javafxInstallerURL
547          * @param {
string} locale (optional) Locale to be used for installation web page
548          * @
return {string}
549          *
550          * Return URL of page to visit to install required version of JavaFX.
551          * If matching JavaFX runtime
is already installed or not officially supported
552          * then
return value is null.
553          */

554         
this.javafxInstallerURL = function(locale) {
555             
if (!this.os && (this.fx == "old" || this.fx == "none")) {
556                 
return getFxUrl(locale);
557             }
558             
return null;
559         };
560
561         
/**
562          @method canAutoInstall
563          @
return {boolean}
564          Returns
true if installation of missing components can be
565          triggered automatically. In particular, ture
is returned
566          
if there are no missing components too.
567          <p>
568          If any of missing components need to be installed manually
569          (i.e. click through additional web pages) then
false is returned.
570          */

571         
this.canAutoInstall = function() {
572             
return isAutoInstallEnabled(this.platform, this.jre, this.fx);
573         };
574
575         
/**
576          @method isRelaunchNeeded
577          @
return {boolean}
578
579          Returns
true if browser relaunch is needed before application can be loaded.
580          This often
is true in conjuction with need to perform installation.
581          <p>
582          Other typical
case - use of unsupported browser when
583          it
is known that there are supported browser for this pltaform.
584          Then both isUnsupportedBrowser() and isRelaunchNeeded()
return true.
585          */

586         
this.isRelaunchNeeded = function() {
587             
return this.relaunch;
588         };
589     }
590
591     
//returns version of instaled JavaFX runtime matching requested version
592     
//or null otherwise
593     function getInstalledFXVersion(requestedVersion) {
594         
//NPAPI browser and JRE with cobundle
595         
if (ua.fx != null && versionCheckFX(requestedVersion, ua.fx)) {
596             
return ua.fx;
597         }
598         
//try to use DT
599         
var p = getPlugin();
600         
if (notNull(p)) {
601             
try {
602                 
return p.getInstalledFXVersion(requestedVersion);
603             }
catch(e) {}
604         }
605         
return null;
606     }
607
608     
//concatenate list with space as separator
609     function listToString(lst) {
610       
if (lst != null) {
611           
return lst.join(" ");
612       }
else {
613           
return null;
614       }
615     }
616
617     function addArgToList(lst, arg) {
618         
if (notNull(lst)) {
619            lst.push(arg);
620            
return lst;
621         }
else {
622             
var res = [arg];
623             
return res;
624         }
625     }
626
627     function doLaunch(ld, platform, cb) {
628         
var app = normalizeApp(ld, true);
629         
if(ua.noPluginWebBrowser){
630             launchWithJnlpProtocol(app.url);
631             
return;
632     }
633
634         
//required argument is missing
635         
if (!(notNull(app) && notNull(app.url))) {
636             
throw "Required attribute missing! (application url need to be specified)";
637         }
638
639         
//if we got array we need to copy over!
640         platform =
new dtjava.Platform(platform);
641
642         
//normalize handlers
643         cb =
new dtjava.Callbacks(cb);
644
645         
var launchFunc = function() {
646             
//prepare jvm arguments
647             
var jvmArgs = notNull(platform.jvmargs) ? platform.jvmargs : null;
648             
if (notNull(platform.javafx)) {
649                 
//if FX is needed we know it is available or
650                 
// we will not get here
651                 
var v = getInstalledFXVersion(platform.javafx);
652                 
//add hint that we need FX toolkit to avoid relaunch
653                 
// if JNLP is not embedded
654                 jvmArgs = addArgToList(jvmArgs,
" -Djnlp.fx=" + v);
655                 
//for swing applications embedding FX we do not want this property as it will
656                 
// trigger FX toolkit and lead to app failure!
657                 
//But for JavaFX application it saves us relaunch as otherwise we wil launch with AWT toolkit ...
658                 
if (!notNull(ld.toolkit) || ld.toolkit == "fx") {
659                     jvmArgs = addArgToList(jvmArgs,
" -Djnlp.tk=jfx");
660                 }
661
662             }
663
664
665             
//if we on 7u6+ we can use DTLite plugin in the NPAPI browsers
666             
//Caveat: as of 7u6 it does not work with Chrome on Linux because Chrome expects
667             
// DTLite plugin to implement xembed (or claim to support xembed)
668             
if (haveDTLite() && !(ua.linux && ua.chrome)) {
669                 
if (doLaunchUsingDTLite(app, jvmArgs, cb)) {
670                     
return;
671                 }
672             }
673
674             
//Did not launch yet? Try DT plugin (7u2+)
675             
var p = getPlugin();
676             
if (notNull(p)) {
677                 
try {
678                     
try {
679                         
//check if new DT APIs are available
680                         
if (versionCheck("10.6+", ua.deploy, false)) {
681                             
// obj.launchApp({"url" : "http://somewhere/my.jnlp",
682                             
// "jnlp_content" : "... BASE 64 ...",
683                             
// "vmargs" : [ "-ea -Djnlp.foo=bar"
684                             
// "appargs" : [ "first arg, second arg" ]
685                             
// "params" : {"p1" : "aaa", "p2" : "bbb"}});
686                             
var callArgs = {"url":app.url};
687                             
if (notNull(jvmArgs)) {
688                                 callArgs[
"vmargs"] = jvmArgs;
689                             }
690                             
//Only use HTML parameters, they are supposed to overwrite values in the JNLP
691                             
//In the future we want to pass arguments too but this needs also be exposed for
692                             
// embedded deployment
693                             
if (notNull(app.params)) {
694                                 
//copy over and ensure all values are strings
695                                 
// (native code will ignore them otherwise)
696                                 
var ptmp = {};
697                                 
for (var k in app.params) {
698                                     ptmp[k] = String(app.
params[k]);
699                                 }
700                                 callArgs[
"params"] = ptmp;
701                             }
702                             
if (notNull(app.jnlp_content)) {
703                                 callArgs[
"jnlp_content"] = app.jnlp_content;
704                             }
705                             
var err = p.launchApp(callArgs);
706                             
if (err == 0) { //0 - error
707                                 
if (isDef(cb.onRuntimeError)) {
708                                     cb.onRuntimeError(app.id);
709                                 }
710                             }
711                         }
else { //revert to old DT APIs
712                             
//older DT APIs expects vmargs as a single string
713                             
if (!p.launchApp(app.url, app.jnlp_content, listToString(jvmArgs))) {
714                                 
if (isDef(cb.onRuntimeError)) {
715                                     cb.onRuntimeError(app.id);
716                                 }
717                             }
718                         }
719                         
return;
720                     }
catch (ee) { //temp support for older build of DT
721                         
if (!p.launchApp(app.url, app.jnlp_content)) {
722                            
if (isDef(cb.onRuntimeError)) {
723                               cb.onRuntimeError(app.id);
724                            }
725                         }
726                         
return;
727                     }
728                 }
catch (e) {
729                     
//old DT
730                 }
731             }
//old Java (pre DTLite)? not Windows? or old DT
732
733             
//use old way to launch it using java plugin
734             
var o = getWebstartObject(app.url);
735             
if (notNull(d.body)) {
736                 d.body.appendChild(o);
737             }
else {
738                 
//should never happen
739                 d.write(o.innerHTML);
740             }
741         }
742
743         
var r = doValidateRelaxed(platform);
744         
//can not launch, try to fix
745         
if (r != null) {
746             resolveAndLaunch(app, platform, r, cb, launchFunc);
747         }
else {
748             launchFunc();
749         }
750     }
751
752     
//process unhandled platform error - convert to code and call callback
753     function reportPlatformError(app, r, cb) {
754         
if (isDef(cb.onDeployError)) {
755             cb.onDeployError(app, r);
756         }
757     }
758
759     function isDTInitialized(p) {
760         
//if plugin is blocked then p.version will be undefined
761         
return p != null && isDef(p.version);
762     }
763
764     
//Wait until DT plugin is initialized and then run the code
765     
//Currently we only use it for embeded apps and Chrome on Windows
766     function runUsingDT(label, f) {
767         
// Possible situations:
768         
// a) plugin is live and we can simply run code
769         
// - just run the code
770         
// b) plugin is in the DOM tree but it is not initialized yet (e.g. Chrome blocking)
771         
// and there is live timer (pendingCount > 0)
772         
// - there could be another request. We will APPEND to it
773         
// (this is different from dtlite as in this case we can not have multiple clicks)
774         
// - renew timer life counter (do not want new timer)
775         
// c) plugin is in the DOM tree and it is not fully initialized yet but timer is stopped
776         
// - overwrite old request
777         
// - restart timer
778         
//
779         
// Problem we are solving:
780         
// when plugin is ready to serve request? How do we schedule call to happen when plugin is initialized?
781         
// Caveat:
782         
// Chrome can popup dialog asking user to grant permissions to load the plugin.
783         
// There is no API to detect dialog is shown and when user grants or declines permissions
784         
//
785         
// Note:
786         
// If we set property on plugin object before it is unblocked then they seem to be lost
787         
// and are not propagated to the final object once it is instantiated.
788         
//
789         
// Workaround we use:
790         
// Once plugin is added we will be checking if it is initialized and once we detect it we will execute code.
791         
// We will stop checking after some time.
792         
var p = getPlugin();
793         
if (p == null) {
794             
return; //NO DT
795         }
796
797         
if (isDTInitialized(p)) {
798             f(p);
799         }
else {
800             
// see if we need new timer
801             
var waitAndUse = null;
802             
if (!isDef(dtjava.dtPendingCnt) || dtjava.dtPendingCnt == 0) {
803                 waitAndUse = function () {
804                     
if (isDTInitialized(p)) {
805                         
if (notNull(dtjava.dtPending)) {
806                             
for (var i in dtjava.dtPending) {
807                                 dtjava.dtPending[i]();
808                             }
809                         }
810                         
return;
811                     }
812                     
if (dtjava.dtPendingCnt > 0) {
813                         dtjava.dtPendingCnt--;
814                         setTimeout(waitAndUse,
500);
815                     }
816                 }
817             }
818             
//add new task in queue
819             
if (!notNull(dtjava.dtPending) || dtjava.dtPendingCnt == 0) {
820                 dtjava.dtPending = {};
821             }
822             dtjava.dtPending[label] = f;
//use map to ensure repitative actions are not queued (e.g. multiple click to launch webstart)
823             
//reset the timer counter
824             dtjava.dtPendingCnt =
1000; //timer is gone after 500s
825             
//start timer if needed
826             
if (waitAndUse != null) waitAndUse();
827         }
828     }
829
830     
//returns same mismatch event if not resolved, null if resolved
831     function resolveAndLaunch(app, platform, v, cb, launchFunction) {
832         
var p = getPlugin();
833         
if( p == null && ua.noPluginWebBrowser){
834             
var readyStateCheck = setInterval(function() {
835                     
if(document.readyState == "complete"){
836                         clearInterval(readyStateCheck);
837                         showMessageBox();
838                     }
839                 },
15);
840             
return;
841         }
842         
//Special case: Chrome/Windows
843         
// (Note: IE may also block activeX control but then it will block attempts to use it too)
844         
if (ua.chrome && ua.win && p != null && !isDTInitialized(p)) {
845             
//this likely means DT plugin is blocked by Chrome
846             
//tell user to grant permissions and retry
847             
var actionLabel;
848             
if (notNull(app.placeholder)) {
849                 
var onClickFunc = function() {w.open("https://www.java.com/en/download/faq/chrome.xml"); return false;};
850                 
var msg1 = "Please give Java permission to run on this browser web page.";
851                 
var msg2 = "Click for more information.";
852                 
var altText = "";
853                 doShowMessageInTheArea(app, msg1, msg2, altText,
"javafx-chrome.png", onClickFunc);
854                 actionLabel = app.id +
"-embed";
855             }
else {
856                 v.jre =
"blocked";
857                 reportPlatformError(app, v, cb);
858                 actionLabel =
"launch"; //we only queue ONE webstart launch.
859                                         
//Do not want to try to queue different apps - bad UE
860                                         
// (once user enable multiple things can spawn)
861                                         
//Note: what if multiple webstart apps are set to launch on page load (suer do not need to click)?
862                                         
// Guess do not worry for now
863                                         
//Note: app.id may be null in case of webstart app.
864             }
865
866             
//now we need to start waiter. Once DT is initialized we can proceeed
867             
var retryFunc = function() {
868                 
var vnew = doValidateRelaxed(platform);
869                 
if (vnew == null) { //no problems with env
870                     launchFunction();
871                 }
else {
872                     resolveAndLaunch(app, platform, vnew, cb, launchFunction);
873                 }
874             };
875             runUsingDT(actionLabel, retryFunc);
876
877             
return;
878         }
879
880         
if (!v.isUnsupportedPlatform() && !v.isUnsupportedBrowser()) { //otherwise fatal, at least until restart of browser
881             
if (isMissingComponent(v) && isDef(cb.onInstallNeeded)) {
882                 
var resolveFunc= function() {
883                     
//once install is over we need to revalidate
884                     
var vnew = doValidateRelaxed(platform);
885                     
if (vnew == null) { //if no problems found - can launch
886                         launchFunction();
887                     }
else { //TODO: what happens if we installed everything but relaunch is needed??
888                         
//We can not get here if component install was not offered for any or missing componens
889                         
//(if auto install was possible, see doInstall() implementation)
890                         
//Hence, it is safe to assume we failed to meet requirements
891                         reportPlatformError(app, vnew, cb);
892
893                         
//TODO: may be should call itself again but
894                         
// then it easy can become infinite loop
895
896                         
//e.g. user installs but we fail to detect it because DT
897                         
// is not FX aware and retry, etc.
898                         
//TODO: think it through
899                     }
900                 };
901
902                 cb.onInstallNeeded(app, platform, cb,
903                             v.canAutoInstall(), v.isRelaunchNeeded(), resolveFunc);
904                 
return;
905             }
906         }
907         reportPlatformError(app, v, cb);
908     }
909
910     function haveDTLite() {
911         
// IE does not support DTLite
912         
if (ua.deploy != null && !ua.ie) {
913             
return versionCheck("10.6+", ua.deploy, false);
914         }
915         
return false;
916     }
917
918     function isDTLiteInitialized(p) {
919         
//if plugin is blocked then p.version will be undefined
920         
return p != null && isDef(p.version);
921     }
922
923     function getDTLitePlugin() {
924         
return document.getElementById("dtlite");
925     }
926
927     function doInjectDTLite() {
928         
//do not want more than one plugin
929         
if (getDTLitePlugin() != null) return;
930
931         
var p = document.createElement('embed');
932         p.width =
'10px';
933         p.height =
'10px';
934         p.id =
"dtlite";
935         p.type =
"application/x-java-applet"; //means we get latest
936
937         
var div = document.createElement("div");
938         div.style.position =
"relative";
939         div.style.left =
"-10000px";
940         div.appendChild(p);
941
942         
var e = document.getElementsByTagName("body");
943         e[
0].appendChild(div);
944     }
945
946     function runUsingDTLite(f) {
947         
// Possible situations:
948         
// a) first request, plugin is not in the DOM tree yet
949         
// - add plugin
950         
// - setup wait mechanism and run f() once plugin is ready
951         
// b) plugin is live and we can simply run code
952         
// - just run the code
953         
// c) plugin is in the DOM tree but it is not initialized yet (e.g. Chrome blocking)
954         
// and there is live timer (pendingCount > 0)
955         
// - there could be another request. We will override it (e.g. user clicked multiple times)
956         
// - renew timer life counter (do not want new timer)
957         
// d) plugin is in the DOM tree and it is not fully initialized yet but timer is stopped
958         
// - overwrite old request
959         
// - restart timer
960         
//
961         
// Problem:
962         
// when plugin is ready to serve request? How do we schedule call to happen when plugin is initialized?
963         
// Caveat:
964         
// Chrome can popup dialog asking user to grant permissions to load the plugin.
965         
// There is no API to detect dialog is shown and when user grants or declines permissions
966         
//
967         
// Note:
968         
// If we set property on plugin object before it is unblocked then they seem to be lost
969         
// and are not propagated to the final object once it is instantiated.
970         
//
971         
// Workaround we use:
972         
// Once plugin is added we will be checking if it is initialized and once we detect it we will execute code.
973         
// We will stop checking after some time.
974         
var p = getDTLitePlugin();
975         
if (p == null) {
976             doInjectDTLite();
977             p = getDTLitePlugin();
978         }
979
980         
if (isDTLiteInitialized(p)) {
981             f(p);
982         }
else {
983             
// see if we need new timer
984             
var waitAndUse = null;
985             
if (!isDef(dtjava.dtlitePendingCnt) || dtjava.dtlitePendingCnt == 0) {
986                 waitAndUse = function () {
987                     
if (isDef(p.version)) {
988                         
if (dtjava.pendingLaunch != null) {
989                             dtjava.pendingLaunch(p);
990                         }
991                         dtjava.pendingLaunch =
null;
992                         
return;
993                     }
994                     
if (dtjava.dtlitePendingCnt > 0) {
995                         dtjava.dtlitePendingCnt--;
996                         setTimeout(waitAndUse,
500);
997                     }
998                 }
999             }
1000             
//add new task in queue
1001             dtjava.pendingLaunch = f;
1002             
//reset the timer counter
1003             dtjava.dtlitePendingCnt =
1000; //timer is gone after 500s
1004             
//start timer if needed
1005             
if (waitAndUse != null) {
1006                 waitAndUse();
1007             }
1008         }
1009     }
1010
1011     function doLaunchUsingDTLite(app, jvmargs, cb) {
1012         
var launchIt = function() {
1013             
var pp = getDTLitePlugin();
1014             
if (pp == null) {
1015                 
//should not be possible as we guard before enter this function
1016                 
if (isDef(cb.onRuntimeError)) {
1017                     cb.onRuntimeError(app.id);
1018                 }
1019             }
1020
1021             
//DTLite only support new invocation API
1022             
// obj.launchApp({"url" : "http://somewhere/my.jnlp",
1023             
// "jnlp_content" : "... BASE 64 ...",
1024             
// "vmargs" : [ "-ea -Djnlp.foo=bar"
1025             
// "appargs" : [ "first arg, second arg" ]
1026             
// "params" : {"p1" : "aaa", "p2" : "bbb"}});
1027             
var callArgs = {"url" : app.url};
1028             
if (notNull(jvmargs)) {
1029                callArgs[
"vmargs"] = jvmargs;
1030             }
1031             
//Only use HTML parameters, they are supposed to overwrite values in the JNLP
1032             
//In the future we want to pass arguments too but this needs also be exposed for
1033             
// embedded deployment
1034             
if (notNull(app.params)) {
1035                 
//copy over and ensure all values are stings
1036                 
// (native code will ignore them otherwise)
1037                 
var ptmp = {};
1038                 
for (var k in app.params) {
1039                     ptmp[k] = String(app.
params[k]);
1040                 }
1041                 callArgs[
"params"] = ptmp;
1042             }
1043             
if (notNull(app.jnlp_content)) {
1044                callArgs[
"jnlp_content"] = app.jnlp_content;
1045             }
1046             
var err = pp.launchApp(callArgs);
1047             
if (err == 0) { //0 - error
1048                 
if (isDef(cb.onRuntimeError)) {
1049                     cb.onRuntimeError(app.id);
1050                 }
1051             }
1052         };
1053
1054         
if (versionCheck("10.4+", ua.deploy, false)) { //only for NPAPI browsers
1055             runUsingDTLite(launchIt);
1056             
return true;
1057         }
1058         
return false;
1059     }
1060
1061     function getWebstartObject(jnlp) {
1062         
var wo = null;
1063         
if (ua.ie) { //TODO: attempt to use object in FF 3.6 lead to hang. Revert to embed for now
1064                      
//TODO: Should Chrome use object?
1065             
//object tag itself
1066             wo = d.createElement(
'object');
1067             wo.width =
'1px'; //zero size reports invalid argument in IE!
1068             wo.height =
'1px'; //TODO: make it less distruptive to page layout? hide div?
1069             
var p = d.createElement('param');
1070             p.name =
'launchjnlp';
1071             p.
value = jnlp;
1072             wo.appendChild(p);
1073             p = d.createElement(
'param');
1074             p.name =
'docbase';
1075             p.
value = notNull(d.documentURI) ? d.documentURI : d.URL;
1076             wo.appendChild(p);
1077
1078             
if (!ua.ie) {
1079                 
//NB:do not need to use exact version in mime type as generic should be mapped to latest?
1080                 wo.type =
"application/x-java-applet;version=1.7";
1081             }
else {
1082                 wo.classid =
"clsid:8AD9C840-044E-11D1-B3E9-00805F499D93";
1083             }
1084         }
else { //TODO: else part should go away once we figure out what is going on with FF
1085             wo = d.createElement(
'embed');
1086             wo.width =
'0px';
1087             wo.height =
'0px';
1088             
//NB: dot notation did not work for custom attributes??? revert to setAttribute
1089             wo.setAttribute(
'launchjnlp', jnlp);
1090             wo.setAttribute(
'docbase', (notNull(d.documentURI) ? d.documentURI : d.URL));
1091             
//NB:do not need to use exact version in mime type as generic should be mapped to latest?
1092             wo.type =
"application/x-java-applet;version=1.7";
1093         }
1094
1095         
var div = d.createElement("div");
1096         div.style.position =
"relative";
1097         div.style.left =
"-10000px";
1098         div.appendChild(wo);
1099         
return div;
1100     }
1101
1102     
// Version class. The argument VersionString is a valid version string and
1103     
// UpgradeFromOldJavaVersion is optional true/false.
1104     
var Match = {
1105         Exact: {
value: 0}, // exact version
1106         Family: {
value: 1}, // Example: 1.7* only matches 1.7.X family
1107         Above: {
value: 2} // Example: 1.7+ matches 1.7 and above
1108     };
1109
1110     
var Token = {
1111         Uninitialized: {
value: -2},
1112         Unknown: {
value: -1},
1113         Identifier: {
value: 0},
1114         Alpha: {
value: 1},
1115         Digits: {
value: 2},
1116         Plus: {
value: 3},
1117         Minus: {
value: 4},
1118         Underbar: {
value: 5},
1119         Star: {
value: 6},
1120         Dot: {
value: 7},
1121         End: {
value: 8}
1122     };
1123
1124     
var Version = function(VersionString, UpgradeFromOldJavaVersion) {
1125         
if (typeof UpgradeFromOldJavaVersion === 'undefined') {
1126             
var UpgradeFromOldJavaVersion = true;
1127         }
1128
1129         
// Constants
1130         
var MAX_DIGITS = 4;
1131
1132         
// Private
1133         
var FVersionString = null;
1134         
var FOld = false;
1135         
var FVersion = null;
1136         
var FBuild = null;
1137         
var FPre = null;
1138         
var FMatch = null;
1139         
var FMajor = null;
1140         
var FMinor = null;
1141         
var FSecurity = null;
1142         
var FPatch = null;
1143
1144         
// Class constructor
1145         
if (!VersionString) {
1146             
return null;
1147         }
1148         
else {
1149             FVersionString = VersionString;
1150             
var v = parseAndSplitVersionString(VersionString, UpgradeFromOldJavaVersion)
1151             FOld = v.old;
1152             FVersion = v.version;
1153             FBuild = v.build;
1154             FMatch = v.match;
1155             FPre = v.pre;
1156
1157             
var parts = splitVersion(v.version);
1158             FMajor = parts.major;
1159             FMinor = parts.minor;
1160             FSecurity = parts.security;
1161             FPatch = parts.patch;
1162         }
1163
1164         
// Public
1165         
return {
1166             VersionString: VersionString,
1167             old: FOld,
1168             major: FMajor,
1169             minor: FMinor,
1170             security: FSecurity,
1171             patch: FPatch,
1172             version: FVersion,
1173             build: FBuild,
1174             pre: FPre,
1175             match: FMatch,
1176
1177             check: function(query) {
1178                 
return check(query, this);
1179             },
1180
1181             
equals: function(query) {
1182                 
return equals(query, this);
1183             }
1184         };
1185
1186         
// Private
1187         function splitVersion(version) {
1188             
var lmajor = null;
1189             
var lminor = null;
1190             
var lsecurity = null;
1191             
var lpatch = null;
1192
1193             
if (version.length >= 1) {
1194                 lmajor = version[
0];
1195             }
1196
1197             
if (version.length >= 2) {
1198                 lminor = version[
1];
1199             }
1200
1201             
if (version.length >= 3) {
1202                 lsecurity = version[
2];
1203             }
1204
1205             
if (version.length >= 4) {
1206                 lpatch = version[
3];
1207             }
1208
1209             
return {
1210                 major: lmajor,
1211                 minor: lminor,
1212                 security: lsecurity,
1213                 patch: lpatch
1214           };
1215         }
1216
1217         function VersionStringTokenizer(versionString) {
1218             
// Convert the version string to lower case and strip all whitespace
1219             
// from the beginning and end of the string.
1220
1221             
var FVersionString = versionString.toLowerCase().trim();
1222             
var FIndex;
1223             
var FCurrentToken = null;
1224             
var FStack = Array();
1225
1226             function isDigit(c) {
1227                 
var result = false;
1228
1229                 
switch(c) {
1230                     
case '0':
1231                     
case '1':
1232                     
case '2':
1233                     
case '3':
1234                     
case '4':
1235                     
case '5':
1236                     
case '6':
1237                     
case '7':
1238                     
case '8':
1239                     
case '9':
1240                         result =
true;
1241                         
break;
1242                 }
1243
1244                 
return result;
1245             }
1246
1247             function isLetter(c) {
1248                 
//return c.match("^[a-zA-Z]");
1249                 
var result = false;
1250                 
var lowerBoundLower = "a".charCodeAt(0);
1251                 
var upperBoundLower = "z".charCodeAt(0);
1252                 
var bound = c.charCodeAt(0);
1253
1254                 
if (lowerBoundLower <= bound && bound <= upperBoundLower) {
1255                     result =
true;
1256                 }
1257
1258                 
return result;
1259             }
1260
1261             function start() {
1262                 FIndex =
0;
1263             }
1264
1265             function currentToken() {
1266                 
return FCurrentToken;
1267             }
1268
1269             function pushToken(Token) {
1270                 
if (FCurrentToken != null) {
1271                     FStack.unshift(FCurrentToken);
1272                 }
1273
1274                 FCurrentToken = Token;
1275             }
1276
1277             function nextToken() {
1278                 
var tokenID = Token.Uninitialized;
1279                 
var token = '';
1280
1281                 
if (FStack.length > 0) {
1282                     tokenID = FStack[
0].tokenID;
1283                     token = FStack[
0].token;
1284                     FStack.shift();
1285                 }
1286                 
else {
1287                     
if (FIndex >= FVersionString.length) {
1288                         tokenID = Token.End;
1289                     }
1290                     
else {
1291                         
while (FIndex < FVersionString.length) {
1292                             
var c = FVersionString.charAt(FIndex);
1293
1294                             
if ((tokenID == Token.Uninitialized || tokenID == Token.Alpha) &&
1295                                 isLetter(c) ==
true) {
1296                                 tokenID = Token.Alpha;
1297                                 FIndex++;
1298                                 token += c;
1299                             }
1300                             
else if ((tokenID == Token.Uninitialized || tokenID == Token.Digits) &&
1301                                      isDigit(c) ==
true) {
1302                                 
if (parseInt(c) == 0 && parseInt(token) == 0) {
1303                                     tokenID = Token.Unknown;
1304                                     token += c;
1305                                     FIndex++;
1306                                     
break;
1307                                 }
1308                                 
else {
1309                                     tokenID = Token.Digits;
1310                                     token += c;
1311                                     FIndex++;
1312                                 }
1313                             }
1314                             
else if ((tokenID == Token.Alpha || tokenID == Token.Identifier) &&
1315                                      isDigit(c) ==
true &&
1316                                      isLetter(c) ==
false) {
1317                                 tokenID = Token.Identifier;
1318                                 FIndex++;
1319                                 token += c;
1320                             }
1321                             
else if (tokenID == Token.Uninitialized) {
1322                                 
switch(c) {
1323                                     
case '-':
1324                                       tokenID = Token.Minus;
1325                                       FIndex++;
1326                                       token = c;
1327                                       
break;
1328                                     
case '+':
1329                                       tokenID = Token.Plus;
1330                                       FIndex++;
1331                                       token = c;
1332                                       
break;
1333                                     
case '*':
1334                                       tokenID = Token.Star;
1335                                       FIndex++;
1336                                       token = c;
1337                                       
break;
1338                                     
case '.':
1339                                       tokenID = Token.Dot;
1340                                       FIndex++;
1341                                       token = c;
1342                                       
break;
1343                                     
case '_':
1344                                       tokenID = Token.Underbar;
1345                                       FIndex++;
1346                                       token = c;
1347                                       
break;
1348                                     
default:
1349                                         tokenID = Token.Unknown;
1350                                         FIndex++;
1351                                         
break;
1352                                 }
1353
1354                                 
break;
1355                             }
1356                             
else {
1357                               
break;
1358                             }
1359                         }
1360                     }
1361                 }
1362
1363                 FCurrentToken = {
1364                     token: token,
1365                     tokenID: tokenID
1366                 }
1367
1368                 
return FCurrentToken;
1369             }
1370
1371             
return {
1372                 start: start,
1373                 nextToken: nextToken,
1374                 pushToken: pushToken,
1375                 currentToken: currentToken,
1376                 isDigit: isDigit,
1377                 isLetter: isLetter
1378             }
1379         }
1380
1381         function VersionStringParser() {
1382             function readDigits(Tokenizer) {
1383                 
var result = new Array();
1384                 
var token = Tokenizer.currentToken();
1385
1386                 
if (token.tokenID == Token.Digits) {
1387                     result.push(parseInt(token.token));
1388                     token = Tokenizer.nextToken();
1389
1390                     
// Read up to 3 more digits.
1391                     
for (var index = 0; index < (MAX_DIGITS - 1); index++) {
1392                         
if (token.tokenID == Token.Dot) {
1393                             token = Tokenizer.nextToken();
1394
1395                             
if (token.tokenID == Token.Digits) {
1396                                 result.push(parseInt(token.token));
1397                                 token = Tokenizer.nextToken();
1398                             }
1399                             
else if (token.tokenID == Token.Star ||
1400                                      token.tokenID == Token.Plus) {
1401                                 
break;
1402                             }
1403                             
else {
1404                                 result =
null;
1405                                 
break;
1406                             }
1407                         }
1408                         
else if (token.tokenID == Token.Star ||
1409                                  token.tokenID == Token.Plus ||
1410                                  token.tokenID == Token.End ||
1411                                  token.tokenID == Token.Minus ||
1412                                  token.tokenID == Token.Underbar ||
1413                                  token.tokenID == Token.Identifier ||
1414                                  (token.tokenID == Token.Alpha && token.token ==
'u')) {
1415                             
break;
1416                         }
1417                         
else {
1418                             result =
null;
1419                             
break;
1420                         }
1421                     }
1422                 }
1423
1424                 
return result;
1425             }
1426
1427             function readMatch(Tokenizer, Old) {
1428                 
var result = Match.Exact;
1429                 
var token = Tokenizer.currentToken();
1430
1431                 
if (token.tokenID == Token.Dot) {
1432                     token = Tokenizer.nextToken();
1433
1434                     
if (token.tokenID == Token.Star) {
1435                         result = Match.Family;
1436                         Tokenizer.nextToken();
1437                     }
1438                     
else if (token.tokenID == Token.Plus) {
1439                         result = Match.Above;
1440                         Tokenizer.nextToken();
1441                     }
1442                 }
1443                 
else if (token.tokenID == Token.Star) {
1444                     result = Match.Family;
1445                     Tokenizer.nextToken();
1446                 }
1447                 
else if (token.tokenID == Token.Plus) {
1448                     result = Match.Above;
1449                     Tokenizer.nextToken();
1450                 }
1451
1452                 
return result;
1453             }
1454
1455             function readPre(Tokenizer) {
1456                 
var result = null;
1457                 
var token = Tokenizer.currentToken();
1458
1459                 
if (token.tokenID == Token.Minus) {
1460                     
var savedToken = token;
1461                     
var token = Tokenizer.nextToken();
1462
1463                     
if (token.tokenID == Token.Alpha) {
1464                         result = token.token;
1465                         Tokenizer.nextToken();
1466                     }
1467                     
else {
1468                         Tokenizer.pushToken(savedToken);
1469                     }
1470                 }
1471
1472                 
return result;
1473             }
1474
1475             function readBuild(Tokenizer, Old) {
1476                 
var result = null;
1477                 
var token = Tokenizer.currentToken();
1478
1479                 
if (token.tokenID == Token.Plus) {
1480                     
// The new version spec has build number prepended with a "+":
1481                     
// RegEx: +([1-9][0-9]*)
1482                     
var savedToken = token;
1483                     
var token = Tokenizer.nextToken();
1484
1485                     
if (token.tokenID == Token.Digits) {
1486                         result = parseInt(token.token);
1487                         Tokenizer.nextToken();
1488                     }
1489                     
else {
1490                         Tokenizer.pushToken(savedToken);
1491                     }
1492                 }
1493                 
else if (Old == true) {
1494                     
// The old version spec has build number prepended with a "-b"
1495                     
// RegEx: -b([1-9][0-9]*)
1496                     
if (token.tokenID == Token.Minus || token.tokenID == Token.Underbar) {
1497                         
var savedToken = token;
1498                         token = Tokenizer.nextToken();
1499
1500                         
if (token.tokenID == Token.Identifier && token.token[0] == 'b') {
1501                             
var builderNumber = parseInt(token.token.substr(1));
1502
1503                             
if (builderNumber != null && isNaN(builderNumber) == false) {
1504                                 Tokenizer.nextToken();
1505                                 result = builderNumber;
1506                             }
1507                         }
1508                         
else {
1509                             Tokenizer.pushToken(savedToken);
1510                         }
1511                     }
1512                 }
1513
1514                 
return result;
1515             }
1516
1517             
// isOldUpdate determines if the version string is in the old
1518             
// short format. For Example: 8u60
1519             function isOldUpdate(version, token) {
1520                 
var result = false;
1521
1522                 
if (version.length == 1 &&
1523                     parseInt(version[
0]) <= 8 &&
1524                     token.tokenID == Token.Identifier &&
1525                     token.token.length >
0 &&
1526                     token.token.charAt(
0) == "u") {
1527                     result =
true;
1528                 }
1529
1530                 
return result;
1531             }
1532
1533             
// Only call this function if isOldUpdate() returns true.
1534             function readOldUpdate(Tokenizer) {
1535                 
var result = null;
1536                 
var token = Tokenizer.currentToken();
1537
1538                 
if (token.tokenID == Token.Identifier) {
1539                     result = parseInt(token.token.substr(
1));
1540                     Tokenizer.nextToken();
1541                 }
1542                 
else if (token.tokenID == Token.Star) {
1543                     lmatch = Match.Family;
1544                     Tokenizer.nextToken();
1545                 }
1546                 
else if (token.tokenID == Token.Plus) {
1547                     lmatch = Match.Above;
1548                     Tokenizer.nextToken();
1549                 }
1550
1551                 
return result;
1552             }
1553
1554             function readOpt(Tokenizer) {
1555                 
var result = null;
1556                 
var token = Tokenizer.currentToken();
1557
1558                 
if (token.tokenID == Token.Alpha) {
1559                     result = token.token;
1560                     Tokenizer.nextToken();
1561                 }
1562
1563                 
return result;
1564             }
1565
1566             function parse(Tokenizer) {
1567                 
var result = null;
1568                 
var success = false;
1569
1570                 
var lold = false;
1571                 
var lversion = null;
1572                 
var lbuild = null;
1573                 
var lmatch = Match.Exact;
1574                 
var lpre = false;
1575                 
var lopt = null;
1576
1577                 Tokenizer.start();
1578                 
var token = Tokenizer.nextToken();
1579
1580                 
if (token.tokenID == Token.Digits) {
1581                     lversion = readDigits(Tokenizer);
1582
1583                     
if (lversion != null && lversion.length > 0) {
1584                         token = Tokenizer.currentToken();
1585
1586                         
if (lversion[0] == 1) {
1587                             
if (lversion.length >= 2 && lversion[1] == 9) {
1588                                 
return null;
1589                             }
1590
1591                             lold =
true;
1592                         }
1593                         
else if (token.token == "u") {
1594                             
// Special case. For Example: 8u*
1595                             token = Tokenizer.nextToken();
1596                         }
1597
1598                         
if (isOldUpdate(lversion, token) == true) {
1599                             lold =
true;
1600                             
var value = readOldUpdate(Tokenizer);
1601
1602                             
if (value != null) {
1603                                 token = Tokenizer.currentToken();
1604                                 lversion.push(parseInt(
value));
1605                                 lold =
true;
1606
1607                                 
if (token.tokenID == Token.End) {
1608                                     success =
true;
1609                                 }
1610                                 
else {
1611                                     lmatch = readMatch(Tokenizer);
1612                                     token = Tokenizer.currentToken();
1613
1614                                     
if (token.tokenID == Token.End) {
1615                                         success =
true;
1616                                     }
1617                                 }
1618                             }
1619                         }
1620                         
else {
1621                             token = Tokenizer.currentToken();
1622
1623                             
if (lold == true && token.tokenID == Token.Underbar) {
1624                                 token = Tokenizer.nextToken();
1625
1626                                 
if (token.tokenID == Token.Digits && lversion.length < MAX_DIGITS) {
1627                                     lversion.push(parseInt(token.token));
1628                                     Tokenizer.nextToken();
1629                                 }
1630                             }
1631
1632                             lpre = readPre(Tokenizer);
1633                             token = Tokenizer.currentToken();
1634
1635                             lbuild = readBuild(Tokenizer, lold);
1636                             lopt = readOpt(Tokenizer);
1637                             lmatch = readMatch(Tokenizer, lold);
1638                             token = Tokenizer.currentToken();
1639
1640                             
if (token.tokenID == Token.End) {
1641                                 success =
true;
1642                             }
1643                         }
1644
1645                         
if (success == true) {
1646                             result = {
1647                                 old: lold,
1648                                 version: lversion,
1649                                 build: lbuild,
1650                                 match: lmatch,
1651                                 pre: lpre,
1652                                 opt: lopt
1653                             };
1654                         }
1655                     }
1656                 }
1657
1658                 
return result;
1659             }
1660
1661             
return {
1662                 parse: parse
1663             }
1664         }
1665
1666         function parseAndSplitVersionString(versionString, UpgradeFromOldJavaVersion) {
1667             
var lold = false;
1668             
var lversion = new Array;
1669             
var lbuild = null;
1670             
var lmatch = null;
1671             
var lpre = false;
1672             
var lopt = null;
1673
1674             
// Corner case inputs.
1675             
if (versionString == null || versionString.length == 0) {
1676                 lversion = [
0, 0, 0, 0];
1677             }
1678             
else {
1679                 
var tokenizer = VersionStringTokenizer(versionString);
1680                 
var parser = VersionStringParser();
1681                 
var result = parser.parse(tokenizer);
1682
1683                 
if (result != null) {
1684                     
if (UpgradeFromOldJavaVersion == true &&
1685                         result.old ==
true) {
1686                         
if (result.version.length > 0 &&
1687                             result.version[
0] == 1) {
1688                             lversion = result.version.splice(
1, result.version.length - 1);
1689                         }
1690                         
else {
1691                             lversion = result.version;
1692                         }
1693
1694                         lold =
true;
1695                     }
1696                     
else {
1697                         lversion = result.version;
1698                     }
1699
1700                     lbuild = result.build;
1701                     lmatch = result.match;
1702                     lpre = result.pre;
1703                 }
1704             }
1705
1706             
return {
1707                 old: lold,
1708                 version: lversion,
1709                 build: lbuild,
1710                 match: lmatch,
1711                 pre: lpre,
1712                 opt: lopt
1713             };
1714         }
1715
1716         function sameVersion(query, version) {
1717             
var result = false;
1718             
var lquery = query;
1719
1720             
if (lquery == null)
1721                 lquery =
0;
1722
1723             
if (parseInt(lquery) == parseInt(version)) {
1724                 result =
true;
1725             }
1726
1727             
return result;
1728         }
1729
1730         
// compareVersionExact comparison returns true only if query and version are
1731         
// exact matches.
1732         function compareVersionExact(query, version) {
1733             
var result = false;
1734
1735             
if ((query.major != null) &&
1736                 (version.major !=
null) &&
1737                 sameVersion(query.major, version.major) &&
1738                 sameVersion(query.minor, version.minor) &&
1739                 sameVersion(query.security, version.security) &&
1740                 sameVersion(query.patch, version.patch) &&
1741                 (query.old == version.old) &&
1742                 (query.pre == version.pre) &&
1743                 ((parseInt(query.build) == parseInt(version.build)) || (query.build ==
null && version.build == null))) {
1744                 result =
true;
1745             }
1746
1747             
return result;
1748         }
1749
1750         
// compareVersionFamily comparison is for the * wild card for the current query
1751         
// version and anything above within the current version. For Example:
1752         
// 1.7* will match 1.7.8.9 but not 1.8.
1753         function compareVersionFamily(query, version) {
1754             
var result = false;
1755
1756             
// There is a subtle corner case comparison when comparing:
1757             
// 1.* to 1.8 (success)
1758             
// 1.* to 9.0 (fail)
1759             
// In this case, if both strings are old that means we have a 1s, so
1760             
// since the query string is all 0s, or empty, we have a match.
1761             
if (query.old == true && query.version.length == 0 && version.old == true) {
1762                 result =
true;
1763             }
1764             
else {
1765                 
// All elements must match on the query version array.
1766                 
for (index = 0 ;index < query.version.length && index < version.version.length;
1767                      index++) {
1768                     
var q = query.version[index];
1769                     
var v = version.version[index];
1770
1771                     
if (parseInt(q) == parseInt(v)) {
1772                         result =
true;
1773                     }
1774                     
else {
1775                         result =
false;
1776                         
break;
1777                     }
1778                 }
1779             }
1780
1781             
return result;
1782         }
1783
1784         
// compareVersionAbove comparison is for the + wild card for the current query
1785         
// version and anything above returning true.
1786         function compareVersionAbove(query, version) {
1787             
var result = false;
1788
1789             
if (query.old == true && query.version.length == 0) {
1790                 result =
true;
1791             }
1792             
else if (query.old == true && version.old == false) {
1793                 result =
true;
1794             }
1795             
else if (query.major == 0) {
1796                 result =
true;
1797             }
1798             
else if ((query.major != null) &&
1799                 (version.major !=
null) &&
1800                 ((parseInt(query.build) == parseInt(version.build)) || (query.build ==
null && version.build == null))) {
1801
1802                 
for (var index = 0; index < query.version.length; index++) {
1803                     
var q = query.version[index];
1804                     
var v = version.version[index];
1805
1806                     
if (parseInt(q) == parseInt(v)) {
1807                         result =
true;
1808                     }
1809                     
else if (parseInt(q) < parseInt(v)) {
1810                         
if ((query.old == true && version.old == true) ||
1811                             (query.old ==
false && version.old == false)) {
1812                             result =
true;
1813                         }
1814
1815                         
break;
1816                     }
1817                     
else {
1818                         result =
false;
1819                         
break;
1820                     }
1821                 }
1822             }
1823
1824             
return result;
1825         }
1826
1827         
// cloneAndCompleteVersionInfo is an internal method. It makes a copy of the
1828         
// version structure and completes the version array to contain four elements.
1829         function cloneAndCompleteVersionInfo(version) {
1830             
var clone_version = version.version.slice(0);
1831
1832             
// The source version string must be a complete version string (four digits).
1833             
// Example: 9.0.0.0
1834             
for (var index = clone_version.length; index < 4 ; index++) {
1835                 clone_version.push(
0);
1836             }
1837
1838             
var parts = splitVersion(clone_version);
1839
1840             
return {
1841                 old: version.old,
1842                 major: parts.major,
1843                 minor: parts.minor,
1844                 security: parts.security,
1845                 patch: parts.patch,
1846                 version: clone_version,
1847                 build: version.build,
1848                 pre: version.pre
1849             };
1850         }
1851
1852         
// Check performs a deploy pattern match comparison and returns
1853         
// true if the comparing version matches false if not.
1854         function check(query, version) {
1855             
var result = false;
1856
1857             
if (query.VersionString == null || query.VersionString.length == 0) {
1858                 result =
true;
1859             }
1860             
else {
1861                 
if (query.build == null && version.build == null) {
1862                     
var lversion = cloneAndCompleteVersionInfo(version);
1863
1864                     
if (query.match == Match.Exact) {
1865                         result = compareVersionExact(query, lversion);
1866                     }
1867                     
else if (query.match == Match.Family) {
1868                         result = compareVersionFamily(query, lversion);
1869                     }
1870                     
else if (query.match == Match.Above) {
1871                         result = compareVersionAbove(query, lversion);
1872                     }
1873                 }
1874             }
1875
1876             
return result;
1877         }
1878
1879         
// Performs a comparison on the two version string arguments and returns
1880         
// true if the comparing version matches false if not.
1881         function
equals(value, version) {
1882             
var result = false;
1883
1884             
if (query.VersionString == null || query.VersionString.length == 0) {
1885                 result =
true;
1886             }
1887             
else {
1888                 
var lversion = cloneAndCompleteVersionInfo(version);
1889                 
var lquery = cloneAndCompleteVersionInfo(query);
1890                 result = compareVersionExact(lquery, lversion);
1891             }
1892
1893             
return result;
1894         }
1895     };
1896
1897     
// Compares two version strings: query and version, matching query against version. query
1898     
// is allowed to have wild cards + and * version is not. The argument UpgradeFromOldJavaVersion
1899     
// is optional. This will remove the 1 prefix if present and mark the old field in the structure
1900     
// that is passed around.
1901     function versionCheck(query, version, UpgradeFromOldJavaVersion) {
1902         
var q = new Version(query, UpgradeFromOldJavaVersion);
1903         
var v = new Version(version, UpgradeFromOldJavaVersion);
1904         
return v.check(q);
1905     }
1906
1907     
// This is similar to version check rules except there is a range
1908     
// over versions (3-7) that are not valid.
1909     
//
1910     
// JavaFX version requirements are always treated as "not earlier than this update".
1911     
// I.e. we expect
1912     
// 2.2.0 to match 2.2*, 2.2+, 2.1+, 2.1*, 2.0 and 1+
1913     
// but not match 2.2.1+, 2.2.1*, 2.3*, 2.3+ or 1*
1914     function versionCheckFX(query, version) {
1915         
var q = new Version(query, false);
1916
1917         
if (parseInt(q.major) >= 3 && parseInt(q.major) <= 7 && query.substr(-1) !== "+") {
1918             
return false;
1919         }
1920
1921         
if (q.match == Match.Exact) {
1922             q =
new Version(query + "+", false);
1923         }
1924
1925         
var v = new Version(version, false);
1926
1927         
return v.check(q);
1928     }
1929
1930     
//as JavaFX comes with own plugin binaries then check based on mime types, etc.
1931     
// may be false positive as it only checks for plugin version, not real JRE
1932     
//Here we check that DT plugin is aware of JRE installations
1933     
//Note that:
1934     
// - if DT is not available we will return false but we only do this i
1935     
// ready to launch => DT must be found
1936     
// - we do not want to check in jreCheck() as we want to avoid loading
1937     
// DT plugin if we can (as old DT may make it not possible to autostart)
1938     function doublecheckJrePresence() {
1939         
if (!haveDTLite()) { //basically IE on windows or Old JRE on windows
1940           
if (postponeNativePluginInstallation && notNull(d.body)) {
1941               
// Native Plugin installation was postponed, as the page didn't have
1942               
// body at that time. Try to install the plugin now.
1943               installNativePlugin();
1944               postponeNativePluginInstallation =
false;
1945           }
1946           
var p = getPlugin();
1947           
if (p != null) {
1948             
return true;
1949             
//WORKAROUND: bug in native DT!!! TODO: What version? bypass for it only
1950             
//return (p.jvms.getLength() > 0);
1951           }
1952
1953           
return false;
1954         }
1955
1956         
//if we are not using native DT plugin (i.e. using DTLite) then no way we can do sanity check
1957         
// => assume first check is accurate
1958         
return true;
1959     }
1960
1961     function jreCheck(jre) {
1962         
// Check if latest JRE is exposed in mimetype and if it is good enough (only for NPAPI browsers)
1963         
if (ua.jre != null) {
1964             
if (versionCheck(jre, ua.jre)) {
1965                
return "ok";
1966             }
1967             
//Note: if we have JRE but it is not match that means we may need an upgrade message
1968             
// but we still could be able to get more accurate answer with native DT plugin
1969         }
1970
1971         
//try to use DT plugin
1972         
var p = getPlugin();
1973         
if (p != null) {
1974             
var VMs = p.jvms;
1975             
for (var i = 0; VMs != null && i < VMs.getLength(); i++) {
1976                 
if (versionCheck(jre, VMs.get(i).version)) {
1977                     
if (!ua.ie && notNull(navigator.mimeTypes)) {
1978                         
//if mime types are available but plugin is not there =>
1979                         
// it is disabled
1980                         
if (!notNull(navigator.mimeTypes["application/x-java-applet"])) {
1981                             
return "disabled";
1982                         }
1983                     }
1984                     
return "ok";
1985                 }
1986             }
1987             
//do not need to try other ways if used DT
1988             
return "none";
1989         }
1990
1991         
//No full DT => On Windows we can not launch FX anyways
1992         
// but may have old JRE
1993         
//And we might be able to launch on Mac/Linux
1994
1995
1996         
//This is only IE on Windows. This gives no update version. only e.g. 1.6.0
1997         
//and also cause java plugin to be loaded => browser will need to be restarted
1998         
//if new JRE is installed.
1999         
//However, if we got here than DT is not available and autoinstall is not possible
2000         
if (ua.ie) {
2001             
var lst = ["1.8.0", "1.7.0", "1.6.0", "1.5.0"];
2002             
for (var v = 0; v < lst.length; v++) {
2003                 
if (versionCheck(jre, lst[v])) {
2004                     
try {
2005                         
//TODO: FIXME: This does not seem to work in my testing in IE7?
2006                         
var axo = new ActiveXObject("JavaWebStart.isInstalled." + lst[v] + ".0");
2007                         
// This is not hit if the above throws an exception.
2008                         
return "ok";
2009                     }
catch (ignored) {
2010                     }
2011                 }
2012             }
2013         }
2014
2015
2016         
return "none";
2017     }
2018
2019     function checkJRESupport() {
2020         
//Negative test. New platforms will not be rejected
2021         
var osProblem = ['iPhone', 'iPod'];
2022         
var os = containsAny(osProblem, navigator.userAgent);
2023
2024         
//Do not support Chrome/Mac as Chrome is 32 bit only
2025         
var browser = (ua.mac && ua.chrome && ua.cputype == "intel");
2026
2027         
//autoinstall possible if native plugin is detected or OS is fine
2028         auto = os || (getPlugin() !=
null);
2029
2030         
//false is no problem found
2031         
return {os: os, browser: browser, auto: auto};
2032     }
2033
2034     
//it is not clear if we can work in IE6
2035     
// but it is hard to test and JRE7 does not even support it
2036     
// mark as unsupported for now
2037     function isUnsupportedVersionOfIE() {
2038         
if (ua.ie) {
2039             
try {
2040               
//these functions are defined in IE only
2041               
var v = 10*ScriptEngineMajorVersion() + ScriptEngineMinorVersion();
2042               
if (v < 57) return true; //IE7 will have 57
2043             }
catch (err) {
2044                 
//really old IE?
2045                 
return true;
2046             }
2047         }
2048         
return false;
2049     }
2050
2051     function checkFXSupport() {
2052         
var browser;
2053         
if (ua.win) {
2054             
//do not support Opera and Safari
2055             
// (not really tested, may be it works but known to have problems with DT detection)
2056             browser = ua.op || ua.wk || isUnsupportedVersionOfIE();
2057
2058             
//false is no problem found
2059             
return {os: false, browser: browser};
2060         }
else if (ua.mac && ua.cputype == "intel") { //do not support PPC/iphone/ipad ...
2061             
var os = !versionCheck("10.7.3+", ua.osVersion, false); //10.7.3 or later!
2062             browser = ua.op ||
2063                 (ua.mac && ua.chrome);
//Opera is not supported
2064             
//Chrome on Mac is 32 bit => plugin only work in 64 bit ...
2065             
//TODO: How do we detect FF running in 32 bit mode?
2066
2067             
//false is no problem found
2068             
return {os: os, browser: browser};
2069         }
else if (ua.linux) {
2070             browser = ua.op;
//Opera unsupported
2071
2072             
//false is no problem found
2073             
return {os: false, browser: browser};
2074         }
else {
2075             
//unknown unsupported OS
2076             
return {os: true, browser: false};
2077         }
2078     }
2079
2080     function relaxVersion(v) {
2081         
if (notNull(v) && v.length > 0) {
2082             
var c = v.charAt(v.length - 1);
2083             
if (c == '*') {
2084               v = v.substring(
0, v.length - 1)+"+";
2085             }
else if (c != '+') { //exact version (e.g. 1.6)
2086                 v = v +
"+";
2087             }
2088         }
2089         
return v;
2090     }
2091
2092     
//we relax validation rules where we try to embed or launch app
2093     
// in order to deal with requests for OLDER jres at the java level
2094     
//Basically we convert request for version in JRE family to request for any future JRE
2095     
//We do NOT do same for JavaFX right now. There is no real need before 3.0 and it is not clear if it is good thing
2096     
//
2097     
//Note we keep validation strict for install and validate-only scenarios.
2098     
// This allows to query accurate details from javascript
2099     function doValidateRelaxed(platform) {
2100         
var p = new dtjava.Platform(platform);
2101
2102         p.jvm = relaxVersion(p.jvm);
2103         
//p.javafx = relaxVersion(p.javafx);
2104
2105         
return doValidate(p);
2106     }
2107
2108     function doValidate(platform, noPluginWebBrowser) {
2109         
//ensure some platform is set (we could get array too!)
2110         platform =
new dtjava.Platform(platform);
2111
2112         
//problem markers
2113         
var fx = "ok", jre = "ok", restart = false, os = false, browser = false,
2114             p, details;
2115
2116         
//check JRE
2117         
if (notNull(platform.jvm) && jreCheck(platform.jvm) != "ok") { //matching JRE not found
2118             
var res = jreCheck("1+");
2119             
if (res == "ok") {
2120                 jre =
"old";
2121             }
else {
2122                 jre = res;
//"none" or "disabled"
2123             }
2124
2125             details = checkJRESupport();
2126             
if (details.os) {
2127                 jre =
"unsupported";
2128                 os =
true;
2129             }
else if(noPluginWebBrowser) {
2130         jre =
"ok";
2131         }
else {
2132                 browser = details.browser;
2133             }
2134         }
2135
2136         
//check FX
2137         
if (notNull(platform.javafx)) {
2138             details = checkFXSupport();
2139             
if (details.os) { //FX is not supported,
2140                               
//do not even try
2141                 fx =
"unsupported";
2142                 os = os || details.os;
2143             }
else if(noPluginWebBrowser) {
2144                 fx =
"ok";
2145         }
else if( details.browser) {
2146                 browser = browser || details.browser;
2147             }
else {
2148                 
//on non windows platforms automated install is not possible
2149                 
// (if it is needed on windows and possible we will set it to false later)
2150
2151                 
if (ua.fx != null) {
2152                   
//found cobundled JavaFX on 7u6+ (and it is NPAPI-based browser)
2153                   
if (versionCheckFX(platform.javafx, ua.fx)) {
2154                         fx =
"ok";
2155                   }
else if (versionCheckFX("2.0+", ua.fx)) {
2156                         fx =
"old";
2157                   }
2158                 }
else if (ua.win) { //could be 7u6(cobundle)/IE or JRE6/FX
2159                   
try {
2160                     p = getPlugin();
2161                     
//typeof did not work in IE
2162                     
var v = p.getInstalledFXVersion(platform.javafx);
2163                     
// If not found then try for the latest family (e.g. if the requested FX version is "2.2" and "8.0.5" is installed
2164                     
// we should not report that FX is old or does not exist. Instead we should continue with "8.0.5" and than either relaunch
2165                     
// with the requested JRE or offer the user to launch the app using the latest JRE installed).
2166                     
if (v == "" || v == null) {
2167                         v = p.getInstalledFXVersion(platform.javafx +
'+');
2168                     }
2169                     
//if found we should get version string, otherwise empty string or null. If found then fx=false!
2170                     
if (v == "" || v == null) {
2171                         v = p.getInstalledFXVersion(
"2.0+"); //check for any FX version
2172                         
if (v == null || v == "") {
2173                             fx =
"none";
2174                         }
else {
2175                             fx =
"old";
2176                         }
2177                     }
2178                   }
catch(err) {
2179                     
//If we got here then environment is supported but
2180                     
//this is non FX aware JRE => no FX and can only offer manual install
2181                     
// (restart needed as toolkit is already loaded)
2182                     fx =
"none";
2183                   }
2184                 }
else if (ua.mac || ua.linux) {
2185                     fx =
"none";
2186                 }
2187             }
2188         }
2189
2190         
//recommend relaunch if OS is ok but browser is not supported
2191         restart = restart || (!os && browser);
2192
2193         
//TODO: need a way to find out if java plugin is loaded => will need to relaunch
2194
2195         
//we need to return null if everything is ok. Check for problems.
2196         
if (fx != "ok" || jre != "ok" || restart || os || browser) {
2197             
return new PlatformMismatchEvent(
2198                 {fx: fx, jre: jre, relaunch: restart, os: os, browser: browser,
2199                     platform: platform});
2200         }
else {
2201             
//if all looks good check JRE again, it could be false positive
2202             
if (ua.override == false && !noPluginWebBrowser && !doublecheckJrePresence()) {
2203                
return new PlatformMismatchEvent(
2204                  {fx: fx, jre:
"none", relaunch: restart, os: os,
2205                      browser: browser, platform: platform});
2206             }
2207         }
2208
2209         
return null;
2210     }
2211
2212     
//TODO: does it make sense to have a way to explicitly request locale?
2213     function guessLocale() {
2214         
var loc = null;
2215
2216         loc = navigator.userLanguage;
2217         
if (loc == null)
2218             loc = navigator.systemLanguage;
2219         
if (loc == null)
2220             loc = navigator.language;
2221
2222         
if (loc != null) {
2223             loc = loc.replace(
"-", "_")
2224         }
2225         
return loc;
2226     }
2227
2228     function getJreUrl(loc) {
2229         
if (!notNull(loc)) {
2230             loc = guessLocale();
2231         }
2232         
return 'https://java.com/dt-redirect?' +
2233             ((notNull(window.location) && notNull(window.location.href)) ?
2234                 (
'&returnPage=' + window.location.href) : '') +
2235             (notNull(loc) ? (
'&locale=' + loc) : '');
2236         
//NB: brand parameter is not supported for now
2237     }
2238
2239     function getFxUrl(locale) {
2240         
return "http://www.oracle.com/technetwork/java/javafx/downloads/index.html";
2241     }
2242
2243     
//return true if mismatch event suggest to perform installation
2244     function isMissingComponent(v) {
2245         
if (v != null) {
2246             
var jre = v.jreStatus();
2247             
var fx = v.javafxStatus();
2248             
//if anything is disabled then this need to be resolved before any further installs
2249             
return (jre == "none" || fx == "none" || jre == "old" || fx == "old")
2250                && (fx !=
"disabled" && jre != "disabled");
2251         }
2252         
return false;
2253     }
2254
2255     function showClickToInstall(ld, isJRE, isUpgrade, isAutoinstall, isRelaunchNeeded, actionFunc) {
2256         
//what product?
2257         
var productName, productLabel;
2258         
if (isJRE) {
2259             productName =
"Java";
2260             productLabel =
"java";
2261         }
else {
2262             productName =
"JavaFX";
2263             productLabel =
"javafx";
2264         }
2265
2266         
var msg1, msg2, imgName;
2267         
if (isUpgrade) {
2268             msg1 =
"A newer version of " + productName + "is required to view the content on this page.";
2269             msg2 =
"Please click here to update " + productName;
2270             imgName =
"upgrade_"+productLabel+".png";
2271         }
else {
2272             msg1 =
"View the content on this page.";
2273             msg2 =
"Please click here to install " + productName;
2274             imgName =
"get_"+productLabel+".png";
2275         }
2276         
var altText = "Click to install "+productName;
2277
2278         doShowMessageInTheArea(ld, msg1, msg2, altText, imgName, actionFunc);
2279     }
2280
2281     function doShowMessageInTheArea(ld, msg1, msg2, altText, imgName, actionFunc) {
2282         
//if image will fit (size 238x155)
2283         
var r = d.createElement("div");
2284         r.width = normalizeDimension(ld.width);
2285         r.height = normalizeDimension(ld.height);
2286
2287         
var lnk = d.createElement("a");
2288         lnk.href=
"";
2289         lnk.onclick = function() {actionFunc();
return false;};
2290         
if (ld.width < 250 || ld.height < 160) { //if relative size this will fail =>
2291                                                  
// will choose image
2292             r.appendChild(
2293                d.createElement(
"p").appendChild(
2294                   d.createTextNode(msg1)));
2295             lnk.appendChild(d.createTextNode(msg2));
2296             r.appendChild(lnk);
2297         }
else {
2298             
var img = d.createElement("img");
2299             img.src = jscodebase + imgName;
2300             img.alt = altText;
2301             img.style.borderWidth=
"0px";
2302             img.style.borderStyle=
"none";
2303 //FIXME: centering image does not work (
in a way it also work with relative dimensions ...)
2304 // lnk.style.top=
"50%";
2305 // lnk.style.left=
"50%";
2306 // lnk.style.marginTop = -
119; // 238/2
2307 // lnk.style.marginLeft = -
77; //155/2
2308             lnk.appendChild(img);
2309             r.appendChild(lnk);
2310         }
2311         wipe(ld.placeholder);
2312         ld.placeholder.appendChild(r);
2313     }
2314
2315     function canJavaFXCoBundleSatisfy(platform) {
2316         
// check if latest co-bundle can satisfy
2317         
if (versionCheck(platform.jvm, minJRECobundleVersion, false) &&
2318             versionCheckFX(platform.javafx,
"2.2.0")) {
2319             
return true;
2320         }
2321         
return false;
2322     }
2323
2324     function defaultInstallHandler(app, platform, cb,
2325                                    isAutoinstall, needRelaunch, launchFunc) {
2326         
var installFunc = function() {
2327             doInstall(app, platform, cb, launchFunc);
2328         };
2329
2330         
var s = doValidate(platform);
2331         
if (!notNull(s)) { //platform match => nothing to install
2332             
if (notNull(launchFunc)) {
2333                 launchFunc();
2334             }
2335         }
2336
2337         
var isUpgrade = notNull(s) && (s.javafxStatus() == "old" || s.jreStatus() == "old");
2338         
if (notNull(app.placeholder)) { //embedded
2339             
if (canJavaFXCoBundleSatisfy(platform)) { //if both JRE and FX are missing we will start install from JRE
2340                 
//it is only JRE that needs to be updated
2341                showClickToInstall(app,
true, isUpgrade, isAutoinstall, needRelaunch, installFunc);
2342             }
else {
2343                showClickToInstall(app, (s.jreStatus() !=
"ok"), isUpgrade, isAutoinstall, needRelaunch, installFunc);
2344             }
2345         }
else { //webstart
2346           
var r = isAutoinstall;
2347           
var msg = null;
2348           
if (!r) {
2349              
if (canJavaFXCoBundleSatisfy(platform)) { //if both JRE and FX are missing we will start install from JRE
2350                  
//it is only JRE that needs to be updated
2351                  
if (isUpgrade) {
2352                      msg =
"A newer version of Java is required to view the content on this page. Please click here to update Java.";
2353                  }
else {
2354                      msg =
"To view the content on this page, please click here to install Java.";
2355                  }
2356                  r = confirm(msg);
2357              }
else {
2358                  
if (isUpgrade) {
2359                      msg =
"A newer version of JavaFX is required to view the content on this page. Please click here to update JavaFX.";
2360                  }
else {
2361                      msg =
"To view the content on this page, please click here to install JavaFX.";
2362                  }
2363                  r = confirm(msg);
2364              }
2365           }
2366           
if (r)
2367              installFunc();
2368         }
2369     }
2370
2371     
/**
2372      * returns
true if we can enable DT plugin auto-install without chance of
2373      * deadlock
on cert mismatch dialog
2374      *
2375      * requestedJREVersion param
is optional - if null, it will be
2376      * treated
as installing any JRE version
2377      *
2378      * DT plugin
for 6uX only knows about JRE installer signed by SUN cert.
2379      * If it encounter Oracle signed JRE installer, it will have chance of
2380      * deadlock
when running with IE. This function is to guard against this.
2381      */

2382     function enableWithoutCertMisMatchWorkaround(requestedJREVersion) {
2383
2384        
// Non-IE browser are okay
2385        
if (!ua.ie) return true;
2386
2387        
// if DT plugin is 10.0.0 or above, return true
2388        
// This is because they are aware of both SUN and Oracle signature and
2389        
// will not show cert mismatch dialog that might cause deadlock
2390        
if (versionCheck("10.0.0+", getPlugin().version, false)) {
2391           
return true;
2392        }
2393
2394        
// If we got there, DT plugin is 6uX
2395
2396        
if (requestedJREVersion == null) {
2397           
// if requestedJREVersion is not defined - it means ANY.
2398           
// can not guarantee it is safe to install ANY version because 6uX
2399           
// DT does not know about Oracle certificates and may deadlock
2400           
return false;
2401        }
2402
2403        
// 6u32 or earlier JRE installer used Sun certificate
2404        
// 6u33+ uses Oracle's certificate
2405        
// DT in JRE6 does not know about Oracle certificate => can only
2406        
// install 6u32 or earlier without risk of deadlock
2407        
return !versionCheck("1.6.0_33+", requestedJREVersion);
2408     }
2409
2410     
// return true if we can auto-install to satisfy the platform requirement
2411     
// return false otherwise
2412     
//
2413     
// We can auto-install if all below is true:
2414     
// - windows platform
2415     
// - native DT plugin available
2416     
// - if JRE install is required, JRE exe is signed by compatible
2417     
// certificate
2418     
// - if FX install is required, JRE co-bundle can satisfy the
2419     
// requirement or DT plugin supports FX auto-install
2420     function isAutoInstallEnabled(platform, jre, fx) {
2421        
// auto-install is windows only
2422        
if (!ua.win) return false;
2423
2424        
// if no DT plugin, return false
2425        
// if DT plugin is there but not operational (e.g. blocked)
2426        
// then pretend there is no autoinstall
2427        
var p = getPlugin();
2428        
if (p == null || !isDef(p.version)) return false;
2429
2430        
if (jre != "ok") {
2431            
// need JRE install
2432            
if (!enableWithoutCertMisMatchWorkaround(platform.jvm)) {
2433                
return false;
2434            }
2435        }
2436
2437        
if (fx != "ok") {
2438             
if (!canJavaFXCoBundleSatisfy(platform)) {
2439                 
// no cobundle, check if there is standalone FX auto-install
2440                 
// DT from Java 7 or later should be ok
2441                 
if (!versionCheck("10.0.0+", getPlugin().version, false)) {
2442                     
return false;
2443                 }
2444             }
else {
2445                 
// we are going to install co-bundle JRE - check if we can do
2446                 
// that
2447                 
if (!enableWithoutCertMisMatchWorkaround(minJRECobundleVersion)) {
2448                     
return false;
2449                 }
2450             }
2451         }
2452         
return true;
2453     }
2454
2455     function doInstall(app, platform, cb, postInstallFunc) {
2456         
var s = doValidate(platform);
2457
2458         cb =
new dtjava.Callbacks(cb);
2459
2460         
if (notNull(s) && s.isUnsupportedPlatform()) {
2461             reportPlatformError(app, s, cb);
2462             
return false; //no install
2463         }
2464
2465         
var placeholder = (app != null) ? app.placeholder : null;
2466
2467         
var codes, status;
2468         
if (isMissingComponent(s)) { //otherwise nothing to install
2469             
if (s.jre != "ok") {
2470                 
if (isDef(cb.onInstallStarted)) {
2471                     cb.onInstallStarted(placeholder,
"Java",
2472                                         
false, getPlugin() != null);
2473                 }
2474                 startManualJREInstall();
2475             }
else { //what it could be??
2476               reportPlatformError(app, s, cb);
2477             }
2478         }
else {
2479             
//nothing to install
2480             
if (postInstallFunc != null) {
2481                 postInstallFunc();
2482             }
2483             
return true;
2484         }
2485         
//no install initiated
2486         
return false;
2487     }
2488
2489     
//just open download URL in new window
2490     function startManualJREInstall() {
2491         w.open(getJreUrl());
2492     }
2493
2494     
//just open download URL in new window
2495     function startManualFXInstall() {
2496         w.open(javafxURL);
2497     }
2498
2499     function defaultGetSplashHandler(ld) {
2500         
if (ld.placeholder != null) {
2501             
var _w = ld.width, _h = ld.height;
2502             
//prepare image
2503             
//if width and height are relative then comparison with int will be false
2504             
// and we will end up using large image. This is on purpose
2505             
// as it is unlikely that relative dimensions are used for tiny applet areas
2506             
var isBig = !(_w < 100 && _h < 100);
2507             
var iU = isBig ? 'javafx-loading-100x100.gif' : 'javafx-loading-25x25.gif';
2508             
var iW = isBig ? 80 : 25;
2509             
var iH = isBig ? 80 : 25;
2510
2511             
var img = d.createElement("img");
2512             img.src = jscodebase + iU;
2513             img.alt =
"";
2514             
//position in the center of the container
2515             img.style.position =
"relative";
2516             img.style.top =
"50%";
2517             img.style.left =
"50%";
2518             img.style.marginTop = normalizeDimension(-iH/
2);
2519             img.style.marginLeft = normalizeDimension(-iW/
2);
2520
2521             
return img;
2522         }
else {
2523             
//webstart or install case
2524             
//TODO: show some html splash for webstart? how to hide it?
2525             
return null;
2526         }
2527     }
2528
2529     function defaultGetNoPluginMessageHandler(app) {
2530         
if (app.placeholder != null) {
2531             
var p = d.createElement("p");
2532             p.appendChild(d.createTextNode(
"FIXME - add real message!"));
2533             
return p;
2534         }
//no op if not embedded content
2535         
return null;
2536     }
2537
2538     
//remove all child elements for given node
2539     function wipe(c) {
2540         
while(c.hasChildNodes()) c.removeChild(c.firstChild);
2541     }
2542
2543     function defaultInstallStartedHandler(placeholder, component, isAuto, restartNeeded) {
2544         
if (placeholder != null) {
2545             
var code = null;
2546             
if (isAuto) {
2547                 code = (component ==
"JavaFX") ?
2548                     
"install:inprogress:javafx": "install:inprogress:jre";
2549             }
else {
2550                 code = (component ==
"JavaFX") ?
2551                     
"install:inprogress:javafx:manual" : "install:inprogress:jre:manual";
2552             }
2553
2554             appletInfoMsg(code);
2555         }
2556     }
2557
2558     function defaultInstallFinishedHandler(placeholder, component, status, relaunch) {
2559         
var t;
2560         
if (status != "success") {
2561             
var msg = null;
2562             
if (component == "javafx") {
2563                 
if (!doublecheckJrePresence()) { //guess if we failed due to no JRE
2564                     
//need to request to install JRE first
2565                     msg =
"install:fx:error:nojre";
2566                 }
else {
2567                     msg =
"install:fx:"+status;
2568                 }
2569             }
else { //must be JRE error
2570                 msg =
"install:jre:"+status;
2571             }
2572             
if (placeholder != null) {
2573                 t = appletErrorMsg(msg,
null);
2574
2575                 
//Instead of hiding splash and applet we simply clear the container
2576                 
//We are not going to show neither splash nor applet anyways ...
2577                 wipe(placeholder);
2578                 placeholder.appendChild(t);
2579             }
else {
2580                 w.alert(webstartErrorMsg(msg));
2581             }
2582         }
else { //success
2583             
if (relaunch) {
2584                 t = appletInfoMsg(
"install:fx:restart");
2585
2586                 
//Instead of hiding splash and applet we simply clear the container
2587                 
//We are not going to show neither splash nor applet anyways ...
2588                 wipe(placeholder);
2589                 placeholder.appendChild(t);
2590             }
2591         }
2592     }
2593
2594     function defaultDeployErrorHandler(app, r) {
2595         
if (r == null) {
2596             code =
"success";
2597         }
else if (r.isUnsupportedBrowser()) {
2598             code =
"browser";
2599         }
else if (r.jreStatus() != "ok") {
2600             code =
"jre:" + r.jreStatus();
2601         }
else if (r.javafxStatus() != "ok") {
2602             code =
"javafx:" + r.javafxStatus();
2603         }
else if (r.isRelaunchNeeded()) {
2604             code =
"relaunch";
2605         }
else {
2606             code =
"unknown " + r.toString();
2607         }
2608
2609         
if (app.placeholder != null) {//embedded app
2610             showAppletError(app.id, code,
null);
2611         }
else { //webstart or install case
2612             w.alert(webstartErrorMsg(code));
2613         }
2614     }
2615
2616     function defaultRuntimeErrorHandler(id) {
2617         
var el_applet = findAppletDiv(id);
2618
2619         
if (getErrorDiv(id) != null) {
2620             showAppletError(id,
"launch:fx:generic:embedded",
2621                 function() {showHideApplet(findAppletDiv(id),
false); return false;});
2622         }
else {
2623             w.alert(webstartErrorMsg(
"launch:fx:generic"));
2624         }
2625     }
2626
2627     
//TODO: Does availability of object mean initialization is completed (or even started?)
2628     
//Can we expect that any subsequent call to this object will actually work?
2629     
//Perhaps it is false alarm
2630     function getPlugin() {
2631         
var result = null;
2632
2633         
if (ua.override == false) {
2634             navigator.plugins.refresh(
false);
2635             result = document.getElementById(
'dtjavaPlugin');
2636         }
2637
2638         
return result;
2639     }
2640
2641     function installNativePlugin() {
2642         
//already installed?
2643         
if (getPlugin() != null) return;
2644
2645         
//can not install plugin now as page has no body yet, postpone
2646         
//NB: use cbDone here to avoid infinite recursion (corner case)
2647         
if (!notNull(d.body) && !cbDone) {
2648             addOnDomReadyInternal(function() {
2649                 installNativePlugin();
2650             });
2651             postponeNativePluginInstallation =
true;
2652             
return;
2653         }
2654
2655         
var p = null;
2656         
if (ua.ie) {
2657             p = d.createElement(
'object');
2658             
//TODO: zero size does not work?? How we can make it less intrusive for layout?
2659             p.width =
'1px';
2660             p.height =
'1px';
2661             
//new CLSID, one with 0000-0000 had been kill bit
2662             p.classid =
'clsid:CAFEEFAC-DEC7-0000-0001-ABCDEFFEDCBA';
2663         }
else {
2664             
// Safari and Opera browsers find the plugin but it
2665             
// doesn't work, so until we can get it to work - don't use it.
2666             
if (!ua.wk && !ua.op && navigator.mimeTypes != null) {
2667                 
// mime-type of the DeployToolkit plugin object
2668                 
// (do not care about old DT plugin anymore)
2669                 
var mimeType = 'application/java-deployment-toolkit';
2670                 
var newDT = false;
2671                 
for (var i = 0; i < navigator.mimeTypes.length; i++) {
2672                     
var mt = navigator.mimeTypes[i];
2673                     newDT = newDT || ((mt.type == mimeType) && mt.enabledPlugin);
2674                 }
2675                 
if (newDT) {
2676                     p = d.createElement(
'embed');
2677                     p.setAttribute(
'type', newDT ? mimeType : oldMimeType);
2678                     p.setAttribute(
'hidden', 'true');
2679                 }
2680             }
2681         }
2682         
if (p != null) {
2683             p.setAttribute(
'id', 'dtjavaPlugin');
2684             d.body.appendChild(p);
2685
2686             
// Update internal versions from plug-in if needed
2687             
if (ua.deploy == null && isDef(p.version)) {
2688                 ua.deploy = p.version;
2689             }
2690         }
2691     }
2692
2693     
var appletCounter = 0;
2694
2695     function prepareAppletID(ld) {
2696         
if (notNull(ld.id)) {
2697             
return ld.id;
2698         }
else {
2699             appletCounter++;
2700             
return ("dtjava-app-" + appletCounter);
2701         }
2702     }
2703
2704     
//returns object that represents an applet/object tag
2705     function getAppletSnippet(ld, platform, cb) {
2706         
//we use wrapper div here as changing style on applet tag
2707         
// cause liveconnect to be initialized and slows down startup
2708         
var wrapper = d.createElement("div");
2709         wrapper.width = normalizeDimension(ld.width);
2710         wrapper.height = normalizeDimension(ld.height);
2711         wrapper.id = ld.id +
"-app";
2712         
//without this it splash will not work in Chrome
2713         wrapper.style.position =
"relative";
2714
2715         
var r = d.createElement("applet"); //TODO: use object!
2716
2717         r.code =
"dummy.class";
2718         r.id = ld.id;
2719         r.width = normalizeDimension(ld.width);
2720         r.height = normalizeDimension(ld.height);
2721
2722         
//things added unconditionally
2723         
var sparams = {"jnlp_href" : ld.url,
2724             
"java_status_events" : true,
2725             
"type" : "application/x-java-applet"};
2726
2727         
if (notNull(ld.jnlp_content)) {
2728             sparams[
'jnlp_embedded'] = ld.jnlp_content;
2729         }
2730         
if (notNull(platform.javafx)) {
2731             
//for swing applications embedding FX we do not want this property as it will
2732             
// trigger FX toolkit and lead to app failure!
2733             
if (!notNull(ld.toolkit) || ld.toolkit == "fx") {
2734                sparams[
"javafx_version"] = ((platform.javafx == "*") ? "2.0+" : platform.javafx);
2735             }
2736             
//FX requires new VM per applet, do it unconditionally
2737             sparams[
"separate_jvm"] = true;
2738             sparams[
"javafx_applet_id"] = r.id;
2739             
//enable scripting for FX unconditionally for now
2740             sparams[
"scriptable"] = true;
2741         }
else {
2742             
if (ld.scriptable) {
2743                 sparams[
"scriptable"] = true;
2744             }
2745             
if (ld.sharedjvm) {
2746                 sparams[
"separate_jvm"] = true;
2747             }
2748         }
2749         
if (notNull(platform.jvmargs)) {
2750             sparams[
"java_arguments"] = listToString(platform.jvmargs);
2751         }
2752
2753         
//prepare parameters first
2754         
var key, p;
2755         
for (key in ld.params) {
2756             
//do not let to override system parameters
2757             
if (!notNull(sparams[key])) {
2758                 p = d.createElement(
"param");
2759                 p.name = key;
2760                 p.
value = ld.params[key];
2761                 r.appendChild(p);
2762             }
2763         }
2764         
for (key in sparams) {
2765             p = d.createElement(
"param");
2766             p.name = key;
2767             p.
value = sparams[key];
2768             r.appendChild(p);
2769         }
2770
2771         
if (isDef(cb.onGetNoPluginMessage)) {
2772             p = d.createElement(
"noapplet");
2773             
var t = cb.onGetNoPluginMessage(ld);
2774             p.appendChild(t);
2775             
//TODO: FIXME: following line fails for me in IE7??
2776             
//r.appendChild(p);
2777         }
2778
2779         wrapper.appendChild(r);
2780         
return wrapper;
2781     }
2782
2783     function findAppletDiv(id) {
2784         
//TODO: FIXME: in static deployment scenario this seem to cause restart of plugin (in FF)
2785         
//Weird but similar code works in the deployJava.js ...
2786         
//TODO: reinvestigate
2787         
var el = d.getElementById(id + "-app");
2788         
if (el == null) { //wrapping div for applet is not required
2789             el = d.getElementById(id);
2790         }
2791         
return el;
2792     }
2793
2794     
//IMPORTANT: whilst we can update style on the applet element itself
2795     
// this is not best idea as this may also cause wait till liveconnect
2796     
// is initialized and slow startup.
2797     function showHideApplet(div, hide) {
2798         
if (!notNull(div)) return;
2799         
if (hide) {
2800             div.style.left = -
10000;
2801         }
else {
2802             div.style.left =
"0px";
2803         }
2804     }
2805
2806     function showHideDiv(div, hide) {
2807         
if (!notNull(div)) return;
2808         
if (hide) {
2809             div.style.visibility =
"hidden";
2810         }
else {
2811             div.style.visibility =
"visible";
2812         }
2813     }
2814
2815     function doHideSplash(id) {
2816         
try {
2817             
var errPane = getErrorDiv(id);
2818             
if (errPane != null && errPane.style != null && errPane.style.visibility == "visible") {
2819                 
//if we have error pane shown then ignore this request
2820                 
// (could be race condition and applet is asking to hide splash to show error too)
2821                 
return;
2822             }
2823
2824             
var el = findAppletDiv(id);
2825             showHideApplet(el,
false);
2826
2827             
//show applet first and then hide splash to avoid blinking
2828             showHideDiv(d.getElementById(id +
"-splash"), true);
2829         }
catch(err) {}
2830     }
2831
2832     
var javafxURL = "https://java.com/javafx";
2833
2834     
//TODO: validate ALL messages are shown as expected and when expected (for applet/webstart/install)
2835     
var errorMessages = {
2836         
"launch:fx:generic" : ["JavaFX application could not launch due to system configuration.",
2837             
" See ", "a", "https://java.com/javafx", "java.com/javafx",
2838             
" for troubleshooting information."],
2839         
"launch:fx:generic:embedded" : ["JavaFX application could not launch due to system configuration ",
2840             
"(", "onclick", "show error details", ").",
2841             
" See ", "a", "https://java.com/javafx", "java.com/javafx",
2842             
" for troubleshooting information."],
2843         
"install:fx:restart" : ["Restart your browser to complete the JavaFX installation,",
2844             
" then return to this page."],
2845         
"install:fx:error:generic" : ["JavaFX install not completed.",
2846             
" See ", "a", "https://java.com/javafx", "java.com/javafx",
2847             
" for troubleshooting information."],
2848         
"install:fx:error:download" : ["JavaFX install could not start because of a download error.",
2849             
" See ", "a", "https://java.com/javafx", "java.com/javafx",
2850             
" for troubleshooting information."],
2851         
"install:fx:error:cancelled" : ["JavaFX install was cancelled.",
2852             
" Reload the page and click on the download button to try again."],
2853         
"install:jre:error:cancelled" : ["Java install was cancelled.",
2854             
" Reload the page and click on the download button to try again."],
2855         
"install:jre:error:generic" : ["Java install not completed.",
2856             
" See ", "a", "https://java.com/", "java.com",
2857             
" for troubleshooting information."],
2858         
"install:jre:error:download" : ["Java install could not start because of a download error.",
2859             
" See ", "a", "https://java.com/", "java.com/",
2860             
" for troubleshooting information."],
2861         
"install:inprogress:jre" : ["Java install in progress."],
2862         
"install:inprogress:javafx" : ["JavaFX install in progress."],
2863         
"install:inprogress:javafx:manual" : ["Please download and run JavaFX Setup from ",
2864             
"a", getFxUrl(null), "java.com/javafx",
2865             
". When complete, restart your browser to finish the installation,",
2866             
" then return to this page."],
2867         
"install:inprogress:jre:manual" : ["Please download and run Java Setup from ",
2868             
"a", getJreUrl(), "java.com/download",
2869             
". When complete, reload the page."],
2870         
"install:fx:error:nojre" : ["b", "Installation failed.", "br",
2871             
"Java Runtime is required to install JavaFX and view this content. ",
2872             
"a", getJreUrl(), "Download Java Runtime",
2873             
" and run the installer. Then reload the page to install JavaFX."],
2874         
"browser": [ 'Content can not be displayed using your Web browser. Please open this page using another browser.'],
2875         
"jre:none": [ 'JavaFX application requires a recent Java runtime. Please download and install the latest JRE from ',
2876             
'a', 'https://java.com', "java.com", '.'],
2877         
"jre:old" : [ 'JavaFX application requires a recent Java runtime. Please download and install the latest JRE from ',
2878             
'a', 'https://java.com', "java.com", '.'],
2879         
"jre:plugin": ['b', "A Java plugin is required to view this content.", 'br',
2880             
"Make sure that ", "a", 'https://java.com', "a recent Java runtime",
2881             
" is installed, and the Java plugin is enabled."],
2882         
"jre:blocked": ["Please give Java permission to run. This will allow Java to present content provided on this page."],
2883         
"jre:unsupported": ["b", "Java is required to view this content but Java is currently unsupported on this platform.",
2884             
"br", "Please consult ", "a", "https://java.com", "the Java documentation",
2885             
" for list of supported platforms."],
2886         
"jre:browser" : ["b", "Java plugin is required to view this content but Java plugin is currently unsupported in this browser.",
2887             
"br", "Please try to launch this application using other browser. Please consult ",
2888             
"a", "https://java.com", "the Java documentation",
2889             
" for list of supported browsers for your OS."],
2890         
"javafx:unsupported" : ["b", "JavaFX 2.0 is required to view this content but JavaFX is currently unsupported on this platform.",
2891             
"br", "Please consult ", "a", javafxURL, "the JavaFX documentation",
2892             
" for list of supported platforms."],
2893         
"javafx:old" : [ 'This application requires newer version of JavaFX runtime. ',
2894             
'Please download and install the latest JavaFX Runtime from ',
2895             
'a', javafxURL, "java.com/javafx", '.'],
2896         
"javafx:none" : ["b", "JavaFX 2.0 is required to view this content.",
2897             
"br", "a", javafxURL, "Get the JavaFX runtime from java.com/javafx",
2898             
" and run the installer. Then restart the browser."],
2899         
"javafx:disabled" : ["JavaFX is disabled. Please open Java Control Panel, switch to Advanced tab and enable it. ",
2900             
"Then restart the browser."],
2901         
"jre:oldplugin" : ["New generation Java plugin is required to view this content." +
2902                 
" Please open Java Control Panel and enable New Generation Java Plugin."],
2903         
"jre:disabled" : ["Java plugin appear to be disabled in your browser. ",
2904                 
" Please enable Java in the browser options."]
2905     };
2906
2907     
//assume we get list of (tag, param, text) where both param and tag are optional
2908     
// Supported tags:
2909     
// ("a", href value, link text)
2910     
// ("b", text)
2911     
// ("br")
2912     
// (text) //text can not be the same as any of tag names
2913     function msgAsDOM(lst, extra, onClickFunc) {
2914         
var i = 0;
2915         
var root = d.createElement("p");
2916
2917         
if (extra != null) {
2918             root.appendChild(extra);
2919         }
2920         
var el;
2921         
while (i < lst.length) {
2922             
switch (lst[i]) {
2923                 
case "a":
2924                     el = d.createElement(lst[i]);
2925                     el.href = lst[i +
1];
2926                     el.appendChild(d.createTextNode(lst[i +
2]));
2927                     i = i +
2;
2928                     
break;
2929                 
case "br":
2930                     el = d.createElement(lst[i]);
2931                     
break;
2932                 
case "b":
2933                     el = d.createElement(lst[i]);
2934                     el.appendChild(d.createTextNode(lst[i +
1]));
2935                     i++;
2936                     
break;
2937                 
case "onclick":
2938                     el = d.createElement(
"a");
2939                     el.href =
"";
2940                     
if (onClickFunc == null) {
2941                        onClickFunc = function() {
return false;}
2942                     }
2943                     el.onclick = onClickFunc;
2944                     el.appendChild(d.createTextNode(lst[i +
1]));
2945                     i = i +
1;
2946                     
break;
2947                 
default:
2948                     el = d.createTextNode(lst[i]);
2949                     
break;
2950             }
2951             root.appendChild(el);
2952             i++;
2953         }
2954         
return root;
2955     }
2956
2957     function webstartErrorMsg(code) {
2958         
var m = "";
2959         
var lst = errorMessages[code];
2960         
var i = 0;
2961         
if (notNull(lst)) {
2962           
while (i < lst.length) {
2963               
if (lst[i] != 'a' && lst[i] != 'br' && lst[i] != 'b') {
2964                   m += lst[i];
2965               }
else if (lst[i] == 'a') { //next element is link => skip it
2966                   i++;
2967               }
2968               i++;
2969           }
2970         }
else {
2971             m =
"Unknown error: ["+code+"]";
2972         }
2973         
return m;
2974     }
2975
2976     function getErrorDiv(id) {
2977         
return d.getElementById(id + "-error");
2978     }
2979
2980     function showAppletError(id, code, onclickFunc) {
2981         
var pane = getErrorDiv(id);
2982
2983         
if (!notNull(pane)) { //should not be possible, we add error pane right a way and then add it again before we add splash/app
2984             
return;
2985         }
2986
2987         
//remove old content in the ERROR PANE only (if any)
2988         wipe(pane);
2989
2990         
//populate and show pane
2991         pane.appendChild(appletErrorMsg(code, onclickFunc));
2992         pane.style.visibility =
"visible";
2993
2994         
//hide splash and applet
2995         showHideDiv(d.getElementById(id+
"-splash"), true);
2996         showHideApplet(findAppletDiv(id),
true);
2997     }
2998
2999     
//returns DOM subtree
3000     function appletErrorMsg(code, onclickFunc) {
3001         
var out = d.createElement("div");
3002         
var img = d.createElement("img");
3003         img.src = jscodebase +
'error.png';
3004         img.width =
'16px';
3005         img.height =
'16px';
3006         img.alt =
"";
3007         img.style.cssFloat =
"left";
3008         img.style.styleFloat =
"left"; //IE way
3009         img.style.margin =
"0px 10px 60px 10px";
3010         img.style.verticalAlign=
"text-top";
3011
3012         
var m = errorMessages[code];
3013         
//error message is missing => show code as fallback
3014         
if (!notNull(m)) {
3015             m = [code];
3016         }
3017
3018         
var hideFunc = null;
3019
3020         
if (isDef(onclickFunc)) {
3021             hideFunc = function() {
3022                 
if (notNull(out.parentNode)) {
3023                   
out.parentNode.removeChild(out);
3024                 }
3025                 
try {
3026                     onclickFunc();
3027                 }
catch (e) {}
3028                 
return false;
3029             }
3030         }
3031
3032         
out.appendChild(msgAsDOM(m, img, hideFunc));
3033         
return out;
3034     }
3035
3036     
//returns DOM subtree
3037     function appletInfoMsg(code) {
3038         
var out = d.createElement("div");
3039
3040         
var m = errorMessages[code];
3041         
//error message is missing => show code as fallback
3042         
if (!notNull(m)) {
3043             m = [code];
3044         }
3045
3046         
out.appendChild(msgAsDOM(m, null, null));
3047         
return out;
3048     }
3049
3050     function normalizeApp(ld, acceptString) {
3051         
var app = null;
3052         
//normalize launch descriptor
3053         
if (notNull(ld)) {
3054             
//could be either url or set of parameters
3055             
if (acceptString && typeof ld === 'string') {
3056                 app =
new dtjava.App(ld, null);
3057             }
else if (ld instanceof dtjava.App) {
3058                 app = ld;
3059             }
else {
3060                 app =
new dtjava.App(ld.url, ld);
3061             }
3062         }
3063         
return app;
3064     }
3065
3066     function setupAppletCallbacks(platform, callbacks) {
3067         
//set default callbacks
3068         
var cb = new dtjava.Callbacks(callbacks);
3069
3070         
//disable splash if it is was not requested explicitly and
3071         
// it is not JavaFX app
3072         
if (platform.javafx == null && cb.onGetSplash === defaultGetSplashHandler) {
3073             cb.onGetSplash =
null;
3074         }
3075         
return cb;
3076     }
3077
3078     
//width and height in styles need to have unit type explicitly referenced
3079     
// or they will not conform to strict doctypes
3080     
//On other hand we can have relative dimensions, e.g. 100% and these are fine without units
3081     
//
3082     
//This method will add unit type to numeric dimension specifications. E.g.
3083     
// 400 => 400px
3084     
// -10 => -10px
3085     
// 50% => 50%
3086     function normalizeDimension(v) {
3087         
if (isFinite(v)) {
3088             
return v + 'px';
3089         }
else {
3090             
return v;
3091         }
3092     }
3093
3094     
//wrap given node s in the div
3095     function wrapInDiv(ld, s, suffix) {
3096         
var sid = ld.id + "-" + suffix;
3097         
var div = d.createElement("div");
3098         div.id = sid;
3099         div.style.width = normalizeDimension(ld.width);
3100         
//this does not work well for different browsers
3101         
//if height is relative ...
3102         
//For firefox it becomes better if 100% is hardcode
3103         
// but then image is off in Chrome and it does not work in IE too ...
3104         div.style.height = normalizeDimension(ld.height);
3105         div.style.position =
"absolute";
3106         
//TODO: provide way to specify bgcolor
3107         
// Perhaps app.style.bgcolor, app.style.splash-image, ... ?
3108         
// What was the param name supported by regular applet?
3109         div.style.backgroundColor =
"white";
3110         
if (s != null) {
3111             div.appendChild(s);
3112         }
3113         
return div;
3114     }
3115
3116     
var pendingCallbacks = {};
3117
3118     function doInstallCallbacks(id, cb) {
3119         
if (cb == null) {
3120             cb = pendingCallbacks[id];
3121             
if (notNull(cb)) {
3122               pendingCallbacks[id] =
null;
3123             }
else {
3124                 
return;
3125             }
3126         }
3127         
var a = document.getElementById(id);
3128         
if (!notNull(a)) return;
3129
3130         
if (isDef(cb.onJavascriptReady)) {
3131             
var onReady = cb.onJavascriptReady;
3132             
if (a.status < 2) { //not READY yet
3133               a.onLoad = function() {
3134                   onReady(id);
3135                   a.onLoad =
null; //workaround bug in plugin for IE in JRE7
3136               }
3137             }
3138         }
3139
3140         
if (isDef(cb.onRuntimeError)) {
3141             
if (a.status < 3) { //not ERROR or READY yet
3142                a.onError = function() {
3143                   cb.onRuntimeError(id);
3144                   
//This used to be added as
3145                   
// "workaround bug in plugin for IE in JRE7"
3146                   
//I do not have recollection what the bug was
3147                   
// and can not reproduce it now
3148                   
//(perhaps multiple calls into callback?)
3149                   
//With FX 2.0 it cause restart of the applet in IE
3150                   
// for reason that is not completely clear
3151                   
//Disable it for now
3152                   
/* a.onError = null; */
3153               }
3154             }
else if (a.status == 3) { //already failed, call handler in place
3155                cb.onRuntimeError(id);
3156             }
3157         }
3158     }
3159
3160
3161     
//we can not install applet callbacks until applet is instantiated as
3162     
//hook entry points are not defined and we do not control when applet is
3163     
//instantiated as developer may not add it to the DOM tree for a while.
3164     
//
3165     
//Therefore what we do is we insert <script> element AFTER applet tag
3166     
//to initiate install after applet tag is parsed
3167     
//
3168     
//However, we can not
3169     
//
3170     function getSnippetToInstallCallbacks(id, cb) {
3171         
if (!notNull(cb) || !(isDef(cb.onDeployError) || isDef(cb.onJavascriptReady))) {
3172             
return null;
3173         }
3174
3175         
var s = d.createElement("script");
3176         pendingCallbacks[id] = cb;
3177         s.text =
"dtjava.installCallbacks('"+id+"')";
3178         
return s;
3179     }
3180
3181     function getErrorPaneSnippet(app) {
3182         
var paneDiv = wrapInDiv(app, null, "error");
3183         paneDiv.style.visibility =
"hidden";
3184         
return paneDiv;
3185     }
3186
3187     function doEmbed(ld, platform, callbacks) {
3188         
var app = normalizeApp(ld, false);
3189         
//required argument is missing
3190         
if (!(notNull(app) && notNull(app.url) &&
3191               notNull(app.width) && notNull(app.height) && notNull(app.placeholder))) {
3192             
//deployment error, not runtime => exception is ok
3193             
throw "Required attributes are missing! (url, width, height and placeholder are required)";
3194         }
3195
3196         app.id = prepareAppletID(app);
3197
3198         
//if placeholder is passed as id => find DOM node
3199         
if ((typeof app.placeholder == "string")) {
3200            
var p = d.getElementById(app.placeholder);
3201            
if (p == null) {
3202                
throw "Application placeholder [id="+app.placeholder+"] not found.";
3203            }
3204             app.placeholder = p;
3205         }
3206
3207         
//we may fail before we even try to add splash. E.g. because it is unsupported platform
3208         
//make sure we have error pane in place to show error
3209         app.placeholder.appendChild(getErrorPaneSnippet(app));
3210
3211         
//if we got array we need to copy over!
3212         platform =
new dtjava.Platform(platform);
3213
3214         
var cb = setupAppletCallbacks(platform, callbacks);
3215
3216         
//allow family match to match next family
3217         
//Once we get to java layer we will deal with it there
3218         
var v = doValidateRelaxed(platform);
3219         
var launchFunction = function() {
3220             
var appSnippet = getAppletSnippet(app, platform, cb);
3221             
var splashSnippet = (cb.onGetSplash == null) ? null : cb.onGetSplash(ld);
3222
3223             
//what we try to do:
3224             
// placeholder need to have relative positioning (then splash will pe position relative to it)
3225             
// if splash is present it needs to have position "absolute", then it will not occupy space
3226             
// and can be placed on top of applet
3227             app.placeholder.style.position =
"relative";
3228             
if (splashSnippet != null) {
3229                 
//position splash on top of applet area and hide applet temporarily
3230                 
var ss = wrapInDiv(app, splashSnippet, "splash");
3231                 showHideDiv(ss,
false);
3232                 showHideApplet(appSnippet,
true);
3233
3234                 wipe(app.placeholder);
3235                 app.placeholder.appendChild(getErrorPaneSnippet(app));
3236                 app.placeholder.appendChild(ss);
3237                 app.placeholder.appendChild(appSnippet);
3238             }
else {
3239                 wipe(app.placeholder);
3240                 app.placeholder.appendChild(getErrorPaneSnippet(app));
3241                 app.placeholder.appendChild(appSnippet);
3242             }
3243             
//Note: this is not needed as we use setTimeout for the same
3244             
//var cbSnippet = getSnippetToInstallCallbacks(app.id, cb);
3245             
//if (cbSnippet != null) {
3246             
// app.placeholder.appendChild(cbSnippet);
3247             
//}
3248             setTimeout(function() {doInstallCallbacks(app.id, cb)},
0);
3249         };
3250
3251         
//can not launch yet
3252         
if (v != null) {
3253             resolveAndLaunch(app, platform, v, cb, launchFunction);
3254         }
else {
3255             launchFunction();
3256         }
3257     }
3258
3259     function extractApp(e) {
3260         
if (notNull(e)) {
3261             
var w = e.width; //TODO: do we need to extract number? e.g. if it was 400px? or 100%?
3262             
var h = e.height;
3263             
var jnlp = "dummy"; //Can find it from list of parameters but it is not really needed in
3264                                 
//static deployment scenario
3265             
return new dtjava.App(jnlp, {
3266                 id: e.id,
3267                 width: w,
3268                 height: h,
3269                 placeholder: e.parentNode
3270             });
3271         }
else {
3272             
throw "Can not find applet with null id";
3273         }
3274     }
3275
3276     function processStaticObject(id, platform, callbacks) {
3277         
var a = d.getElementById(id); //TODO: use findAppletDiv??
3278         
var app = extractApp(a);
3279
3280         
var cb = setupAppletCallbacks(platform, callbacks);
3281         
//Ensure some platform is set
3282         platform =
new dtjava.Platform(platform);
3283
3284         
var launchFunc = function() {
3285             
//add error pane
3286             app.placeholder.insertBefore(getErrorPaneSnippet(app), a);
3287
3288             
if (cb.onGetSplash != null) {
3289                 
//TODO: show splash if it was not hidden yet!
3290                 
var splashSnippet = cb.onGetSplash(app);
3291                 
if (notNull(splashSnippet)) {
3292                     
var ss = wrapInDiv(app, splashSnippet, "splash");
3293                     
if (notNull(ss)) {
3294                         app.placeholder.style.position =
"relative";
3295                         app.placeholder.insertBefore(ss, a);
3296                         showHideApplet(a,
true);
3297                     }
3298                 }
3299             }
3300
3301             
//TODO: install applet callbacks if they are provided
3302             
//Note - in theory we need to check if callbacks are supported too
3303             
// but if detection was not possible then it is hard to do
3304             
//they always wotk for FX or jre 7+ but how validate this?
3305             
//otherwise attempt to set them will block js and then trigger exception ...
3306         }
3307
3308         
var v = doValidateRelaxed(platform);
3309         
if (v != null) {
3310             
//TODO: Problem
3311             
// if FX missing and static deployment
3312             
// then JRE will try to autoinstall itself - this will cause popup
3313             
// Then DT will detect problem and also initiate install too
3314             
// a) double install
3315             
// b) if popup is canceled then we still offer to install again but it will not help applet to launch
3316             
// c) popup is unconditional and really ugly ...
3317             
//But popup comes from JRE7 - can not fix it, on other hand 6 will go manual install route
3318
3319             resolveAndLaunch(app, platform, v, cb, launchFunc);
3320         }
else {
3321             launchFunc();
3322         }
3323     }
3324
3325     function doRegister(id, platform, cb) {
3326         
//we will record static object and process it once onload is done
3327         addOnDomReady(function() {
3328             processStaticObject(id, platform, cb);
3329         });
3330     }
3331
3332     
//perform basic (lightweight) initialization
3333     init();
3334
3335     
/**
3336      The Java Deployment Toolkit
is utility to deploy Java content in
3337      the browser
as applets or applications using right version of Java.
3338      If needed it can initiate upgrade of user
's system to install required
3339      components of Java platform.
3340      <p>
3341      Note that some of Deployment Toolkit methods may not be fully operational
if
3342      used before web page body
is loaded (because DT native plugins could not be instantiated).
3343      If you intend to use it before web page DOM tree
is ready then dtjava.js needs to be loaded inside the
3344      body element of the page and before use of other DT APIs.
3345
3346      @
class dtjava
3347      @
static */
3348     
return {
3349         
/**
3350          Version of Javascript part of Deployment Toolkit.
3351          Increasing date lexicographically.
3352
3353          @property version
3354          @type
string
3355          */

3356         version:
"20150817",
3357
3358         
/**
3359          Validate that platform requirements are met.
3360
3361          @param platform {Platform}
3362          (Optional)
set of platform requirements.
3363          <p>
3364
3365          Default settings are
3366          <ul>
3367          <li>platform.jvm :
"1.6+"
3368          <li>platform.javafx :
null
3369          <li>platform.plugin :
"*"
3370          </ul>
3371
3372          @
return {PlatformMismatchEvent}
3373          Returns
null if all requirements are met.
3374          Return PlatformMismatchEvent describing the problem otherwise.
3375          */

3376         validate: function(platform) {
3377             
return doValidate(platform, ua.noPluginWebBrowser);
3378         },
3379
3380         
/**
3381          Perform install of missing components based
on given
3382          platform requirements. By
default if automated install is
3383          not possible then manual install will be offered.
3384
3385          @method install
3386          @param platform {Platform}
3387          Description of platform requirements.
3388          @param callbacks {Callbacks}
3389          Optional
set of callbacks to customize install experience.
3390          @
return {boolean}
3391          Returns
true if install was initiated.
3392
3393          */

3394         install: function(platform, callbacks) {
3395             
return doInstall(null, platform, callbacks, null);
3396         },
3397
3398         
// (TODO: AI: what are limitations on "connect back to origin host?"
3399         
// can someone provide us fake JNLP url to get access to other host?
3400         
// Perhaps we should support this for relative URLs only?)
3401         
/**
3402          Launch application (not embedded
into browser) based on given
3403          application descriptor. If launch requirements are not met
3404          then autoinstall may be initiated
if requested and supported.
3405          By
default autoinstall is disabled.
3406
3407          @method launch
3408          @param ld {App |
string | array}
3409          Application launch descriptor. Could be defined
as one of following:
3410          <ul>
3411          <li>instance of App
object,
3412          <li>
string with URL of application JNLP file
3413          <li>or array (
where URL attribute is required)
3414          </ul>
3415          At least link to JNLP file must be provided (could be full URL or relative to
3416          document location).
3417          <p>
3418          Note that passing parameters through the Apps
object is not supported by this method.
3419          Any parameters specified will be ignored.
3420
3421          @param platform {Platform}
3422          Optional platform requirements (such
as JRE and JavaFX versions).
3423
3424          @param callbacks {Callbacks | array}
3425          Optional
set of callbacks. See Callbacks for details.
3426          */

3427             
//this will not use jvargs either but we do not necessary need to document it
3428         launch: function(ld, platform, callbacks) {
3429             
return doLaunch(ld, platform, callbacks);
3430         },
3431
3432         
/**
3433          Embeds application
into browser based on given application descriptor
3434          (required elements: url of JNLP file, width and height, id or reference to placeholder node).
3435          <p>
3436          If JRE or JavaFX installation
is required then default handler is to return "click to install" html snippet.
3437          To enable autoinstall custom onDeployError handler need to be used.
3438          <p>
3439          If applet can not be launched because platform requirements are not met
3440          (e.g. DT plugin
is not available or mandatory parameters are missing)
3441          
return value will be null.
3442          <p>
3443          Set applet identifier
in the launch descriptor if you want to name your
3444          applet
in the DOM tree (e.g. to use it from javascript later).
3445
3446          @method embed
3447          @param ld {App |
string | array}
3448          Application launch descriptor. Could be defined
as one of following:
3449          <ul>
3450          <li>instance of App
object,
3451          <li>array (
where attribute names are same as in App object)
3452          </ul>
3453          At least link to JNLP file, width and height must be provided.
3454          @param platform {Platform}
3455          Optional platform requirements (such
as JRE and JavaFX versions).
3456          @param cb {Callbacks | array}
3457          Optional
set of callbacks. See Callbacks for details.
3458          @
return {void}
3459          */

3460         embed: function(ld, platform, cb) {
3461             
return doEmbed(ld, platform, cb);
3462         },
3463
3464         
/**
3465          Registers statically deployed Java applet to customize loading experience
3466          
if Javascript is enabled.
3467          <p>
3468          Note that launch of statically deployed applet will be initiated
3469          before
this this function will get control. Hence platform
3470          requirements listed here will NOT be validated prior to launch
3471          and will be used
if applet launch can not be initiated otherwise.
3472
3473          @method register
3474          @param id
3475          Identifier of application.
3476          @param platform {Platform}
3477          Optional platform requirements (such
as JRE and JavaFX versions).
3478          @param cb {Callbacks | array}
3479          Optional
set of callbacks. See Callbacks for details.
3480          */

3481         register: function(id, platform, callbacks) {
3482             
return doRegister(id, platform, callbacks);
3483         },
3484
3485
3486         
/**
3487          * Hides html splash panel
for applet with given id.
3488          * If splash panel does not exist
this method has no effect.
3489          * For JavaFX applications
this method will be called automatically once application is ready.
3490          * For Swing/AWT applets application code need to call
into this method explicitly if they were deployed
3491          * with custom splash handler.
3492          *
3493          * @method hideSplash
3494          * @param id Identifier of applet whose splash panel need to be hidden
3495          */

3496         hideSplash: function(id) {
3497             
return doHideSplash(id);
3498         },
3499
3500         
/**
3501          Helper function: cross-browser onLoad support
3502          <p>
3503          This will call fn() once document
is loaded.
3504          If page
is already loaded when this method is
3505          called then fn()
is called immediately.
3506          <p>
3507          If strictMode
is true then fn() is called once page
3508          and all its assets are loaded (i.e.
when document
3509          ready state will be
'complete').
3510          Otherwise fn()
is called after DOM tree is fully created
3511          (but some assets may not yet be loaded).
3512          <p>
3513          It
is ok to call this function multiple times. It will append
3514          to existing chain of events (and
do not replace them).
3515
3516          @method addOnloadCallback
3517
3518          @param {function} fn
3519          (required) function to call
3520
3521          @param strictMode {boolean} Flag indicating whether page assets need to
3522          be loaded before launch (
default is false).
3523          */

3524         addOnloadCallback: function(fn, strictMode) {
3525             
//WORKAROUND for RT-21574
3526             
// avoid using onDomReady because it leads to deadlocks
3527             
if (strictMode || (ua.chrome && !ua.win)) {
3528                 addOnload(fn);
3529             }
else {
3530                 addOnDomReady(fn);
3531             }
3532         },
3533
3534         
/**
3535          * Add onJavascriptReady and onDeployError callbacks
3536          * to the existing Java applet or JavaFX application.
3537          * Application need to be alive
in the browser DOM tree for this to work
3538          *
3539          * @param id {
string} applet id
3540          * @param cb {array} Set of callbacks. If
null then pending callbacks are installed (if any for this applet).
3541          * @
private
3542          */

3543         installCallbacks: function(id, cb) {
3544             doInstallCallbacks(id, cb);
3545         },
3546
3547         
/** Platform requirements for application launch.
3548
3549          <p><br>
3550          The version pattern strings are of the form #[.#[.#[_#]]][+|*],
3551          which includes strings such
as "1.6", * "2.0*", and "1.6.0_18+".
3552          <p>
3553
3554          A star (*) means
"any version within this family" where family is defined
3555          
by prefix and a plus (+) means "any version greater or equal to the specified version".
3556          For example
"1.6.0*" matches 1.6.0_25 but not 1.7.0_01,
3557          whereas
"1.6.0+" or "1.*" match both.
3558          <p>
3559          If the version pattern does not include all four version components
3560          but does not end with a star or plus, it will be treated
as if it
3561          ended with a star.
"2.0" is exactly equivalent to "2.0*", and will
3562          match any version number beginning with
"2.0".
3563          <p>
3564          Null version
string is treated as "there is no requirement to have it installed".
3565          Validation will pass whether
this component is installed or not.
3566          <p>
3567          Both
"+" and "*" will match any installed version of component. However if component is not
3568          installed then validation will fail.
3569
3570          @
class Platform
3571          @
for dtjava
3572          @constructor
3573          @param r {array}
3574          Array describing platform requirements. Element names should match
3575          Platform properties.
3576          */

3577         Platform: function(r) {
3578             
//init with defaults
3579
3580             
/**
3581              JRE/JVM version.
3582              @property jvm
3583              @type version pattern
string
3584              @
default "1.6+"
3585              */

3586             
this.jvm = "1.6+";
3587             
/**
3588              Minimum JavaFX version.
3589              @property javafx
3590              @type version pattern
string
3591              @
default null
3592              */

3593             
this.javafx = null;
3594             
/**
3595              Java Plugin version.
3596              If
set to null then browser plugin support for embedded content is not validated.
3597              @property plugin
3598              @type version pattern
string
3599              @
default "*"
3600              */

3601             
this.plugin = "*";
3602             
/**
3603              List of requested JVM arguments.
3604              @property jvmargs
3605              @type
string
3606              @
default null
3607              */

3608             
this.jvmargs = null;
3609
3610             
//copy over
3611             
for (var v in r) {
3612                 
this[v] = r[v];
3613                 
//we expect jvmargs to come as array. if not - convert to array
3614                 
if (this["jvmargs"] != null && typeof this.jvmargs == "string") {
3615                     
this["jvmargs"] = this["jvmargs"].split(" ");
3616                 }
3617             }
3618
3619            
/**
3620              * @method toString
3621              * @
return {string}
3622              * Returns
string replesentation of platform spec. Useful for debugging.
3623              */

3624             
this.toString = function() {
3625                 
return "Platform [jvm=" + this.jvm + ", javafx=" + this.javafx
3626                 +
", plugin=" + this.plugin + ", jvmargs=" + this.jvmargs + "]";
3627             };
3628         },
3629
3630         
/**
3631          Application launch descriptor.
3632
3633          @
class App
3634          @
for dtjava
3635          @constructor
3636          @param url {
string}
3637          (Required) location of JNLP file. Could be full URL or
partial
3638          relative to document
base.
3639          @param details {array}
3640          (Optional)
set of values for other object properties.
3641          Name should match documented
object properties.
3642          */

3643         App: function(url, details) {
3644             
/**
3645              Location of application
's JNLP file. Can not be null or undefined.
3646              @property url
3647              @type
string
3648              */

3649             
this.url = url;
3650
3651             
//default behavior
3652             
this.scriptable = true;
3653             
this.sharedjvm = true;
3654
3655             
if (details != undefined && details != null) {
3656                 
/**
3657                  Identifier of
this App. Expected to be unique on this page.
3658                  If
null then it is autogenerated.
3659                  @property id
3660                  @type
string
3661                  */

3662                 
this.id = details.id;
3663                 
/**
3664                  Base64 encoded content of JNLP file.
3665                  @property jnlp_content
3666                  @type
string
3667                  */

3668                 
this.jnlp_content = details.jnlp_content;
3669                 
/**
3670                  Applet width. Could be absolute or relative (e.g.
50 or 50%)
3671                  @property width
3672                  @type
string
3673                  */

3674                 
this.width = details.width;
3675                 
/**
3676                  Applet height. Could be absolute or relative (e.g.
50 or 50%)
3677                  @property height
3678                  @type
int
3679                  */

3680                 
this.height = details.height;
3681
3682                 
/**
3683                  Set of named parameters to pass to application.
3684                  @property
params
3685                  @type array
3686                  */

3687                 
this.params = details.params;
3688
3689                 
/**
3690                  If
set to true then Javascript to Java bridge will be initialized.
3691                  Note that some platform requirements imply Javascript bridge
is initialized anyways.
3692                  If
set to false the Java to Javascript calls are still possible.
3693
3694                  //TODO: AI: will it affect applet callbacks?
3695
3696                  @property scriptable
3697                  @type boolean
3698                  @
default true
3699                  */

3700                 
this.scriptable = details.scriptable;
3701
3702                 
/**
3703                  True
if application does not need JVM instance to be dedicated to this application.
3704                  Some of platform requirements may imply exclusive use of JVM.
3705                  <p>
3706                  Note that even
if sharing is enabled java plugin may choose to run applets in different JVM
3707                  instances. There
is no way to force java plugin to reuse same JVM.
3708
3709                  @property sharedjvm
3710                  @type boolean
3711                  @
default true
3712                  */

3713                 
this.sharedjvm = details.sharedjvm;
3714
3715                 
/**
3716                  Reference to DOM node to embed application
into.
3717                  If not provided
by the user and application is embedded then will be allocated dynamically.
3718                  <p>
3719                  Note that element may be not inserted
into the DOM tree yet.
3720                  <p>
3721                  User may also provide identifier of the existing DOM node to be used
as placeholder.
3722                  @property placeholder
3723                  @type {DOM node | DOM node id}
3724                  @
default null
3725                  */

3726                 
this.placeholder = details.placeholder;
3727
3728                 
/**
3729                   Tookit used
by the application.
3730                   By
default it is "fx" (and null is treated as JavaFX too).
3731                   Swing applications embedding JavaFX components need to pass
"swing"
3732                 */

3733                 
this.toolkit = details.toolkit;
3734             }
3735
3736             
/**
3737              * Returns
string representation of this object.
3738              *
3739              * @
return {string}
3740              */

3741             
this.toString = function() {
3742                 
var pstr = "null";
3743                 
var first = true;
3744                 
if (notNull(this.params)) {
3745                     pstr =
"{";
3746                     
for (p in this.params) {
3747                         pstr += ((first) ?
"" : ", ") + p + " => " + this.params[p];
3748                         first =
false;
3749                     }
3750                     pstr +=
"}";
3751                 }
3752                 
return "dtjava.App: [url=" + this.url + ", id=" + this.id + ", dimensions=(" + this.width + "," + this.height + ")"
3753                     +
", toolkit=" + this.toolkit
3754                     +
", embedded_jnlp=" + (notNull(this.jnlp_content) ? (this.jnlp_content.length + " bytes") : "NO")
3755                     +
", params=" + pstr + "]";
3756             }
3757         },
3758
3759
3760         
/**
3761          Set of callbacks to be used to customize user experience.
3762
3763          @
class Callbacks
3764          @
for dtjava
3765          @constructor
3766          @param cb {list of callbacks}
3767          
set of callbacks to set
3768          */

3769         Callbacks: function(cb) {
3770             
/**
3771              Callback to be called to obtain content of the splash panel. Gets application
3772              launch descriptor
as an input. If null is returned then splash is disabled.
3773              Non-
null return value is expected to be html snippet to be added into splash overlay.
3774              Only applicable to embed().
3775              <p>
3776              Note that autohiding splash
is not supported by all platforms. Splash will be hidden by default
3777              
for JavaFX application but not for Swing/AWT applets. In later case if use of splash is desirable
3778              then app need to call dtjava.hideSplash() explicitly to initiate hiding splash.
3779
3780              @property onGetSplash
3781              @type function(app)
3782              @
default Default splash panel for JavaFX applications embedded into web page, null otherwise.
3783              */

3784             
this.onGetSplash = defaultGetSplashHandler;
3785
3786             
/**
3787              Called
if embedding or launching application need
3788              additional components to be installed. This callback
is
3789              responsible
for handling such situation, e.g. reporting
3790              need to install something to the user,
3791              initiating installation
using install() and
3792              hiding splash panel
for embedded apps (if needed).
3793              After installation
is complete callback implementation may
3794              retry attempt to launch application
using provided launch function.
3795              <p>
3796              This method
is NOT called if platform requirement could not be met
3797              (e.g.
if platfrom is not supported or if installation
3798              
is not possible).
3799              <p>Default handler provides
"click to install" solution for
3800              embedded application and attempt to perform installation without
3801              additional questions
for apps started using launch().
3802              <p>
3803              If handler
is null then it is treated as no op handler.
3804              <p>
3805              Parameters:
3806              <ul>
3807              <li> <b>app</b> - application launch descriptor.
3808                  For embedded applications app.placeholder will refer to
3809                  the root of the applet area
in the DOM tree (to be used for
3810                  visual feedback)
3811              <li> <b>platform</b> - application platform requirements
3812              <li> <b>cb</b> -
set of callbacks to be used during
3813                    installation process
3814              <li> <b>isAutoinstall</b> -
true if install can be launched
3815                  automatically
3816              <li> <b>needRestart</b> -
true if browser restart will be required
3817                  once installation
is complete
3818              <li> <b>launchFunction</b> - function to be executed to
3819                  retry launching the application once installation
is finished
3820              </ul>
3821
3822              @property onInstallNeeded
3823              @type function(app, platform, cb, isAutoinstall, needRelaunch, launchFunc)
3824              @
default Default implementation shows "click to install" banner
3825                
for embedded applications or initiates installation immediately
3826                
for applications launched from web page.
3827              */

3828             
this.onInstallNeeded = defaultInstallHandler;
3829
3830             
/**
3831              Called before installation of required component
is triggered.
3832              For manual install scenario it
is called before installation
3833              page
is opened.
3834              <p>
3835              This method can be used to provide visual feedback to the user
3836              during the installation. Placeholder
3837              points to the area that can be used
for visualization,
3838              
for embedded applications it will be applet area.
3839              If
null then callee need to find place for visualization on its own.
3840              <p>
3841              In
case of automatic launch of installation onInstallFinished will be called
3842              once installation
is complete (succesfully or not).
3843              <p>
3844              If handler
is null then it is treated as no-op handler.
3845
3846              Parameters:
3847              <ul>
3848              <li> <b>placeholder</b> - DOM element to insert visual feedback
into.
3849                   If
null then callee need to add visual feedback to the document on its own
3850                   (e.g. placeholder will be
null if installation is not happening in context of embedding application into
3851                   web page).
3852              <li> <b>component</b> - String
"Java", "JavaFX" or "Java bundle"
3853              <li> <b>isAutoInstall</b> -
true if installer will be launched
3854                   automatically
3855              <li> <b>restartNeeded</b> - boolean to specify whether browser restart will be required
3856              </ul>
3857
3858              @property onInstallStarted
3859              @type function(placeholder, component, isAuto, restartNeeded)
3860              @
default No-op
3861              */

3862             
this.onInstallStarted = defaultInstallStartedHandler;
3863
3864             
/**
3865              Called once installation of required component
3866              
is completed. This method will NOT be called if installation is
3867              performed
in manual mode.
3868
3869              Parameters:
3870              <ul>
3871              <li> <b>placeholder</b> - DOM element that was passed to
3872                  onInstallStarted to insert visual feedback
into.
3873              <li> <b>component</b> - String
"jre" or "javafx"
3874              <li> <b>status</b> - status code
is string categorizing the status of install.
3875              (
"success", "error:generic", "error:download" or "error:canceled")
3876              <li> <b>relaunchNeeded</b> - boolean to specify
3877              whether browser restart
is required to complete the installation
3878              </ul>
3879
3880              @property onInstallFinished
3881              @type function(placeholder, component, status, relaunchNeeded)
3882              @
default no op
3883              */

3884             
this.onInstallFinished = defaultInstallFinishedHandler;
3885
3886             
/**
3887              This function
is called if application can not be deployed because
3888              current platform does not match given platform requirements.
3889              It
is also called if request to install missing components can not be
3890              completed due to platform.
3891              <p>
3892              Problem can be fatal error or transient issue (e.g. relaunch needed). Further
3893              details can be extracted
from provided mismatchEvent. Here are some typical combinations:
3894
3895              <ul>
3896              <li><em>Current browser
is not supported by Java</em> - (r.isUnsupportedBrowser())
3897              <li><em>Browser need to be restarted before application can be launched</em> - (r.isRelaunchNeeded())
3898              <li>JRE specific codes
3899              <ul>
3900              <li><em>JRE
is not supported on this platform</em> - (r.jreStatus() == "unsupported")
3901              <li><em>JRE
is not detected and need to be installed</em> - (r.jreStatus() == "none")
3902              <li><em>Installed version of JRE does not match requirements</em> - (r.jreStatus() ==
"old")
3903              <li><em>Matching JRE
is detected but deprecated Java plugin is used and
3904                      it does not support JNLP applets</em> - (r.jreStatus() ==
"oldplugin")
3905              </ul>
3906              <li> JavaFX specific codes
3907              <ul>
3908              <li><em>JavaFX
is not supported on this platform</em> - (r.javafxStatus() == "unsupported")
3909              <li><em>JavaFX Runtime
is missing and need to be installed manually</em> - (r.javafxStatus() == "none")
3910              <li><em>Installed version of JavaFX Runtime does not match requirements</em> - (r.javafxStatus() ==
"old")
3911              <li><em>JavaFX Runtime
is installed but currently disabled</em> - (r.javafxStatus() == "disabled")
3912              </ul>
3913              </ul>
3914
3915              Default error handler handles both application launch errors and embedded content.
3916
3917              @property onDeployError
3918              @type function(app, mismatchEvent)
3919              */

3920             
this.onDeployError = defaultDeployErrorHandler;
3921
3922             
/**
3923              * Called to
get content to be shown in the applet area if Java plugin is not installed
3924              * and none of callbacks helped to resolve
this.
3925              *
3926              * @property onGetNoPluginMessage
3927              * @type function(app)
3928              * @
return DOM Element object representing content to be shown in the applet area if
3929              * java plugin
is not detected by browser.
3930              */

3931             
this.onGetNoPluginMessage = defaultGetNoPluginMessageHandler;
3932
3933             
/**
3934              Called once applet
is ready to accept Javascript calls.
3935              Only supported
for plugin version 10.0.0 or later
3936              @property onJavascriptReady
3937              @type function(id)
3938              @
default null
3939              */

3940             
this.onJavascriptReady = null;
3941
3942             
/**
3943              Called
if application failed to launch.
3944              Only supported
for plugin version 10.0.0 or later.
3945
3946              @property onRuntimeError
3947              @type function(id)
3948              @
default no op
3949              */

3950             
this.onRuntimeError = defaultRuntimeErrorHandler;
3951
3952             
//overwrite with provided parameters
3953             
for (c in cb) {
3954                 
this[c] = cb[c];
3955             }
3956         }
3957     };
3958 }();


Gõ tìm kiếm nhanh...