a simple Java-FX Application which Simulate the Approximation of Pi https://nextn.xyz
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3955 lines
151 KiB

  1. /*
  2. * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
  3. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  4. */
  5. /**
  6. The Java Deployment Toolkit is a utility to deploy Java content in
  7. the browser as applets or applications using the right version of Java.
  8. If needed it can initiate an upgrade of user's system to install required
  9. components of Java platform.
  10. <p>
  11. Note that some of the Deployment Toolkit methods may not be fully operational if
  12. used before web page body is loaded (because DT native plugins could not be instantiated).
  13. If you intend to use it before web page DOM tree is ready then dtjava.js
  14. needs to be loaded inside the body element of the page and before use of other DT APIs.
  15. @module java/deployment_toolkit
  16. */
  17. var dtjava = function() {
  18. function notNull(o) {
  19. return (o != undefined && o != null);
  20. }
  21. function isDef(fn) {
  22. return (fn != null && typeof fn != "undefined");
  23. }
  24. //return true if any of patterns from query list is found in the given string
  25. function containsAny(lst, str) {
  26. for (var q = 0; q < lst.length; q++) {
  27. if (str.indexOf(lst[q]) != -1) {
  28. return true;
  29. }
  30. }
  31. return false;
  32. }
  33. /* Location of static web content - images, javascript files. */
  34. var jscodebase = (function () {
  35. // <script> elements are added to the DOM and run synchronously,
  36. // the currently running script will also be the last element in the array
  37. var scripts = document.getElementsByTagName("script");
  38. var src = scripts[scripts.length - 1].getAttribute("src");
  39. return src ? src.substring(0, src.lastIndexOf('/') + 1) : "";
  40. })();
  41. //set to true to disable FX auto install (before release)
  42. var noFXAutoInstall = false;
  43. // page has no body yet, postpone plugin installation
  44. postponeNativePluginInstallation = false;
  45. // JRE version we start to have JRE and FX true co-bundle
  46. var minJRECobundleVersion = "1.7.0_06";
  47. //aliases
  48. var d = document;
  49. var w = window;
  50. var cbDone = false; //done with onload callbacks
  51. var domInternalCb = []; //list of internal callbacks
  52. var domCb = []; //list of callbacks
  53. var ua = null;
  54. // Add internal function to be called on DOM ready event.
  55. // These functions will be called before functions added by addOnDomReady().
  56. // Used to do internal initialization (installing native plug-in) to avoid
  57. // race condition with user requests.
  58. function addOnDomReadyInternal(fn) {
  59. if (cbDone) {
  60. fn();
  61. } else {
  62. domInternalCb[domInternalCb.length] = fn;
  63. }
  64. }
  65. // add function to be called on DOM ready event
  66. function addOnDomReady(fn) {
  67. if (cbDone) {
  68. fn();
  69. } else {
  70. domCb[domCb.length] = fn;
  71. }
  72. }
  73. //invoke pending onload callbacks
  74. function invokeCallbacks() {
  75. if (!cbDone) {
  76. //swfoject.js tests whether DOM is actually ready first
  77. // in order to not fire too early. Use same heuristic
  78. try {
  79. var t = d.getElementsByTagName("body")[0].appendChild(
  80. d.createElement("div"));
  81. t.parentNode.removeChild(t);
  82. } catch (e) {
  83. return;
  84. }
  85. cbDone = true;
  86. for (var i = 0; i < domInternalCb.length; i++) {
  87. domInternalCb[i]();
  88. }
  89. for (var i = 0; i < domCb.length; i++) {
  90. domCb[i]();
  91. }
  92. }
  93. }
  94. //cross browser onload support.
  95. //Derived from swfobject.js
  96. function addOnload(fn) {
  97. if (isDef(w.addEventListener)) {
  98. w.addEventListener("load", fn, false);
  99. } else if (isDef(d.addEventListener)) {
  100. d.addEventListener("load", fn, false);
  101. } else if (isDef(w.attachEvent)) {
  102. w.attachEvent("onload", fn);
  103. //TODO: swfobject also keeps references to the listeners to detach them on onload
  104. // to avoid memory leaks ...
  105. } else if (typeof w.onload == "function") {
  106. var fnOld = w.onload;
  107. w.onload = function() {
  108. fnOld();
  109. fn();
  110. };
  111. } else {
  112. w.onload = fn;
  113. }
  114. }
  115. function detectEnv() {
  116. var dom = isDef(d.getElementById) && isDef(d.getElementsByTagName) && isDef(d.createElement);
  117. var u = navigator.userAgent.toLowerCase(),
  118. p = navigator.platform.toLowerCase();
  119. //NB: may need to be refined as some user agent may contain strings related to other browsers
  120. // (e.g. Chrome has both Safari and mozilla, Safari also has mozilla
  121. var windows = p ? /win/.test(p) : /win/.test(u),
  122. mac = p ? /mac/.test(p) : /mac/.test(u),
  123. linux = p ? /linux/.test(p) : /linux/.test(u),
  124. chrome = /chrome/.test(u),
  125. // get webkit version or false if not webkit
  126. webkit = !chrome && /webkit/.test(u) ?
  127. parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false,
  128. opera = /opera/.test(u),
  129. cputype = null,
  130. osVersion = null;
  131. var ie = false;
  132. try {
  133. //Used to be using trick from
  134. // http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html
  135. //ie = !+"\v1",
  136. //but it does not work with IE9 in standards mode
  137. //Reverting to alternative - use execScript
  138. ie = isDef(window.execScript);
  139. // IE 11 does not support execScript any more and no exception is thrown, so lets use more naive test.
  140. // http://msdn.microsoft.com/en-us/library/ie/bg182625(v=vs.85).aspx
  141. if (!ie) { // We do not want to overwrite if ie was detected above.
  142. ie = (navigator.userAgent.match(/Trident/i) != null);
  143. }
  144. } catch (ee) {
  145. //if javafx app is in the iframe and content of main window is coming from other domain
  146. // then some browsers may restrict access to outer window properties,
  147. // e.g. FF can throw exception for top.execScript (see RT-17885)
  148. //We could revert to more naive test, e.g. test user agent for "MSIE " string
  149. // but so far IE does not seem to throw exception => if we get here it is not IE anyways
  150. ie = false;
  151. }
  152. var edge = false;
  153. var noActiveX = false;
  154. edge = (navigator.userAgent.match(/Edge/i) != null);
  155. // If IE and Windows 8 or Windows 8.1 then check for Metro mode
  156. if(ie && navigator.userAgent.match(/Windows NT 6\.[23]/i) != null) {
  157. try {
  158. // try to create a known ActiveX object
  159. new ActiveXObject("htmlfile");
  160. } catch(e) {
  161. // ActiveX is disabled or not supported.
  162. noActiveX = true;
  163. }
  164. }
  165. if(edge || noActiveX) {
  166. ie = false;
  167. }
  168. var noPluginWebBrowser = edge || chrome || noActiveX;
  169. //we are not required to detect everything and can leave values null as
  170. // long as we later treat them accordingly.
  171. //We use "cputype" to detect if given hardware is supported,
  172. // e.g. we do not support PPC or iPhone/iPad despite they are running Mac OS
  173. //We use "osVersion" to detect if Java/JavaFX can be installed on this OS
  174. // e.g. Oracle Java for Mac requires 10.7.3
  175. if (mac) {
  176. if ((p && /intel/.test(p)) || /intel/.test(u)) {
  177. cputype = "intel";
  178. }
  179. //looking for things like 10_7, 10_6_8, 10.4 in the user agent
  180. var t = u.match(/mac os x (10[0-9_\.]+)/);
  181. //normalize to "." separators
  182. osVersion = notNull(t) ? t[0].replace("mac os x ","").replace(/_/g, ".") : null;
  183. }
  184. // trim() is not supported by IE10 and before
  185. if(typeof String.prototype.trim !== 'function') {
  186. String.prototype.trim = function() {
  187. return this.replace(/^\s+|\s+$/g, '');
  188. }
  189. }
  190. // startsWith() is not supported by IE
  191. if(typeof String.prototype.startsWith !== 'function') {
  192. String.prototype.startsWith = function(searchString, position) {
  193. position = position || 0;
  194. return this.indexOf(searchString, position) === position;
  195. }
  196. }
  197. // Check mime types. Works with netscape family browsers and checks latest installed plugin only
  198. var mm = navigator.mimeTypes;
  199. var jre = null;
  200. var deploy = null;
  201. var fx = null;
  202. var override = false;
  203. if (typeof __dtjavaTestHook__ !== 'undefined' &&
  204. __dtjavaTestHook__ != null &&
  205. __dtjavaTestHook__.jre != null &&
  206. __dtjavaTestHook__.jfx != null &&
  207. __dtjavaTestHook__.deploy != null) {
  208. jre = __dtjavaTestHook__.jre;
  209. deploy = __dtjavaTestHook__.deploy;
  210. fx = __dtjavaTestHook__.jfx;
  211. override = true;
  212. }
  213. else {
  214. //Cache configuration from plugin mimetypes
  215. //It is only available for NPAPI browsers
  216. for (var t = 0; t < mm.length; t++) {
  217. // The jpi-version is the JRE version.
  218. var m = navigator.mimeTypes[t].type;
  219. if (m.indexOf("application/x-java-applet;version") != -1 && m.indexOf('=') != -1) {
  220. var v = m.substring(m.indexOf('=') + 1);
  221. // Use the existing version comparison mechanism to ensure that
  222. // the latest JRE is selected ( "versionA"<="VersionB" equals to
  223. // versionCheck("versionA+","versionB") returns "true")
  224. if(jre == null || versionCheck(jre + "+", v)){
  225. jre = v;
  226. }
  227. }
  228. //Supported for 7u6 or later
  229. if (m.indexOf("application/x-java-applet;deploy") != -1 && m.indexOf('=') != -1) {
  230. deploy = m.substring(m.indexOf('=') + 1);
  231. }
  232. //javafx version for cobundled javafx (7u6+)
  233. if (m.indexOf("application/x-java-applet;javafx") != -1 && m.indexOf('=') != -1) {
  234. fx = m.substring(m.indexOf('=') + 1);
  235. }
  236. }
  237. }
  238. return {haveDom:dom, wk:webkit, ie:ie, win:windows,
  239. linux:linux, mac:mac, op: opera, chrome:chrome, edge:edge,
  240. jre:jre, deploy:deploy, fx:fx, noPluginWebBrowser:noPluginWebBrowser,
  241. cputype: cputype, osVersion: osVersion, override: override};
  242. }
  243. function showMessageBox() {
  244. var message = 'Java Plug-in is not supported by this browser. <a href="https://java.com/dt-redirect">More info</a>';
  245. 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%; top:5;left:5;position:absolute; opacity:0.9; width:600px;';
  246. var messageStyle = "border: .85px; margin:-2.2em 0 0.55em 2.5em;";
  247. var messageBox = '<img src="https://java.com/js/alert_16.png"><div style="'+ messageStyle +'"><p>'+ message + '</p>';
  248. var divTag = document.createElement("div");
  249. divTag.id = "messagebox";
  250. divTag.setAttribute('style', mbStyle);
  251. divTag.innerHTML = messageBox;
  252. document.body.appendChild(divTag);
  253. }
  254. //partially derived from swfobject.js
  255. var initDone = false;
  256. function init() {
  257. if (typeof __dtjavaTestHook__ !== 'undefined') {
  258. jre = null;
  259. jfx = null;
  260. deploy = null;
  261. if ((__dtjavaTestHook__ != null) && (__dtjavaTestHook__.args != null)) {
  262. jre = __dtjavaTestHook__.args.jre;
  263. jfx = __dtjavaTestHook__.args.jfx;
  264. deploy = __dtjavaTestHook__.args.deploy;
  265. }
  266. if ((window.location.href.indexOf('http://localhost') == 0) ||
  267. (window.location.href.indexOf('file:///') == 0)) {
  268. __dtjavaTestHook__ = {
  269. detectEnv: detectEnv,
  270. Version: Version,
  271. checkFXSupport: checkFXSupport,
  272. versionCheck: versionCheck,
  273. versionCheckFX: versionCheckFX,
  274. jre: jre,
  275. jfx: jfx,
  276. deploy: deploy
  277. };
  278. }
  279. }
  280. if (initDone) return;
  281. ua = detectEnv();
  282. if (!ua.haveDom) {
  283. return;
  284. }
  285. //NB: dtjava.js can be added dynamically and init() can be called after
  286. // document onload event is fired
  287. if (( isDef(d.readyState) && d.readyState == "complete") ||
  288. (!isDef(d.readyState) &&
  289. (d.getElementsByTagName("body")[0] || d.body))) {
  290. invokeCallbacks();
  291. }
  292. if (!cbDone) {
  293. if (isDef(d.addEventListener)) {
  294. d.addEventListener("DOMContentLoaded",
  295. invokeCallbacks, false);
  296. }
  297. if (ua.ie && ua.win) {
  298. // http://msdn.microsoft.com/en-us/library/ie/ms536343(v=vs.85).aspx
  299. // attachEvent is not supported by IE 11.
  300. if (isDef(d.addEventListener)) {
  301. d.addEventListener("onreadystatechange", function() {
  302. if (d.readyState == "complete") {
  303. d.removeEventListener("onreadystatechange", arguments.callee, false);
  304. invokeCallbacks();
  305. }
  306. }, false);
  307. } else {
  308. d.attachEvent("onreadystatechange", function() {
  309. if (d.readyState == "complete") {
  310. d.detachEvent("onreadystatechange", arguments.callee);
  311. invokeCallbacks();
  312. }
  313. });
  314. }
  315. if (w == top) { // if not inside an iframe
  316. (function() {
  317. if (cbDone) {
  318. return;
  319. }
  320. //AI: what for??
  321. try {
  322. d.documentElement.doScroll("left");
  323. } catch(e) {
  324. setTimeout(arguments.callee, 0);
  325. return;
  326. }
  327. invokeCallbacks();
  328. })();
  329. }
  330. }
  331. if (ua.wk) {
  332. (function() {
  333. if (cbDone) {
  334. return;
  335. }
  336. if (!/loaded|complete/.test(d.readyState)) {
  337. setTimeout(arguments.callee, 0);
  338. return;
  339. }
  340. invokeCallbacks();
  341. })();
  342. }
  343. addOnload(invokeCallbacks);
  344. }
  345. //only try to install native plugin if we do not have DTLite
  346. //Practically this means we are running NPAPI browser on Windows
  347. //(Chrome or FF) and recent JRE (7u4+?)
  348. if (!haveDTLite()) {
  349. installNativePlugin();
  350. }
  351. }
  352. function getAbsoluteUrl(jnlp){
  353. var absoluteUrl;
  354. if(isAbsoluteUrl(jnlp)) {
  355. absoluteUrl = jnlp;
  356. } else {
  357. var location = window.location.href;
  358. var pos = location.lastIndexOf('/');
  359. var docbase = pos > -1 ? location.substring(0, pos + 1) : location + '/';
  360. absoluteUrl = docbase + jnlp;
  361. }
  362. return absoluteUrl;
  363. }
  364. function launchWithJnlpProtocol(jnlp) {
  365. document.location="jnlp:"+ getAbsoluteUrl(jnlp);
  366. }
  367. function isAbsoluteUrl(url){
  368. var protocols = ["http://", "https://", "file://"];
  369. for (var i=0; i < protocols.length; i++){
  370. if(url.toLowerCase().startsWith(protocols[i])){
  371. return true;;
  372. }
  373. }
  374. return false;
  375. }
  376. /**
  377. This class provides details on why current platform does not meet
  378. application platform requirements. Note that severe problems are
  379. reported immediately and therefore full check may be not performed and
  380. some (unrelated to fatal problem)
  381. methods may provide false positive answers.
  382. <p>
  383. If multiple components do not match then worst status is reported.
  384. Application need to repeat checks on each individual component
  385. if it want to find out all details.
  386. @class PlatformMismatchEvent
  387. @for dtjava
  388. */
  389. function PlatformMismatchEvent(a) {
  390. //expect to get all parameters needed
  391. for (var p in a) {
  392. this[p] = a[p];
  393. }
  394. /**
  395. * @method toString
  396. * @return {string}
  397. * Returns string replesentation of event. Useful for debugging.
  398. */
  399. this.toString = function() {
  400. return "MISMATCH [os=" + this.os + ", browser=" + this.browser
  401. + ", jre=" + this.jre + ", fx=" + this.fx
  402. + ", relaunch=" + this.relaunch + ", platform="
  403. + this.platform + "]";
  404. };
  405. /**
  406. @method isUnsupportedPlatform
  407. @return {boolean}
  408. Returns true if this platform (OS/hardware) is not supported in a way
  409. to satisfy all platfrom requirements.
  410. (E.g. page is viewed on iPhone or JavaFX 2.0 application on Solaris.)
  411. <p>
  412. Note that this does not include browser match data.
  413. If platform is unsupported then application can not be
  414. launched and user need to use another platform to view it.
  415. */
  416. this.isUnsupportedPlatform = function() {
  417. return this.os;
  418. };
  419. /**
  420. @method isUnsupportedBrowser
  421. @return {boolean}
  422. Returns true if error is because current browser is not supported.
  423. <p>
  424. If true is returned and isRelaunchNeeded() returns true too then
  425. there are known supported browsers browsers for this platform.
  426. (but they are not necessary installed on end user system)
  427. */
  428. this.isUnsupportedBrowser = function() {
  429. return this.browser;
  430. };
  431. /**
  432. @method jreStatus
  433. @return {string}
  434. Returns "ok" if error was not due to missing JRE.
  435. Otherwise return error code characterizing the problem:
  436. <ul>
  437. <li> none - no JRE were detected on the system
  438. <li> old - some version of JRE was detected but it does not match platform requirements
  439. <li> oldplugin - matching JRE found but it is configured to use deprecated Java plugin that
  440. does not support Java applets
  441. <ul>
  442. <p>
  443. canAutoInstall() and isRelaunchNeeded() can be used to
  444. get more details on how seamless user' install experience will be.
  445. */
  446. this.jreStatus = function() {
  447. return this.jre;
  448. };
  449. /**
  450. * @method jreInstallerURL
  451. * @param {string} locale (optional) Locale to be used for installation web page
  452. * @return {string}
  453. *
  454. * Return URL of page to visit to install required version of Java.
  455. * If matching java runtime is already installed or not officially supported
  456. * then return value is null.
  457. */
  458. this.jreInstallerURL = function(locale) {
  459. if (!this.os && (this.jre == "old" || this.jre == "none")) {
  460. return getJreUrl(locale);
  461. }
  462. return null;
  463. };
  464. /**
  465. @method javafxStatus
  466. @return {string}
  467. Returns "ok" if error was not due to missing JavaFX.
  468. Otherwise return error code characterizing the problem:
  469. <ul>
  470. <li> none - no JavaFX runtime is detected on the system
  471. <li> old - some version of JavaFX runtime iss detected but it does not match platform requirements
  472. <li> disabled - matching JavaFX is detected but it is disabled
  473. <li> unsupported - JavaFX is not supported on this platform
  474. <ul>
  475. <p>
  476. canAutoInstall() and isRelaunchNeeded() can be used to
  477. get more details on how seamless user' install experience will be.
  478. */
  479. this.javafxStatus = function() {
  480. return this.fx;
  481. };
  482. /**
  483. * @method javafxInstallerURL
  484. * @param {string} locale (optional) Locale to be used for installation web page
  485. * @return {string}
  486. *
  487. * Return URL of page to visit to install required version of JavaFX.
  488. * If matching JavaFX runtime is already installed or not officially supported
  489. * then return value is null.
  490. */
  491. this.javafxInstallerURL = function(locale) {
  492. if (!this.os && (this.fx == "old" || this.fx == "none")) {
  493. return getFxUrl(locale);
  494. }
  495. return null;
  496. };
  497. /**
  498. @method canAutoInstall
  499. @return {boolean}
  500. Returns true if installation of missing components can be
  501. triggered automatically. In particular, ture is returned
  502. if there are no missing components too.
  503. <p>
  504. If any of missing components need to be installed manually
  505. (i.e. click through additional web pages) then false is returned.
  506. */
  507. this.canAutoInstall = function() {
  508. return isAutoInstallEnabled(this.platform, this.jre, this.fx);
  509. };
  510. /**
  511. @method isRelaunchNeeded
  512. @return {boolean}
  513. Returns true if browser relaunch is needed before application can be loaded.
  514. This often is true in conjuction with need to perform installation.
  515. <p>
  516. Other typical case - use of unsupported browser when
  517. it is known that there are supported browser for this pltaform.
  518. Then both isUnsupportedBrowser() and isRelaunchNeeded() return true.
  519. */
  520. this.isRelaunchNeeded = function() {
  521. return this.relaunch;
  522. };
  523. }
  524. //returns version of instaled JavaFX runtime matching requested version
  525. //or null otherwise
  526. function getInstalledFXVersion(requestedVersion) {
  527. //NPAPI browser and JRE with cobundle
  528. if (ua.fx != null && versionCheckFX(requestedVersion, ua.fx)) {
  529. return ua.fx;
  530. }
  531. //try to use DT
  532. var p = getPlugin();
  533. if (notNull(p)) {
  534. try {
  535. return p.getInstalledFXVersion(requestedVersion);
  536. } catch(e) {}
  537. }
  538. return null;
  539. }
  540. //concatenate list with space as separator
  541. function listToString(lst) {
  542. if (lst != null) {
  543. return lst.join(" ");
  544. } else {
  545. return null;
  546. }
  547. }
  548. function addArgToList(lst, arg) {
  549. if (notNull(lst)) {
  550. lst.push(arg);
  551. return lst;
  552. } else {
  553. var res = [arg];
  554. return res;
  555. }
  556. }
  557. function doLaunch(ld, platform, cb) {
  558. var app = normalizeApp(ld, true);
  559. if(ua.noPluginWebBrowser){
  560. launchWithJnlpProtocol(app.url);
  561. return;
  562. }
  563. //required argument is missing
  564. if (!(notNull(app) && notNull(app.url))) {
  565. throw "Required attribute missing! (application url need to be specified)";
  566. }
  567. //if we got array we need to copy over!
  568. platform = new dtjava.Platform(platform);
  569. //normalize handlers
  570. cb = new dtjava.Callbacks(cb);
  571. var launchFunc = function() {
  572. //prepare jvm arguments
  573. var jvmArgs = notNull(platform.jvmargs) ? platform.jvmargs : null;
  574. if (notNull(platform.javafx)) {
  575. //if FX is needed we know it is available or
  576. // we will not get here
  577. var v = getInstalledFXVersion(platform.javafx);
  578. //add hint that we need FX toolkit to avoid relaunch
  579. // if JNLP is not embedded
  580. jvmArgs = addArgToList(jvmArgs, " -Djnlp.fx=" + v);
  581. //for swing applications embedding FX we do not want this property as it will
  582. // trigger FX toolkit and lead to app failure!
  583. //But for JavaFX application it saves us relaunch as otherwise we wil launch with AWT toolkit ...
  584. if (!notNull(ld.toolkit) || ld.toolkit == "fx") {
  585. jvmArgs = addArgToList(jvmArgs, " -Djnlp.tk=jfx");
  586. }
  587. }
  588. //if we on 7u6+ we can use DTLite plugin in the NPAPI browsers
  589. //Caveat: as of 7u6 it does not work with Chrome on Linux because Chrome expects
  590. // DTLite plugin to implement xembed (or claim to support xembed)
  591. if (haveDTLite() && !(ua.linux && ua.chrome)) {
  592. if (doLaunchUsingDTLite(app, jvmArgs, cb)) {
  593. return;
  594. }
  595. }
  596. //Did not launch yet? Try DT plugin (7u2+)
  597. var p = getPlugin();
  598. if (notNull(p)) {
  599. try {
  600. try {
  601. //check if new DT APIs are available
  602. if (versionCheck("10.6+", ua.deploy, false)) {
  603. // obj.launchApp({"url" : "http://somewhere/my.jnlp",
  604. // "jnlp_content" : "... BASE 64 ...",
  605. // "vmargs" : [ "-ea -Djnlp.foo=bar"
  606. // "appargs" : [ "first arg, second arg" ]
  607. // "params" : {"p1" : "aaa", "p2" : "bbb"}});
  608. var callArgs = {"url":app.url};
  609. if (notNull(jvmArgs)) {
  610. callArgs["vmargs"] = jvmArgs;
  611. }
  612. //Only use HTML parameters, they are supposed to overwrite values in the JNLP
  613. //In the future we want to pass arguments too but this needs also be exposed for
  614. // embedded deployment
  615. if (notNull(app.params)) {
  616. //copy over and ensure all values are strings
  617. // (native code will ignore them otherwise)
  618. var ptmp = {};
  619. for (var k in app.params) {
  620. ptmp[k] = String(app.params[k]);
  621. }
  622. callArgs["params"] = ptmp;
  623. }
  624. if (notNull(app.jnlp_content)) {
  625. callArgs["jnlp_content"] = app.jnlp_content;
  626. }
  627. var err = p.launchApp(callArgs);
  628. if (err == 0) { //0 - error
  629. if (isDef(cb.onRuntimeError)) {
  630. cb.onRuntimeError(app.id);
  631. }
  632. }
  633. } else { //revert to old DT APIs
  634. //older DT APIs expects vmargs as a single string
  635. if (!p.launchApp(app.url, app.jnlp_content, listToString(jvmArgs))) {
  636. if (isDef(cb.onRuntimeError)) {
  637. cb.onRuntimeError(app.id);
  638. }
  639. }
  640. }
  641. return;
  642. } catch (ee) { //temp support for older build of DT
  643. if (!p.launchApp(app.url, app.jnlp_content)) {
  644. if (isDef(cb.onRuntimeError)) {
  645. cb.onRuntimeError(app.id);
  646. }
  647. }
  648. return;
  649. }
  650. } catch (e) {
  651. //old DT
  652. }
  653. } //old Java (pre DTLite)? not Windows? or old DT
  654. //use old way to launch it using java plugin
  655. var o = getWebstartObject(app.url);
  656. if (notNull(d.body)) {
  657. d.body.appendChild(o);
  658. } else {
  659. //should never happen
  660. d.write(o.innerHTML);
  661. }
  662. }
  663. var r = doValidateRelaxed(platform);
  664. //can not launch, try to fix
  665. if (r != null) {
  666. resolveAndLaunch(app, platform, r, cb, launchFunc);
  667. } else {
  668. launchFunc();
  669. }
  670. }
  671. //process unhandled platform error - convert to code and call callback
  672. function reportPlatformError(app, r, cb) {
  673. if (isDef(cb.onDeployError)) {
  674. cb.onDeployError(app, r);
  675. }
  676. }
  677. function isDTInitialized(p) {
  678. //if plugin is blocked then p.version will be undefined
  679. return p != null && isDef(p.version);
  680. }
  681. //Wait until DT plugin is initialized and then run the code
  682. //Currently we only use it for embeded apps and Chrome on Windows
  683. function runUsingDT(label, f) {
  684. // Possible situations:
  685. // a) plugin is live and we can simply run code
  686. // - just run the code
  687. // b) plugin is in the DOM tree but it is not initialized yet (e.g. Chrome blocking)
  688. // and there is live timer (pendingCount > 0)
  689. // - there could be another request. We will APPEND to it
  690. // (this is different from dtlite as in this case we can not have multiple clicks)
  691. // - renew timer life counter (do not want new timer)
  692. // c) plugin is in the DOM tree and it is not fully initialized yet but timer is stopped
  693. // - overwrite old request
  694. // - restart timer
  695. //
  696. // Problem we are solving:
  697. // when plugin is ready to serve request? How do we schedule call to happen when plugin is initialized?
  698. // Caveat:
  699. // Chrome can popup dialog asking user to grant permissions to load the plugin.
  700. // There is no API to detect dialog is shown and when user grants or declines permissions
  701. //
  702. // Note:
  703. // If we set property on plugin object before it is unblocked then they seem to be lost
  704. // and are not propagated to the final object once it is instantiated.
  705. //
  706. // Workaround we use:
  707. // Once plugin is added we will be checking if it is initialized and once we detect it we will execute code.
  708. // We will stop checking after some time.
  709. var p = getPlugin();
  710. if (p == null) {
  711. return; //NO DT
  712. }
  713. if (isDTInitialized(p)) {
  714. f(p);
  715. } else {
  716. // see if we need new timer
  717. var waitAndUse = null;
  718. if (!isDef(dtjava.dtPendingCnt) || dtjava.dtPendingCnt == 0) {
  719. waitAndUse = function () {
  720. if (isDTInitialized(p)) {
  721. if (notNull(dtjava.dtPending)) {
  722. for (var i in dtjava.dtPending) {
  723. dtjava.dtPending[i]();
  724. }
  725. }
  726. return;
  727. }
  728. if (dtjava.dtPendingCnt > 0) {
  729. dtjava.dtPendingCnt--;
  730. setTimeout(waitAndUse, 500);
  731. }
  732. }
  733. }
  734. //add new task in queue
  735. if (!notNull(dtjava.dtPending) || dtjava.dtPendingCnt == 0) {
  736. dtjava.dtPending = {};
  737. }
  738. dtjava.dtPending[label] = f; //use map to ensure repitative actions are not queued (e.g. multiple click to launch webstart)
  739. //reset the timer counter
  740. dtjava.dtPendingCnt = 1000; //timer is gone after 500s
  741. //start timer if needed
  742. if (waitAndUse != null) waitAndUse();
  743. }
  744. }
  745. //returns same mismatch event if not resolved, null if resolved
  746. function resolveAndLaunch(app, platform, v, cb, launchFunction) {
  747. var p = getPlugin();
  748. if( p == null && ua.noPluginWebBrowser){
  749. var readyStateCheck = setInterval(function() {
  750. if(document.readyState == "complete"){
  751. clearInterval(readyStateCheck);
  752. showMessageBox();
  753. }
  754. }, 15);
  755. return;
  756. }
  757. //Special case: Chrome/Windows
  758. // (Note: IE may also block activeX control but then it will block attempts to use it too)
  759. if (ua.chrome && ua.win && p != null && !isDTInitialized(p)) {
  760. //this likely means DT plugin is blocked by Chrome
  761. //tell user to grant permissions and retry
  762. var actionLabel;
  763. if (notNull(app.placeholder)) {
  764. var onClickFunc = function() {w.open("https://www.java.com/en/download/faq/chrome.xml"); return false;};
  765. var msg1 = "Please give Java permission to run on this browser web page.";
  766. var msg2 = "Click for more information.";
  767. var altText = "";
  768. doShowMessageInTheArea(app, msg1, msg2, altText, "javafx-chrome.png", onClickFunc);
  769. actionLabel = app.id + "-embed";
  770. } else {
  771. v.jre = "blocked";
  772. reportPlatformError(app, v, cb);
  773. actionLabel = "launch"; //we only queue ONE webstart launch.
  774. //Do not want to try to queue different apps - bad UE
  775. // (once user enable multiple things can spawn)
  776. //Note: what if multiple webstart apps are set to launch on page load (suer do not need to click)?
  777. // Guess do not worry for now
  778. //Note: app.id may be null in case of webstart app.
  779. }
  780. //now we need to start waiter. Once DT is initialized we can proceeed
  781. var retryFunc = function() {
  782. var vnew = doValidateRelaxed(platform);
  783. if (vnew == null) { //no problems with env
  784. launchFunction();
  785. } else {
  786. resolveAndLaunch(app, platform, vnew, cb, launchFunction);
  787. }
  788. };
  789. runUsingDT(actionLabel, retryFunc);
  790. return;
  791. }
  792. if (!v.isUnsupportedPlatform() && !v.isUnsupportedBrowser()) { //otherwise fatal, at least until restart of browser
  793. if (isMissingComponent(v) && isDef(cb.onInstallNeeded)) {
  794. var resolveFunc= function() {
  795. //once install is over we need to revalidate
  796. var vnew = doValidateRelaxed(platform);
  797. if (vnew == null) { //if no problems found - can launch
  798. launchFunction();
  799. } else { //TODO: what happens if we installed everything but relaunch is needed??
  800. //We can not get here if component install was not offered for any or missing componens
  801. //(if auto install was possible, see doInstall() implementation)
  802. //Hence, it is safe to assume we failed to meet requirements
  803. reportPlatformError(app, vnew, cb);
  804. //TODO: may be should call itself again but
  805. // then it easy can become infinite loop
  806. //e.g. user installs but we fail to detect it because DT
  807. // is not FX aware and retry, etc.
  808. //TODO: think it through
  809. }
  810. };
  811. cb.onInstallNeeded(app, platform, cb,
  812. v.canAutoInstall(), v.isRelaunchNeeded(), resolveFunc);
  813. return;
  814. }
  815. }
  816. reportPlatformError(app, v, cb);
  817. }
  818. function haveDTLite() {
  819. // IE does not support DTLite
  820. if (ua.deploy != null && !ua.ie) {
  821. return versionCheck("10.6+", ua.deploy, false);
  822. }
  823. return false;
  824. }
  825. function isDTLiteInitialized(p) {
  826. //if plugin is blocked then p.version will be undefined
  827. return p != null && isDef(p.version);
  828. }
  829. function getDTLitePlugin() {
  830. return document.getElementById("dtlite");
  831. }
  832. function doInjectDTLite() {
  833. //do not want more than one plugin
  834. if (getDTLitePlugin() != null) return;
  835. var p = document.createElement('embed');
  836. p.width = '10px';
  837. p.height = '10px';
  838. p.id = "dtlite";
  839. p.type = "application/x-java-applet"; //means we get latest
  840. var div = document.createElement("div");
  841. div.style.position = "relative";
  842. div.style.left = "-10000px";
  843. div.appendChild(p);
  844. var e = document.getElementsByTagName("body");
  845. e[0].appendChild(div);
  846. }
  847. function runUsingDTLite(f) {
  848. // Possible situations:
  849. // a) first request, plugin is not in the DOM tree yet
  850. // - add plugin
  851. // - setup wait mechanism and run f() once plugin is ready
  852. // b) plugin is live and we can simply run code
  853. // - just run the code
  854. // c) plugin is in the DOM tree but it is not initialized yet (e.g. Chrome blocking)
  855. // and there is live timer (pendingCount > 0)
  856. // - there could be another request. We will override it (e.g. user clicked multiple times)
  857. // - renew timer life counter (do not want new timer)
  858. // d) plugin is in the DOM tree and it is not fully initialized yet but timer is stopped
  859. // - overwrite old request
  860. // - restart timer
  861. //
  862. // Problem:
  863. // when plugin is ready to serve request? How do we schedule call to happen when plugin is initialized?
  864. // Caveat:
  865. // Chrome can popup dialog asking user to grant permissions to load the plugin.
  866. // There is no API to detect dialog is shown and when user grants or declines permissions
  867. //
  868. // Note:
  869. // If we set property on plugin object before it is unblocked then they seem to be lost
  870. // and are not propagated to the final object once it is instantiated.
  871. //
  872. // Workaround we use:
  873. // Once plugin is added we will be checking if it is initialized and once we detect it we will execute code.
  874. // We will stop checking after some time.
  875. var p = getDTLitePlugin();
  876. if (p == null) {
  877. doInjectDTLite();
  878. p = getDTLitePlugin();
  879. }
  880. if (isDTLiteInitialized(p)) {
  881. f(p);
  882. } else {
  883. // see if we need new timer
  884. var waitAndUse = null;
  885. if (!isDef(dtjava.dtlitePendingCnt) || dtjava.dtlitePendingCnt == 0) {
  886. waitAndUse = function () {
  887. if (isDef(p.version)) {
  888. if (dtjava.pendingLaunch != null) {
  889. dtjava.pendingLaunch(p);
  890. }
  891. dtjava.pendingLaunch = null;
  892. return;
  893. }
  894. if (dtjava.dtlitePendingCnt > 0) {
  895. dtjava.dtlitePendingCnt--;
  896. setTimeout(waitAndUse, 500);
  897. }
  898. }
  899. }
  900. //add new task in queue
  901. dtjava.pendingLaunch = f;
  902. //reset the timer counter
  903. dtjava.dtlitePendingCnt = 1000; //timer is gone after 500s
  904. //start timer if needed
  905. if (waitAndUse != null) {
  906. waitAndUse();
  907. }
  908. }
  909. }
  910. function doLaunchUsingDTLite(app, jvmargs, cb) {
  911. var launchIt = function() {
  912. var pp = getDTLitePlugin();
  913. if (pp == null) {
  914. //should not be possible as we guard before enter this function
  915. if (isDef(cb.onRuntimeError)) {
  916. cb.onRuntimeError(app.id);
  917. }
  918. }
  919. //DTLite only support new invocation API
  920. // obj.launchApp({"url" : "http://somewhere/my.jnlp",
  921. // "jnlp_content" : "... BASE 64 ...",
  922. // "vmargs" : [ "-ea -Djnlp.foo=bar"
  923. // "appargs" : [ "first arg, second arg" ]
  924. // "params" : {"p1" : "aaa", "p2" : "bbb"}});
  925. var callArgs = {"url" : app.url};
  926. if (notNull(jvmargs)) {
  927. callArgs["vmargs"] = jvmargs;
  928. }
  929. //Only use HTML parameters, they are supposed to overwrite values in the JNLP
  930. //In the future we want to pass arguments too but this needs also be exposed for
  931. // embedded deployment
  932. if (notNull(app.params)) {
  933. //copy over and ensure all values are stings
  934. // (native code will ignore them otherwise)
  935. var ptmp = {};
  936. for (var k in app.params) {
  937. ptmp[k] = String(app.params[k]);
  938. }
  939. callArgs["params"] = ptmp;
  940. }
  941. if (notNull(app.jnlp_content)) {
  942. callArgs["jnlp_content"] = app.jnlp_content;
  943. }
  944. var err = pp.launchApp(callArgs);
  945. if (err == 0) { //0 - error
  946. if (isDef(cb.onRuntimeError)) {
  947. cb.onRuntimeError(app.id);
  948. }
  949. }
  950. };
  951. if (versionCheck("10.4+", ua.deploy, false)) { //only for NPAPI browsers
  952. runUsingDTLite(launchIt);
  953. return true;
  954. }
  955. return false;
  956. }
  957. function getWebstartObject(jnlp) {
  958. var wo = null;
  959. if (ua.ie) { //TODO: attempt to use object in FF 3.6 lead to hang. Revert to embed for now
  960. //TODO: Should Chrome use object?
  961. //object tag itself
  962. wo = d.createElement('object');
  963. wo.width = '1px'; //zero size reports invalid argument in IE!
  964. wo.height = '1px'; //TODO: make it less distruptive to page layout? hide div?
  965. var p = d.createElement('param');
  966. p.name = 'launchjnlp';
  967. p.value = jnlp;
  968. wo.appendChild(p);
  969. p = d.createElement('param');
  970. p.name = 'docbase';
  971. p.value = notNull(d.documentURI) ? d.documentURI : d.URL;
  972. wo.appendChild(p);
  973. if (!ua.ie) {
  974. //NB:do not need to use exact version in mime type as generic should be mapped to latest?
  975. wo.type = "application/x-java-applet;version=1.7";
  976. } else {
  977. wo.classid = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93";
  978. }
  979. } else { //TODO: else part should go away once we figure out what is going on with FF
  980. wo = d.createElement('embed');
  981. wo.width = '0px';
  982. wo.height = '0px';
  983. //NB: dot notation did not work for custom attributes??? revert to setAttribute
  984. wo.setAttribute('launchjnlp', jnlp);
  985. wo.setAttribute('docbase', (notNull(d.documentURI) ? d.documentURI : d.URL));
  986. //NB:do not need to use exact version in mime type as generic should be mapped to latest?
  987. wo.type = "application/x-java-applet;version=1.7";
  988. }
  989. var div = d.createElement("div");
  990. div.style.position = "relative";
  991. div.style.left = "-10000px";
  992. div.appendChild(wo);
  993. return div;
  994. }
  995. // Version class. The argument VersionString is a valid version string and
  996. // UpgradeFromOldJavaVersion is optional true/false.
  997. var Match = {
  998. Exact: {value: 0}, // exact version
  999. Family: {value: 1}, // Example: 1.7* only matches 1.7.X family
  1000. Above: {value: 2} // Example: 1.7+ matches 1.7 and above
  1001. };
  1002. var Token = {
  1003. Uninitialized: {value: -2},
  1004. Unknown: {value: -1},
  1005. Identifier: {value: 0},
  1006. Alpha: {value: 1},
  1007. Digits: {value: 2},
  1008. Plus: {value: 3},
  1009. Minus: {value: 4},
  1010. Underbar: {value: 5},
  1011. Star: {value: 6},
  1012. Dot: {value: 7},
  1013. End: {value: 8}
  1014. };
  1015. var Version = function(VersionString, UpgradeFromOldJavaVersion) {
  1016. if (typeof UpgradeFromOldJavaVersion === 'undefined') {
  1017. var UpgradeFromOldJavaVersion = true;
  1018. }
  1019. // Constants
  1020. var MAX_DIGITS = 4;
  1021. // Private
  1022. var FVersionString = null;
  1023. var FOld = false;
  1024. var FVersion = null;
  1025. var FBuild = null;
  1026. var FPre = null;
  1027. var FMatch = null;
  1028. var FMajor = null;
  1029. var FMinor = null;
  1030. var FSecurity = null;
  1031. var FPatch = null;
  1032. // Class constructor
  1033. if (!VersionString) {
  1034. return null;
  1035. }
  1036. else {
  1037. FVersionString = VersionString;
  1038. var v = parseAndSplitVersionString(VersionString, UpgradeFromOldJavaVersion)
  1039. FOld = v.old;
  1040. FVersion = v.version;
  1041. FBuild = v.build;
  1042. FMatch = v.match;
  1043. FPre = v.pre;
  1044. var parts = splitVersion(v.version);
  1045. FMajor = parts.major;
  1046. FMinor = parts.minor;
  1047. FSecurity = parts.security;
  1048. FPatch = parts.patch;
  1049. }
  1050. // Public
  1051. return {
  1052. VersionString: VersionString,
  1053. old: FOld,
  1054. major: FMajor,
  1055. minor: FMinor,
  1056. security: FSecurity,
  1057. patch: FPatch,
  1058. version: FVersion,
  1059. build: FBuild,
  1060. pre: FPre,
  1061. match: FMatch,
  1062. check: function(query) {
  1063. return check(query, this);
  1064. },
  1065. equals: function(query) {
  1066. return equals(query, this);
  1067. }
  1068. };
  1069. // Private
  1070. function splitVersion(version) {
  1071. var lmajor = null;
  1072. var lminor = null;
  1073. var lsecurity = null;
  1074. var lpatch = null;
  1075. if (version.length >= 1) {
  1076. lmajor = version[0];
  1077. }
  1078. if (version.length >= 2) {
  1079. lminor = version[1];
  1080. }
  1081. if (version.length >= 3) {
  1082. lsecurity = version[2];
  1083. }
  1084. if (version.length >= 4) {
  1085. lpatch = version[3];
  1086. }
  1087. return {
  1088. major: lmajor,
  1089. minor: lminor,
  1090. security: lsecurity,
  1091. patch: lpatch
  1092. };
  1093. }
  1094. function VersionStringTokenizer(versionString) {
  1095. // Convert the version string to lower case and strip all whitespace
  1096. // from the beginning and end of the string.
  1097. var FVersionString = versionString.toLowerCase().trim();
  1098. var FIndex;
  1099. var FCurrentToken = null;
  1100. var FStack = Array();
  1101. function isDigit(c) {
  1102. var result = false;
  1103. switch(c) {
  1104. case '0':
  1105. case '1':
  1106. case '2':
  1107. case '3':
  1108. case '4':
  1109. case '5':
  1110. case '6':
  1111. case '7':
  1112. case '8':
  1113. case '9':
  1114. result = true;
  1115. break;
  1116. }
  1117. return result;
  1118. }
  1119. function isLetter(c) {
  1120. //return c.match("^[a-zA-Z]");
  1121. var result = false;
  1122. var lowerBoundLower = "a".charCodeAt(0);
  1123. var upperBoundLower = "z".charCodeAt(0);
  1124. var bound = c.charCodeAt(0);
  1125. if (lowerBoundLower <= bound && bound <= upperBoundLower) {
  1126. result = true;
  1127. }
  1128. return result;
  1129. }
  1130. function start() {
  1131. FIndex = 0;
  1132. }
  1133. function currentToken() {
  1134. return FCurrentToken;
  1135. }
  1136. function pushToken(Token) {
  1137. if (FCurrentToken != null) {
  1138. FStack.unshift(FCurrentToken);
  1139. }
  1140. FCurrentToken = Token;
  1141. }
  1142. function nextToken() {
  1143. var tokenID = Token.Uninitialized;
  1144. var token = '';
  1145. if (FStack.length > 0) {
  1146. tokenID = FStack[0].tokenID;
  1147. token = FStack[0].token;
  1148. FStack.shift();
  1149. }
  1150. else {
  1151. if (FIndex >= FVersionString.length) {
  1152. tokenID = Token.End;
  1153. }
  1154. else {
  1155. while (FIndex < FVersionString.length) {
  1156. var c = FVersionString.charAt(FIndex);
  1157. if ((tokenID == Token.Uninitialized || tokenID == Token.Alpha) &&
  1158. isLetter(c) == true) {
  1159. tokenID = Token.Alpha;
  1160. FIndex++;
  1161. token += c;
  1162. }
  1163. else if ((tokenID == Token.Uninitialized || tokenID == Token.Digits) &&
  1164. isDigit(c) == true) {
  1165. if (parseInt(c) == 0 && parseInt(token) == 0) {
  1166. tokenID = Token.Unknown;
  1167. token += c;
  1168. FIndex++;
  1169. break;
  1170. }
  1171. else {
  1172. tokenID = Token.Digits;
  1173. token += c;
  1174. FIndex++;
  1175. }
  1176. }
  1177. else if ((tokenID == Token.Alpha || tokenID == Token.Identifier) &&
  1178. isDigit(c) == true &&
  1179. isLetter(c) == false) {
  1180. tokenID = Token.Identifier;
  1181. FIndex++;
  1182. token += c;
  1183. }
  1184. else if (tokenID == Token.Uninitialized) {
  1185. switch(c) {
  1186. case '-':
  1187. tokenID = Token.Minus;
  1188. FIndex++;
  1189. token = c;
  1190. break;
  1191. case '+':
  1192. tokenID = Token.Plus;
  1193. FIndex++;
  1194. token = c;
  1195. break;
  1196. case '*':
  1197. tokenID = Token.Star;
  1198. FIndex++;
  1199. token = c;
  1200. break;
  1201. case '.':
  1202. tokenID = Token.Dot;
  1203. FIndex++;
  1204. token = c;
  1205. break;
  1206. case '_':
  1207. tokenID = Token.Underbar;
  1208. FIndex++;
  1209. token = c;
  1210. break;
  1211. default:
  1212. tokenID = Token.Unknown;
  1213. FIndex++;
  1214. break;
  1215. }
  1216. break;
  1217. }
  1218. else {
  1219. break;
  1220. }
  1221. }
  1222. }
  1223. }
  1224. FCurrentToken = {
  1225. token: token,
  1226. tokenID: tokenID
  1227. }
  1228. return FCurrentToken;
  1229. }
  1230. return {
  1231. start: start,
  1232. nextToken: nextToken,
  1233. pushToken: pushToken,
  1234. currentToken: currentToken,
  1235. isDigit: isDigit,
  1236. isLetter: isLetter
  1237. }
  1238. }
  1239. function VersionStringParser() {
  1240. function readDigits(Tokenizer) {
  1241. var result = new Array();
  1242. var token = Tokenizer.currentToken();
  1243. if (token.tokenID == Token.Digits) {
  1244. result.push(parseInt(token.token));
  1245. token = Tokenizer.nextToken();
  1246. // Read up to 3 more digits.
  1247. for (var index = 0; index < (MAX_DIGITS - 1); index++) {
  1248. if (token.tokenID == Token.Dot) {
  1249. token = Tokenizer.nextToken();
  1250. if (token.tokenID == Token.Digits) {
  1251. result.push(parseInt(token.token));
  1252. token = Tokenizer.nextToken();
  1253. }
  1254. else if (token.tokenID == Token.Star ||
  1255. token.tokenID == Token.Plus) {
  1256. break;
  1257. }
  1258. else {
  1259. result = null;
  1260. break;
  1261. }
  1262. }
  1263. else if (token.tokenID == Token.Star ||
  1264. token.tokenID == Token.Plus ||
  1265. token.tokenID == Token.End ||
  1266. token.tokenID == Token.Minus ||
  1267. token.tokenID == Token.Underbar ||
  1268. token.tokenID == Token.Identifier ||
  1269. (token.tokenID == Token.Alpha && token.token == 'u')) {
  1270. break;
  1271. }
  1272. else {
  1273. result = null;
  1274. break;
  1275. }
  1276. }
  1277. }
  1278. return result;
  1279. }
  1280. function readMatch(Tokenizer, Old) {
  1281. var result = Match.Exact;
  1282. var token = Tokenizer.currentToken();
  1283. if (token.tokenID == Token.Dot) {
  1284. token = Tokenizer.nextToken();
  1285. if (token.tokenID == Token.Star) {
  1286. result = Match.Family;
  1287. Tokenizer.nextToken();
  1288. }
  1289. else if (token.tokenID == Token.Plus) {
  1290. result = Match.Above;
  1291. Tokenizer.nextToken();
  1292. }
  1293. }
  1294. else if (token.tokenID == Token.Star) {
  1295. result = Match.Family;
  1296. Tokenizer.nextToken();
  1297. }
  1298. else if (token.tokenID == Token.Plus) {
  1299. result = Match.Above;
  1300. Tokenizer.nextToken();
  1301. }
  1302. return result;
  1303. }
  1304. function readPre(Tokenizer) {
  1305. var result = null;
  1306. var token = Tokenizer.currentToken();
  1307. if (token.tokenID == Token.Minus) {
  1308. var savedToken = token;
  1309. var token = Tokenizer.nextToken();
  1310. if (token.tokenID == Token.Alpha) {
  1311. result = token.token;
  1312. Tokenizer.nextToken();
  1313. }
  1314. else {
  1315. Tokenizer.pushToken(savedToken);
  1316. }
  1317. }
  1318. return result;
  1319. }
  1320. function readBuild(Tokenizer, Old) {
  1321. var result = null;
  1322. var token = Tokenizer.currentToken();
  1323. if (token.tokenID == Token.Plus) {
  1324. // The new version spec has build number prepended with a "+":
  1325. // RegEx: +([1-9][0-9]*)
  1326. var savedToken = token;
  1327. var token = Tokenizer.nextToken();
  1328. if (token.tokenID == Token.Digits) {
  1329. result = parseInt(token.token);
  1330. Tokenizer.nextToken();
  1331. }
  1332. else {
  1333. Tokenizer.pushToken(savedToken);
  1334. }
  1335. }
  1336. else if (Old == true) {
  1337. // The old version spec has build number prepended with a "-b"
  1338. // RegEx: -b([1-9][0-9]*)
  1339. if (token.tokenID == Token.Minus || token.tokenID == Token.Underbar) {
  1340. var savedToken = token;
  1341. token = Tokenizer.nextToken();
  1342. if (token.tokenID == Token.Identifier && token.token[0] == 'b') {
  1343. var builderNumber = parseInt(token.token.substr(1));
  1344. if (builderNumber != null && isNaN(builderNumber) == false) {
  1345. Tokenizer.nextToken();
  1346. result = builderNumber;
  1347. }
  1348. }
  1349. else {
  1350. Tokenizer.pushToken(savedToken);
  1351. }
  1352. }
  1353. }
  1354. return result;
  1355. }
  1356. // isOldUpdate determines if the version string is in the old
  1357. // short format. For Example: 8u60
  1358. function isOldUpdate(version, token) {
  1359. var result = false;
  1360. if (version.length == 1 &&
  1361. parseInt(version[0]) <= 8 &&
  1362. token.tokenID == Token.Identifier &&
  1363. token.token.length > 0 &&
  1364. token.token.charAt(0) == "u") {
  1365. result = true;
  1366. }
  1367. return result;
  1368. }
  1369. // Only call this function if isOldUpdate() returns true.
  1370. function readOldUpdate(Tokenizer) {
  1371. var result = null;
  1372. var token = Tokenizer.currentToken();
  1373. if (token.tokenID == Token.Identifier) {
  1374. result = parseInt(token.token.substr(1));
  1375. Tokenizer.nextToken();
  1376. }
  1377. else if (token.tokenID == Token.Star) {
  1378. lmatch = Match.Family;
  1379. Tokenizer.nextToken();
  1380. }
  1381. else if (token.tokenID == Token.Plus) {
  1382. lmatch = Match.Above;
  1383. Tokenizer.nextToken();
  1384. }
  1385. return result;
  1386. }
  1387. function readOpt(Tokenizer) {
  1388. var result = null;
  1389. var token = Tokenizer.currentToken();
  1390. if (token.tokenID == Token.Alpha) {
  1391. result = token.token;
  1392. Tokenizer.nextToken();
  1393. }
  1394. return result;
  1395. }
  1396. function parse(Tokenizer) {
  1397. var result = null;
  1398. var success = false;
  1399. var lold = false;
  1400. var lversion = null;
  1401. var lbuild = null;
  1402. var lmatch = Match.Exact;
  1403. var lpre = false;
  1404. var lopt = null;
  1405. Tokenizer.start();
  1406. var token = Tokenizer.nextToken();
  1407. if (token.tokenID == Token.Digits) {
  1408. lversion = readDigits(Tokenizer);
  1409. if (lversion != null && lversion.length > 0) {
  1410. token = Tokenizer.currentToken();
  1411. if (lversion[0] == 1) {
  1412. if (lversion.length >= 2 && lversion[1] == 9) {
  1413. return null;
  1414. }
  1415. lold = true;
  1416. }
  1417. else if (token.token == "u") {
  1418. // Special case. For Example: 8u*
  1419. token = Tokenizer.nextToken();
  1420. }
  1421. if (isOldUpdate(lversion, token) == true) {
  1422. lold = true;
  1423. var value = readOldUpdate(Tokenizer);
  1424. if (value != null) {
  1425. token = Tokenizer.currentToken();
  1426. lversion.push(parseInt(value));
  1427. lold = true;
  1428. if (token.tokenID == Token.End) {
  1429. success = true;
  1430. }
  1431. else {
  1432. lmatch = readMatch(Tokenizer);
  1433. token = Tokenizer.currentToken();
  1434. if (token.tokenID == Token.End) {
  1435. success = true;
  1436. }
  1437. }
  1438. }
  1439. }
  1440. else {
  1441. token = Tokenizer.currentToken();
  1442. if (lold == true && token.tokenID == Token.Underbar) {
  1443. token = Tokenizer.nextToken();
  1444. if (token.tokenID == Token.Digits && lversion.length < MAX_DIGITS) {
  1445. lversion.push(parseInt(token.token));
  1446. Tokenizer.nextToken();
  1447. }
  1448. }
  1449. lpre = readPre(Tokenizer);
  1450. token = Tokenizer.currentToken();
  1451. lbuild = readBuild(Tokenizer, lold);
  1452. lopt = readOpt(Tokenizer);
  1453. lmatch = readMatch(Tokenizer, lold);
  1454. token = Tokenizer.currentToken();
  1455. if (token.tokenID == Token.End) {
  1456. success = true;
  1457. }
  1458. }
  1459. if (success == true) {
  1460. result = {
  1461. old: lold,
  1462. version: lversion,
  1463. build: lbuild,
  1464. match: lmatch,
  1465. pre: lpre,
  1466. opt: lopt
  1467. };
  1468. }
  1469. }
  1470. }
  1471. return result;
  1472. }
  1473. return {
  1474. parse: parse
  1475. }
  1476. }
  1477. function parseAndSplitVersionString(versionString, UpgradeFromOldJavaVersion) {
  1478. var lold = false;
  1479. var lversion = new Array;
  1480. var lbuild = null;
  1481. var lmatch = null;
  1482. var lpre = false;
  1483. var lopt = null;
  1484. // Corner case inputs.
  1485. if (versionString == null || versionString.length == 0) {
  1486. lversion = [0, 0, 0, 0];
  1487. }
  1488. else {
  1489. var tokenizer = VersionStringTokenizer(versionString);
  1490. var parser = VersionStringParser();
  1491. var result = parser.parse(tokenizer);
  1492. if (result != null) {
  1493. if (UpgradeFromOldJavaVersion == true &&
  1494. result.old == true) {
  1495. if (result.version.length > 0 &&
  1496. result.version[0] == 1) {
  1497. lversion = result.version.splice(1, result.version.length - 1);
  1498. }
  1499. else {
  1500. lversion = result.version;
  1501. }
  1502. lold = true;
  1503. }
  1504. else {
  1505. lversion = result.version;
  1506. }
  1507. lbuild = result.build;
  1508. lmatch = result.match;
  1509. lpre = result.pre;
  1510. }
  1511. }
  1512. return {
  1513. old: lold,
  1514. version: lversion,
  1515. build: lbuild,
  1516. match: lmatch,
  1517. pre: lpre,
  1518. opt: lopt
  1519. };
  1520. }
  1521. function sameVersion(query, version) {
  1522. var result = false;
  1523. var lquery = query;
  1524. if (lquery == null)
  1525. lquery = 0;
  1526. if (parseInt(lquery) == parseInt(version)) {
  1527. result = true;
  1528. }
  1529. return result;
  1530. }
  1531. // compareVersionExact comparison returns true only if query and version are
  1532. // exact matches.
  1533. function compareVersionExact(query, version) {
  1534. var result = false;
  1535. if ((query.major != null) &&
  1536. (version.major != null) &&
  1537. sameVersion(query.major, version.major) &&
  1538. sameVersion(query.minor, version.minor) &&
  1539. sameVersion(query.security, version.security) &&
  1540. sameVersion(query.patch, version.patch) &&
  1541. (query.old == version.old) &&
  1542. (query.pre == version.pre) &&
  1543. ((parseInt(query.build) == parseInt(version.build)) || (query.build == null && version.build == null))) {
  1544. result = true;
  1545. }
  1546. return result;
  1547. }
  1548. // compareVersionFamily comparison is for the * wild card for the current query
  1549. // version and anything above within the current version. For Example:
  1550. // 1.7* will match 1.7.8.9 but not 1.8.
  1551. function compareVersionFamily(query, version) {
  1552. var result = false;
  1553. // There is a subtle corner case comparison when comparing:
  1554. // 1.* to 1.8 (success)
  1555. // 1.* to 9.0 (fail)
  1556. // In this case, if both strings are old that means we have a 1s, so
  1557. // since the query string is all 0s, or empty, we have a match.
  1558. if (query.old == true && query.version.length == 0 && version.old == true) {
  1559. result = true;
  1560. }
  1561. else {
  1562. // All elements must match on the query version array.
  1563. for (index = 0 ;index < query.version.length && index < version.version.length;
  1564. index++) {
  1565. var q = query.version[index];
  1566. var v = version.version[index];
  1567. if (parseInt(q) == parseInt(v)) {
  1568. result = true;
  1569. }
  1570. else {
  1571. result = false;
  1572. break;
  1573. }
  1574. }
  1575. }
  1576. return result;
  1577. }
  1578. // compareVersionAbove comparison is for the + wild card for the current query
  1579. // version and anything above returning true.
  1580. function compareVersionAbove(query, version) {
  1581. var result = false;
  1582. if (query.old == true && query.version.length == 0) {
  1583. result = true;
  1584. }
  1585. else if (query.old == true && version.old == false) {
  1586. result = true;
  1587. }
  1588. else if (query.major == 0) {
  1589. result = true;
  1590. }
  1591. else if ((query.major != null) &&
  1592. (version.major != null) &&
  1593. ((parseInt(query.build) == parseInt(version.build)) || (query.build == null && version.build == null))) {
  1594. for (var index = 0; index < query.version.length; index++) {
  1595. var q = query.version[index];
  1596. var v = version.version[index];
  1597. if (parseInt(q) == parseInt(v)) {
  1598. result = true;
  1599. }
  1600. else if (parseInt(q) < parseInt(v)) {
  1601. if ((query.old == true && version.old == true) ||
  1602. (query.old == false && version.old == false)) {
  1603. result = true;
  1604. }
  1605. break;
  1606. }
  1607. else {
  1608. result = false;
  1609. break;
  1610. }
  1611. }
  1612. }
  1613. return result;
  1614. }
  1615. // cloneAndCompleteVersionInfo is an internal method. It makes a copy of the
  1616. // version structure and completes the version array to contain four elements.
  1617. function cloneAndCompleteVersionInfo(version) {
  1618. var clone_version = version.version.slice(0);
  1619. // The source version string must be a complete version string (four digits).
  1620. // Example: 9.0.0.0
  1621. for (var index = clone_version.length; index < 4 ; index++) {
  1622. clone_version.push(0);
  1623. }
  1624. var parts = splitVersion(clone_version);
  1625. return {
  1626. old: version.old,
  1627. major: parts.major,
  1628. minor: parts.minor,
  1629. security: parts.security,
  1630. patch: parts.patch,
  1631. version: clone_version,
  1632. build: version.build,
  1633. pre: version.pre
  1634. };
  1635. }
  1636. // Check performs a deploy pattern match comparison and returns
  1637. // true if the comparing version matches false if not.
  1638. function check(query, version) {
  1639. var result = false;
  1640. if (query.VersionString == null || query.VersionString.length == 0) {
  1641. result = true;
  1642. }
  1643. else {
  1644. if (query.build == null && version.build == null) {
  1645. var lversion = cloneAndCompleteVersionInfo(version);
  1646. if (query.match == Match.Exact) {
  1647. result = compareVersionExact(query, lversion);
  1648. }
  1649. else if (query.match == Match.Family) {
  1650. result = compareVersionFamily(query, lversion);
  1651. }
  1652. else if (query.match == Match.Above) {
  1653. result = compareVersionAbove(query, lversion);
  1654. }
  1655. }
  1656. }
  1657. return result;
  1658. }
  1659. // Performs a comparison on the two version string arguments and returns
  1660. // true if the comparing version matches false if not.
  1661. function equals(value, version) {
  1662. var result = false;
  1663. if (query.VersionString == null || query.VersionString.length == 0) {
  1664. result = true;
  1665. }
  1666. else {
  1667. var lversion = cloneAndCompleteVersionInfo(version);
  1668. var lquery = cloneAndCompleteVersionInfo(query);
  1669. result = compareVersionExact(lquery, lversion);
  1670. }
  1671. return result;
  1672. }
  1673. };
  1674. // Compares two version strings: query and version, matching query against version. query
  1675. // is allowed to have wild cards + and * version is not. The argument UpgradeFromOldJavaVersion
  1676. // is optional. This will remove the 1 prefix if present and mark the old field in the structure
  1677. // that is passed around.
  1678. function versionCheck(query, version, UpgradeFromOldJavaVersion) {
  1679. var q = new Version(query, UpgradeFromOldJavaVersion);
  1680. var v = new Version(version, UpgradeFromOldJavaVersion);
  1681. return v.check(q);
  1682. }
  1683. // This is similar to version check rules except there is a range
  1684. // over versions (3-7) that are not valid.
  1685. //
  1686. // JavaFX version requirements are always treated as "not earlier than this update".
  1687. // I.e. we expect
  1688. // 2.2.0 to match 2.2*, 2.2+, 2.1+, 2.1*, 2.0 and 1+
  1689. // but not match 2.2.1+, 2.2.1*, 2.3*, 2.3+ or 1*
  1690. function versionCheckFX(query, version) {
  1691. var q = new Version(query, false);
  1692. if (parseInt(q.major) >= 3 && parseInt(q.major) <= 7 && query.substr(-1) !== "+") {
  1693. return false;
  1694. }
  1695. if (q.match == Match.Exact) {
  1696. q = new Version(query + "+", false);
  1697. }
  1698. var v = new Version(version, false);
  1699. return v.check(q);
  1700. }
  1701. //as JavaFX comes with own plugin binaries then check based on mime types, etc.
  1702. // may be false positive as it only checks for plugin version, not real JRE
  1703. //Here we check that DT plugin is aware of JRE installations
  1704. //Note that:
  1705. // - if DT is not available we will return false but we only do this i
  1706. // ready to launch => DT must be found
  1707. // - we do not want to check in jreCheck() as we want to avoid loading
  1708. // DT plugin if we can (as old DT may make it not possible to autostart)
  1709. function doublecheckJrePresence() {
  1710. if (!haveDTLite()) { //basically IE on windows or Old JRE on windows
  1711. if (postponeNativePluginInstallation && notNull(d.body)) {
  1712. // Native Plugin installation was postponed, as the page didn't have
  1713. // body at that time. Try to install the plugin now.
  1714. installNativePlugin();
  1715. postponeNativePluginInstallation = false;
  1716. }
  1717. var p = getPlugin();
  1718. if (p != null) {
  1719. return true;
  1720. //WORKAROUND: bug in native DT!!! TODO: What version? bypass for it only
  1721. //return (p.jvms.getLength() > 0);
  1722. }
  1723. return false;
  1724. }
  1725. //if we are not using native DT plugin (i.e. using DTLite) then no way we can do sanity check
  1726. // => assume first check is accurate
  1727. return true;
  1728. }
  1729. function jreCheck(jre) {
  1730. // Check if latest JRE is exposed in mimetype and if it is good enough (only for NPAPI browsers)
  1731. if (ua.jre != null) {
  1732. if (versionCheck(jre, ua.jre)) {
  1733. return "ok";
  1734. }
  1735. //Note: if we have JRE but it is not match that means we may need an upgrade message
  1736. // but we still could be able to get more accurate answer with native DT plugin
  1737. }
  1738. //try to use DT plugin
  1739. var p = getPlugin();
  1740. if (p != null) {
  1741. var VMs = p.jvms;
  1742. for (var i = 0; VMs != null && i < VMs.getLength(); i++) {
  1743. if (versionCheck(jre, VMs.get(i).version)) {
  1744. if (!ua.ie && notNull(navigator.mimeTypes)) {
  1745. //if mime types are available but plugin is not there =>
  1746. // it is disabled
  1747. if (!notNull(navigator.mimeTypes["application/x-java-applet"])) {
  1748. return "disabled";
  1749. }
  1750. }
  1751. return "ok";
  1752. }
  1753. }
  1754. //do not need to try other ways if used DT
  1755. return "none";
  1756. }
  1757. //No full DT => On Windows we can not launch FX anyways
  1758. // but may have old JRE
  1759. //And we might be able to launch on Mac/Linux
  1760. //This is only IE on Windows. This gives no update version. only e.g. 1.6.0
  1761. //and also cause java plugin to be loaded => browser will need to be restarted
  1762. //if new JRE is installed.
  1763. //However, if we got here than DT is not available and autoinstall is not possible
  1764. if (ua.ie) {
  1765. var lst = ["1.8.0", "1.7.0", "1.6.0", "1.5.0"];
  1766. for (var v = 0; v < lst.length; v++) {
  1767. if (versionCheck(jre, lst[v])) {
  1768. try {
  1769. //TODO: FIXME: This does not seem to work in my testing in IE7?
  1770. var axo = new ActiveXObject("JavaWebStart.isInstalled." + lst[v] + ".0");
  1771. // This is not hit if the above throws an exception.
  1772. return "ok";
  1773. } catch (ignored) {
  1774. }
  1775. }
  1776. }
  1777. }
  1778. return "none";
  1779. }
  1780. function checkJRESupport() {
  1781. //Negative test. New platforms will not be rejected
  1782. var osProblem = ['iPhone', 'iPod'];
  1783. var os = containsAny(osProblem, navigator.userAgent);
  1784. //Do not support Chrome/Mac as Chrome is 32 bit only
  1785. var browser = (ua.mac && ua.chrome && ua.cputype == "intel");
  1786. //autoinstall possible if native plugin is detected or OS is fine
  1787. auto = os || (getPlugin() != null);
  1788. //false is no problem found
  1789. return {os: os, browser: browser, auto: auto};
  1790. }
  1791. //it is not clear if we can work in IE6
  1792. // but it is hard to test and JRE7 does not even support it
  1793. // mark as unsupported for now
  1794. function isUnsupportedVersionOfIE() {
  1795. if (ua.ie) {
  1796. try {
  1797. //these functions are defined in IE only
  1798. var v = 10*ScriptEngineMajorVersion() + ScriptEngineMinorVersion();
  1799. if (v < 57) return true; //IE7 will have 57
  1800. } catch (err) {
  1801. //really old IE?
  1802. return true;
  1803. }
  1804. }
  1805. return false;
  1806. }
  1807. function checkFXSupport() {
  1808. var browser;
  1809. if (ua.win) {
  1810. //do not support Opera and Safari
  1811. // (not really tested, may be it works but known to have problems with DT detection)
  1812. browser = ua.op || ua.wk || isUnsupportedVersionOfIE();
  1813. //false is no problem found
  1814. return {os: false, browser: browser};
  1815. } else if (ua.mac && ua.cputype == "intel") { //do not support PPC/iphone/ipad ...
  1816. var os = !versionCheck("10.7.3+", ua.osVersion, false); //10.7.3 or later!
  1817. browser = ua.op ||
  1818. (ua.mac && ua.chrome); //Opera is not supported
  1819. //Chrome on Mac is 32 bit => plugin only work in 64 bit ...
  1820. //TODO: How do we detect FF running in 32 bit mode?
  1821. //false is no problem found
  1822. return {os: os, browser: browser};
  1823. } else if (ua.linux) {
  1824. browser = ua.op; //Opera unsupported
  1825. //false is no problem found
  1826. return {os: false, browser: browser};
  1827. } else {
  1828. //unknown unsupported OS
  1829. return {os: true, browser: false};
  1830. }
  1831. }
  1832. function relaxVersion(v) {
  1833. if (notNull(v) && v.length > 0) {
  1834. var c = v.charAt(v.length - 1);
  1835. if (c == '*') {
  1836. v = v.substring(0, v.length - 1)+"+";
  1837. } else if (c != '+') { //exact version (e.g. 1.6)
  1838. v = v + "+";
  1839. }
  1840. }
  1841. return v;
  1842. }
  1843. //we relax validation rules where we try to embed or launch app
  1844. // in order to deal with requests for OLDER jres at the java level
  1845. //Basically we convert request for version in JRE family to request for any future JRE
  1846. //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
  1847. //
  1848. //Note we keep validation strict for install and validate-only scenarios.
  1849. // This allows to query accurate details from javascript
  1850. function doValidateRelaxed(platform) {
  1851. var p = new dtjava.Platform(platform);
  1852. p.jvm = relaxVersion(p.jvm);
  1853. //p.javafx = relaxVersion(p.javafx);
  1854. return doValidate(p);
  1855. }
  1856. function doValidate(platform, noPluginWebBrowser) {
  1857. //ensure some platform is set (we could get array too!)
  1858. platform = new dtjava.Platform(platform);
  1859. //problem markers
  1860. var fx = "ok", jre = "ok", restart = false, os = false, browser = false,
  1861. p, details;
  1862. //check JRE
  1863. if (notNull(platform.jvm) && jreCheck(platform.jvm) != "ok") { //matching JRE not found
  1864. var res = jreCheck("1+");
  1865. if (res == "ok") {
  1866. jre = "old";
  1867. } else {
  1868. jre = res; //"none" or "disabled"
  1869. }
  1870. details = checkJRESupport();
  1871. if (details.os) {
  1872. jre = "unsupported";
  1873. os = true;
  1874. } else if(noPluginWebBrowser) {
  1875. jre = "ok";
  1876. } else {
  1877. browser = details.browser;
  1878. }
  1879. }
  1880. //check FX
  1881. if (notNull(platform.javafx)) {
  1882. details = checkFXSupport();
  1883. if (details.os) { //FX is not supported,
  1884. //do not even try
  1885. fx = "unsupported";
  1886. os = os || details.os;
  1887. } else if(noPluginWebBrowser) {
  1888. fx = "ok";
  1889. } else if( details.browser) {
  1890. browser = browser || details.browser;
  1891. } else {
  1892. //on non windows platforms automated install is not possible
  1893. // (if it is needed on windows and possible we will set it to false later)
  1894. if (ua.fx != null) {
  1895. //found cobundled JavaFX on 7u6+ (and it is NPAPI-based browser)
  1896. if (versionCheckFX(platform.javafx, ua.fx)) {
  1897. fx = "ok";
  1898. } else if (versionCheckFX("2.0+", ua.fx)) {
  1899. fx = "old";
  1900. }
  1901. } else if (ua.win) { //could be 7u6(cobundle)/IE or JRE6/FX
  1902. try {
  1903. p = getPlugin();
  1904. //typeof did not work in IE
  1905. var v = p.getInstalledFXVersion(platform.javafx);
  1906. // 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
  1907. // we should not report that FX is old or does not exist. Instead we should continue with "8.0.5" and than either relaunch
  1908. // with the requested JRE or offer the user to launch the app using the latest JRE installed).
  1909. if (v == "" || v == null) {
  1910. v = p.getInstalledFXVersion(platform.javafx + '+');
  1911. }
  1912. //if found we should get version string, otherwise empty string or null. If found then fx=false!
  1913. if (v == "" || v == null) {
  1914. v = p.getInstalledFXVersion("2.0+"); //check for any FX version
  1915. if (v == null || v == "") {
  1916. fx = "none";
  1917. } else {
  1918. fx = "old";
  1919. }
  1920. }
  1921. } catch(err) {
  1922. //If we got here then environment is supported but
  1923. //this is non FX aware JRE => no FX and can only offer manual install
  1924. // (restart needed as toolkit is already loaded)
  1925. fx = "none";
  1926. }
  1927. } else if (ua.mac || ua.linux) {
  1928. fx = "none";
  1929. }
  1930. }
  1931. }
  1932. //recommend relaunch if OS is ok but browser is not supported
  1933. restart = restart || (!os && browser);
  1934. //TODO: need a way to find out if java plugin is loaded => will need to relaunch
  1935. //we need to return null if everything is ok. Check for problems.
  1936. if (fx != "ok" || jre != "ok" || restart || os || browser) {
  1937. return new PlatformMismatchEvent(
  1938. {fx: fx, jre: jre, relaunch: restart, os: os, browser: browser,
  1939. platform: platform});
  1940. } else {
  1941. //if all looks good check JRE again, it could be false positive
  1942. if (ua.override == false && !noPluginWebBrowser && !doublecheckJrePresence()) {
  1943. return new PlatformMismatchEvent(
  1944. {fx: fx, jre: "none", relaunch: restart, os: os,
  1945. browser: browser, platform: platform});
  1946. }
  1947. }
  1948. return null;
  1949. }
  1950. //TODO: does it make sense to have a way to explicitly request locale?
  1951. function guessLocale() {
  1952. var loc = null;
  1953. loc = navigator.userLanguage;
  1954. if (loc == null)
  1955. loc = navigator.systemLanguage;
  1956. if (loc == null)
  1957. loc = navigator.language;
  1958. if (loc != null) {
  1959. loc = loc.replace("-", "_")
  1960. }
  1961. return loc;
  1962. }
  1963. function getJreUrl(loc) {
  1964. if (!notNull(loc)) {
  1965. loc = guessLocale();
  1966. }
  1967. return 'https://java.com/dt-redirect?' +
  1968. ((notNull(window.location) && notNull(window.location.href)) ?
  1969. ('&returnPage=' + window.location.href) : '') +
  1970. (notNull(loc) ? ('&locale=' + loc) : '');
  1971. //NB: brand parameter is not supported for now
  1972. }
  1973. function getFxUrl(locale) {
  1974. return "http://www.oracle.com/technetwork/java/javafx/downloads/index.html";
  1975. }
  1976. //return true if mismatch event suggest to perform installation
  1977. function isMissingComponent(v) {
  1978. if (v != null) {
  1979. var jre = v.jreStatus();
  1980. var fx = v.javafxStatus();
  1981. //if anything is disabled then this need to be resolved before any further installs
  1982. return (jre == "none" || fx == "none" || jre == "old" || fx == "old")
  1983. && (fx != "disabled" && jre != "disabled");
  1984. }
  1985. return false;
  1986. }
  1987. function showClickToInstall(ld, isJRE, isUpgrade, isAutoinstall, isRelaunchNeeded, actionFunc) {
  1988. //what product?
  1989. var productName, productLabel;
  1990. if (isJRE) {
  1991. productName = "Java";
  1992. productLabel = "java";
  1993. } else {
  1994. productName = "JavaFX";
  1995. productLabel = "javafx";
  1996. }
  1997. var msg1, msg2, imgName;
  1998. if (isUpgrade) {
  1999. msg1 = "A newer version of " + productName + "is required to view the content on this page.";
  2000. msg2 = "Please click here to update " + productName;
  2001. imgName = "upgrade_"+productLabel+".png";
  2002. } else {
  2003. msg1 = "View the content on this page.";
  2004. msg2 = "Please click here to install " + productName;
  2005. imgName = "get_"+productLabel+".png";
  2006. }
  2007. var altText = "Click to install "+productName;
  2008. doShowMessageInTheArea(ld, msg1, msg2, altText, imgName, actionFunc);
  2009. }
  2010. function doShowMessageInTheArea(ld, msg1, msg2, altText, imgName, actionFunc) {
  2011. //if image will fit (size 238x155)
  2012. var r = d.createElement("div");
  2013. r.width = normalizeDimension(ld.width);
  2014. r.height = normalizeDimension(ld.height);
  2015. var lnk = d.createElement("a");
  2016. lnk.href="";
  2017. lnk.onclick = function() {actionFunc(); return false;};
  2018. if (ld.width < 250 || ld.height < 160) { //if relative size this will fail =>
  2019. // will choose image
  2020. r.appendChild(
  2021. d.createElement("p").appendChild(
  2022. d.createTextNode(msg1)));
  2023. lnk.appendChild(d.createTextNode(msg2));
  2024. r.appendChild(lnk);
  2025. } else {
  2026. var img = d.createElement("img");
  2027. img.src = jscodebase + imgName;
  2028. img.alt = altText;
  2029. img.style.borderWidth="0px";
  2030. img.style.borderStyle="none";
  2031. //FIXME: centering image does not work (in a way it also work with relative dimensions ...)
  2032. // lnk.style.top="50%";
  2033. // lnk.style.left="50%";
  2034. // lnk.style.marginTop = -119; // 238/2
  2035. // lnk.style.marginLeft = -77; //155/2
  2036. lnk.appendChild(img);
  2037. r.appendChild(lnk);
  2038. }
  2039. wipe(ld.placeholder);
  2040. ld.placeholder.appendChild(r);
  2041. }
  2042. function canJavaFXCoBundleSatisfy(platform) {
  2043. // check if latest co-bundle can satisfy
  2044. if (versionCheck(platform.jvm, minJRECobundleVersion, false) &&
  2045. versionCheckFX(platform.javafx, "2.2.0")) {
  2046. return true;
  2047. }
  2048. return false;
  2049. }
  2050. function defaultInstallHandler(app, platform, cb,
  2051. isAutoinstall, needRelaunch, launchFunc) {
  2052. var installFunc = function() {
  2053. doInstall(app, platform, cb, launchFunc);
  2054. };
  2055. var s = doValidate(platform);
  2056. if (!notNull(s)) { //platform match => nothing to install
  2057. if (notNull(launchFunc)) {
  2058. launchFunc();
  2059. }
  2060. }
  2061. var isUpgrade = notNull(s) && (s.javafxStatus() == "old" || s.jreStatus() == "old");
  2062. if (notNull(app.placeholder)) { //embedded
  2063. if (canJavaFXCoBundleSatisfy(platform)) { //if both JRE and FX are missing we will start install from JRE
  2064. //it is only JRE that needs to be updated
  2065. showClickToInstall(app, true, isUpgrade, isAutoinstall, needRelaunch, installFunc);
  2066. } else {
  2067. showClickToInstall(app, (s.jreStatus() != "ok"), isUpgrade, isAutoinstall, needRelaunch, installFunc);
  2068. }
  2069. } else { //webstart
  2070. var r = isAutoinstall;
  2071. var msg = null;
  2072. if (!r) {
  2073. if (canJavaFXCoBundleSatisfy(platform)) { //if both JRE and FX are missing we will start install from JRE
  2074. //it is only JRE that needs to be updated
  2075. if (isUpgrade) {
  2076. msg = "A newer version of Java is required to view the content on this page. Please click here to update Java.";
  2077. } else {
  2078. msg = "To view the content on this page, please click here to install Java.";
  2079. }
  2080. r = confirm(msg);
  2081. } else {
  2082. if (isUpgrade) {
  2083. msg = "A newer version of JavaFX is required to view the content on this page. Please click here to update JavaFX.";
  2084. } else {
  2085. msg = "To view the content on this page, please click here to install JavaFX.";
  2086. }
  2087. r = confirm(msg);
  2088. }
  2089. }
  2090. if (r)
  2091. installFunc();
  2092. }
  2093. }
  2094. /**
  2095. * returns true if we can enable DT plugin auto-install without chance of
  2096. * deadlock on cert mismatch dialog
  2097. *
  2098. * requestedJREVersion param is optional - if null, it will be
  2099. * treated as installing any JRE version
  2100. *
  2101. * DT plugin for 6uX only knows about JRE installer signed by SUN cert.
  2102. * If it encounter Oracle signed JRE installer, it will have chance of
  2103. * deadlock when running with IE. This function is to guard against this.
  2104. */
  2105. function enableWithoutCertMisMatchWorkaround(requestedJREVersion) {
  2106. // Non-IE browser are okay
  2107. if (!ua.ie) return true;
  2108. // if DT plugin is 10.0.0 or above, return true
  2109. // This is because they are aware of both SUN and Oracle signature and
  2110. // will not show cert mismatch dialog that might cause deadlock
  2111. if (versionCheck("10.0.0+", getPlugin().version, false)) {
  2112. return true;
  2113. }
  2114. // If we got there, DT plugin is 6uX
  2115. if (requestedJREVersion == null) {
  2116. // if requestedJREVersion is not defined - it means ANY.
  2117. // can not guarantee it is safe to install ANY version because 6uX
  2118. // DT does not know about Oracle certificates and may deadlock
  2119. return false;
  2120. }
  2121. // 6u32 or earlier JRE installer used Sun certificate
  2122. // 6u33+ uses Oracle's certificate
  2123. // DT in JRE6 does not know about Oracle certificate => can only
  2124. // install 6u32 or earlier without risk of deadlock
  2125. return !versionCheck("1.6.0_33+", requestedJREVersion);
  2126. }
  2127. // return true if we can auto-install to satisfy the platform requirement
  2128. // return false otherwise
  2129. //
  2130. // We can auto-install if all below is true:
  2131. // - windows platform
  2132. // - native DT plugin available
  2133. // - if JRE install is required, JRE exe is signed by compatible
  2134. // certificate
  2135. // - if FX install is required, JRE co-bundle can satisfy the
  2136. // requirement or DT plugin supports FX auto-install
  2137. function isAutoInstallEnabled(platform, jre, fx) {
  2138. // auto-install is windows only
  2139. if (!ua.win) return false;
  2140. // if no DT plugin, return false
  2141. // if DT plugin is there but not operational (e.g. blocked)
  2142. // then pretend there is no autoinstall
  2143. var p = getPlugin();
  2144. if (p == null || !isDef(p.version)) return false;
  2145. if (jre != "ok") {
  2146. // need JRE install
  2147. if (!enableWithoutCertMisMatchWorkaround(platform.jvm)) {
  2148. return false;
  2149. }
  2150. }
  2151. if (fx != "ok") {
  2152. if (!canJavaFXCoBundleSatisfy(platform)) {
  2153. // no cobundle, check if there is standalone FX auto-install
  2154. // DT from Java 7 or later should be ok
  2155. if (!versionCheck("10.0.0+", getPlugin().version, false)) {
  2156. return false;
  2157. }
  2158. } else {
  2159. // we are going to install co-bundle JRE - check if we can do
  2160. // that
  2161. if (!enableWithoutCertMisMatchWorkaround(minJRECobundleVersion)) {
  2162. return false;
  2163. }
  2164. }
  2165. }
  2166. return true;
  2167. }
  2168. function doInstall(app, platform, cb, postInstallFunc) {
  2169. var s = doValidate(platform);
  2170. cb = new dtjava.Callbacks(cb);
  2171. if (notNull(s) && s.isUnsupportedPlatform()) {
  2172. reportPlatformError(app, s, cb);
  2173. return false; //no install
  2174. }
  2175. var placeholder = (app != null) ? app.placeholder : null;
  2176. var codes, status;
  2177. if (isMissingComponent(s)) { //otherwise nothing to install
  2178. if (s.jre != "ok") {
  2179. if (isDef(cb.onInstallStarted)) {
  2180. cb.onInstallStarted(placeholder, "Java",
  2181. false, getPlugin() != null);
  2182. }
  2183. startManualJREInstall();
  2184. } else { //what it could be??
  2185. reportPlatformError(app, s, cb);
  2186. }
  2187. } else {
  2188. //nothing to install
  2189. if (postInstallFunc != null) {
  2190. postInstallFunc();
  2191. }
  2192. return true;
  2193. }
  2194. //no install initiated
  2195. return false;
  2196. }
  2197. //just open download URL in new window
  2198. function startManualJREInstall() {
  2199. w.open(getJreUrl());
  2200. }
  2201. //just open download URL in new window
  2202. function startManualFXInstall() {
  2203. w.open(javafxURL);
  2204. }
  2205. function defaultGetSplashHandler(ld) {
  2206. if (ld.placeholder != null) {
  2207. var _w = ld.width, _h = ld.height;
  2208. //prepare image
  2209. //if width and height are relative then comparison with int will be false
  2210. // and we will end up using large image. This is on purpose
  2211. // as it is unlikely that relative dimensions are used for tiny applet areas
  2212. var isBig = !(_w < 100 && _h < 100);
  2213. var iU = isBig ? 'javafx-loading-100x100.gif' : 'javafx-loading-25x25.gif';
  2214. var iW = isBig ? 80 : 25;
  2215. var iH = isBig ? 80 : 25;
  2216. var img = d.createElement("img");
  2217. img.src = jscodebase + iU;
  2218. img.alt = "";
  2219. //position in the center of the container
  2220. img.style.position = "relative";
  2221. img.style.top = "50%";
  2222. img.style.left = "50%";
  2223. img.style.marginTop = normalizeDimension(-iH/2);
  2224. img.style.marginLeft = normalizeDimension(-iW/2);
  2225. return img;
  2226. } else {
  2227. //webstart or install case
  2228. //TODO: show some html splash for webstart? how to hide it?
  2229. return null;
  2230. }
  2231. }
  2232. function defaultGetNoPluginMessageHandler(app) {
  2233. if (app.placeholder != null) {
  2234. var p = d.createElement("p");
  2235. p.appendChild(d.createTextNode("FIXME - add real message!"));
  2236. return p;
  2237. } //no op if not embedded content
  2238. return null;
  2239. }
  2240. //remove all child elements for given node
  2241. function wipe(c) {
  2242. while(c.hasChildNodes()) c.removeChild(c.firstChild);
  2243. }
  2244. function defaultInstallStartedHandler(placeholder, component, isAuto, restartNeeded) {
  2245. if (placeholder != null) {
  2246. var code = null;
  2247. if (isAuto) {
  2248. code = (component == "JavaFX") ?
  2249. "install:inprogress:javafx": "install:inprogress:jre";
  2250. } else {
  2251. code = (component == "JavaFX") ?
  2252. "install:inprogress:javafx:manual" : "install:inprogress:jre:manual";
  2253. }
  2254. appletInfoMsg(code);
  2255. }
  2256. }
  2257. function defaultInstallFinishedHandler(placeholder, component, status, relaunch) {
  2258. var t;
  2259. if (status != "success") {
  2260. var msg = null;
  2261. if (component == "javafx") {
  2262. if (!doublecheckJrePresence()) { //guess if we failed due to no JRE
  2263. //need to request to install JRE first
  2264. msg = "install:fx:error:nojre";
  2265. } else {
  2266. msg = "install:fx:"+status;
  2267. }
  2268. } else { //must be JRE error
  2269. msg = "install:jre:"+status;
  2270. }
  2271. if (placeholder != null) {
  2272. t = appletErrorMsg(msg, null);
  2273. //Instead of hiding splash and applet we simply clear the container
  2274. //We are not going to show neither splash nor applet anyways ...
  2275. wipe(placeholder);
  2276. placeholder.appendChild(t);
  2277. } else {
  2278. w.alert(webstartErrorMsg(msg));
  2279. }
  2280. } else { //success
  2281. if (relaunch) {
  2282. t = appletInfoMsg("install:fx:restart");
  2283. //Instead of hiding splash and applet we simply clear the container
  2284. //We are not going to show neither splash nor applet anyways ...
  2285. wipe(placeholder);
  2286. placeholder.appendChild(t);
  2287. }
  2288. }
  2289. }
  2290. function defaultDeployErrorHandler(app, r) {
  2291. if (r == null) {
  2292. code = "success";
  2293. } else if (r.isUnsupportedBrowser()) {
  2294. code = "browser";
  2295. } else if (r.jreStatus() != "ok") {
  2296. code = "jre:" + r.jreStatus();
  2297. } else if (r.javafxStatus() != "ok") {
  2298. code = "javafx:" + r.javafxStatus();
  2299. } else if (r.isRelaunchNeeded()) {
  2300. code = "relaunch";
  2301. } else {
  2302. code = "unknown " + r.toString();
  2303. }
  2304. if (app.placeholder != null) {//embedded app
  2305. showAppletError(app.id, code, null);
  2306. } else { //webstart or install case
  2307. w.alert(webstartErrorMsg(code));
  2308. }
  2309. }
  2310. function defaultRuntimeErrorHandler(id) {
  2311. var el_applet = findAppletDiv(id);
  2312. if (getErrorDiv(id) != null) {
  2313. showAppletError(id, "launch:fx:generic:embedded",
  2314. function() {showHideApplet(findAppletDiv(id), false); return false;});
  2315. } else {
  2316. w.alert(webstartErrorMsg("launch:fx:generic"));
  2317. }
  2318. }
  2319. //TODO: Does availability of object mean initialization is completed (or even started?)
  2320. //Can we expect that any subsequent call to this object will actually work?
  2321. //Perhaps it is false alarm
  2322. function getPlugin() {
  2323. var result = null;
  2324. if (ua.override == false) {
  2325. navigator.plugins.refresh(false);
  2326. result = document.getElementById('dtjavaPlugin');
  2327. }
  2328. return result;
  2329. }
  2330. function installNativePlugin() {
  2331. //already installed?
  2332. if (getPlugin() != null) return;
  2333. //can not install plugin now as page has no body yet, postpone
  2334. //NB: use cbDone here to avoid infinite recursion (corner case)
  2335. if (!notNull(d.body) && !cbDone) {
  2336. addOnDomReadyInternal(function() {
  2337. installNativePlugin();
  2338. });
  2339. postponeNativePluginInstallation = true;
  2340. return;
  2341. }
  2342. var p = null;
  2343. if (ua.ie) {
  2344. p = d.createElement('object');
  2345. //TODO: zero size does not work?? How we can make it less intrusive for layout?
  2346. p.width = '1px';
  2347. p.height = '1px';
  2348. //new CLSID, one with 0000-0000 had been kill bit
  2349. p.classid = 'clsid:CAFEEFAC-DEC7-0000-0001-ABCDEFFEDCBA';
  2350. } else {
  2351. // Safari and Opera browsers find the plugin but it
  2352. // doesn't work, so until we can get it to work - don't use it.
  2353. if (!ua.wk && !ua.op && navigator.mimeTypes != null) {
  2354. // mime-type of the DeployToolkit plugin object
  2355. // (do not care about old DT plugin anymore)
  2356. var mimeType = 'application/java-deployment-toolkit';
  2357. var newDT = false;
  2358. for (var i = 0; i < navigator.mimeTypes.length; i++) {
  2359. var mt = navigator.mimeTypes[i];
  2360. newDT = newDT || ((mt.type == mimeType) && mt.enabledPlugin);
  2361. }
  2362. if (newDT) {
  2363. p = d.createElement('embed');
  2364. p.setAttribute('type', newDT ? mimeType : oldMimeType);
  2365. p.setAttribute('hidden', 'true');
  2366. }
  2367. }
  2368. }
  2369. if (p != null) {
  2370. p.setAttribute('id', 'dtjavaPlugin');
  2371. d.body.appendChild(p);
  2372. // Update internal versions from plug-in if needed
  2373. if (ua.deploy == null && isDef(p.version)) {
  2374. ua.deploy = p.version;
  2375. }
  2376. }
  2377. }
  2378. var appletCounter = 0;
  2379. function prepareAppletID(ld) {
  2380. if (notNull(ld.id)) {
  2381. return ld.id;
  2382. } else {
  2383. appletCounter++;
  2384. return ("dtjava-app-" + appletCounter);
  2385. }
  2386. }
  2387. //returns object that represents an applet/object tag
  2388. function getAppletSnippet(ld, platform, cb) {
  2389. //we use wrapper div here as changing style on applet tag
  2390. // cause liveconnect to be initialized and slows down startup
  2391. var wrapper = d.createElement("div");
  2392. wrapper.width = normalizeDimension(ld.width);
  2393. wrapper.height = normalizeDimension(ld.height);
  2394. wrapper.id = ld.id + "-app";
  2395. //without this it splash will not work in Chrome
  2396. wrapper.style.position = "relative";
  2397. var r = d.createElement("applet"); //TODO: use object!
  2398. r.code = "dummy.class";
  2399. r.id = ld.id;
  2400. r.width = normalizeDimension(ld.width);
  2401. r.height = normalizeDimension(ld.height);
  2402. //things added unconditionally
  2403. var sparams = {"jnlp_href" : ld.url,
  2404. "java_status_events" : true,
  2405. "type" : "application/x-java-applet"};
  2406. if (notNull(ld.jnlp_content)) {
  2407. sparams['jnlp_embedded'] = ld.jnlp_content;
  2408. }
  2409. if (notNull(platform.javafx)) {
  2410. //for swing applications embedding FX we do not want this property as it will
  2411. // trigger FX toolkit and lead to app failure!
  2412. if (!notNull(ld.toolkit) || ld.toolkit == "fx") {
  2413. sparams["javafx_version"] = ((platform.javafx == "*") ? "2.0+" : platform.javafx);
  2414. }
  2415. //FX requires new VM per applet, do it unconditionally
  2416. sparams["separate_jvm"] = true;
  2417. sparams["javafx_applet_id"] = r.id;
  2418. //enable scripting for FX unconditionally for now
  2419. sparams["scriptable"] = true;
  2420. } else {
  2421. if (ld.scriptable) {
  2422. sparams["scriptable"] = true;
  2423. }
  2424. if (ld.sharedjvm) {
  2425. sparams["separate_jvm"] = true;
  2426. }
  2427. }
  2428. if (notNull(platform.jvmargs)) {
  2429. sparams["java_arguments"] = platform.jvmargs;
  2430. }
  2431. //prepare parameters first
  2432. var key, p;
  2433. for (key in ld.params) {
  2434. //do not let to override system parameters
  2435. if (!notNull(sparams[key])) {
  2436. p = d.createElement("param");
  2437. p.name = key;
  2438. p.value = ld.params[key];
  2439. r.appendChild(p);
  2440. }
  2441. }
  2442. for (key in sparams) {
  2443. p = d.createElement("param");
  2444. p.name = key;
  2445. p.value = sparams[key];
  2446. r.appendChild(p);
  2447. }
  2448. if (isDef(cb.onGetNoPluginMessage)) {
  2449. p = d.createElement("noapplet");
  2450. var t = cb.onGetNoPluginMessage(ld);
  2451. p.appendChild(t);
  2452. //TODO: FIXME: following line fails for me in IE7??
  2453. //r.appendChild(p);
  2454. }
  2455. wrapper.appendChild(r);
  2456. return wrapper;
  2457. }
  2458. function findAppletDiv(id) {
  2459. //TODO: FIXME: in static deployment scenario this seem to cause restart of plugin (in FF)
  2460. //Weird but similar code works in the deployJava.js ...
  2461. //TODO: reinvestigate
  2462. var el = d.getElementById(id + "-app");
  2463. if (el == null) { //wrapping div for applet is not required
  2464. el = d.getElementById(id);
  2465. }
  2466. return el;
  2467. }
  2468. //IMPORTANT: whilst we can update style on the applet element itself
  2469. // this is not best idea as this may also cause wait till liveconnect
  2470. // is initialized and slow startup.
  2471. function showHideApplet(div, hide) {
  2472. if (!notNull(div)) return;
  2473. if (hide) {
  2474. div.style.left = -10000;
  2475. } else {
  2476. div.style.left = "0px";
  2477. }
  2478. }
  2479. function showHideDiv(div, hide) {
  2480. if (!notNull(div)) return;
  2481. if (hide) {
  2482. div.style.visibility = "hidden";
  2483. } else {
  2484. div.style.visibility = "visible";
  2485. }
  2486. }
  2487. function doHideSplash(id) {
  2488. try {
  2489. var errPane = getErrorDiv(id);
  2490. if (errPane != null && errPane.style != null && errPane.style.visibility == "visible") {
  2491. //if we have error pane shown then ignore this request
  2492. // (could be race condition and applet is asking to hide splash to show error too)
  2493. return;
  2494. }
  2495. var el = findAppletDiv(id);
  2496. showHideApplet(el, false);
  2497. //show applet first and then hide splash to avoid blinking
  2498. showHideDiv(d.getElementById(id + "-splash"), true);
  2499. } catch(err) {}
  2500. }
  2501. var javafxURL = "https://java.com/javafx";
  2502. //TODO: validate ALL messages are shown as expected and when expected (for applet/webstart/install)
  2503. var errorMessages = {
  2504. "launch:fx:generic" : ["JavaFX application could not launch due to system configuration.",
  2505. " See ", "a", "https://java.com/javafx", "java.com/javafx",
  2506. " for troubleshooting information."],
  2507. "launch:fx:generic:embedded" : ["JavaFX application could not launch due to system configuration ",
  2508. "(", "onclick", "show error details", ").",
  2509. " See ", "a", "https://java.com/javafx", "java.com/javafx",
  2510. " for troubleshooting information."],
  2511. "install:fx:restart" : ["Restart your browser to complete the JavaFX installation,",
  2512. " then return to this page."],
  2513. "install:fx:error:generic" : ["JavaFX install not completed.",
  2514. " See ", "a", "https://java.com/javafx", "java.com/javafx",
  2515. " for troubleshooting information."],
  2516. "install:fx:error:download" : ["JavaFX install could not start because of a download error.",
  2517. " See ", "a", "https://java.com/javafx", "java.com/javafx",
  2518. " for troubleshooting information."],
  2519. "install:fx:error:cancelled" : ["JavaFX install was cancelled.",
  2520. " Reload the page and click on the download button to try again."],
  2521. "install:jre:error:cancelled" : ["Java install was cancelled.",
  2522. " Reload the page and click on the download button to try again."],
  2523. "install:jre:error:generic" : ["Java install not completed.",
  2524. " See ", "a", "https://java.com/", "java.com",
  2525. " for troubleshooting information."],
  2526. "install:jre:error:download" : ["Java install could not start because of a download error.",
  2527. " See ", "a", "https://java.com/", "java.com/",
  2528. " for troubleshooting information."],
  2529. "install:inprogress:jre" : ["Java install in progress."],
  2530. "install:inprogress:javafx" : ["JavaFX install in progress."],
  2531. "install:inprogress:javafx:manual" : ["Please download and run JavaFX Setup from ",
  2532. "a", getFxUrl(null), "java.com/javafx",
  2533. ". When complete, restart your browser to finish the installation,",
  2534. " then return to this page."],
  2535. "install:inprogress:jre:manual" : ["Please download and run Java Setup from ",
  2536. "a", getJreUrl(), "java.com/download",
  2537. ". When complete, reload the page."],
  2538. "install:fx:error:nojre" : ["b", "Installation failed.", "br",
  2539. "Java Runtime is required to install JavaFX and view this content. ",
  2540. "a", getJreUrl(), "Download Java Runtime",
  2541. " and run the installer. Then reload the page to install JavaFX."],
  2542. "browser": [ 'Content can not be displayed using your Web browser. Please open this page using another browser.'],
  2543. "jre:none": [ 'JavaFX application requires a recent Java runtime. Please download and install the latest JRE from ',
  2544. 'a', 'https://java.com', "java.com", '.'],
  2545. "jre:old" : [ 'JavaFX application requires a recent Java runtime. Please download and install the latest JRE from ',
  2546. 'a', 'https://java.com', "java.com", '.'],
  2547. "jre:plugin": ['b', "A Java plugin is required to view this content.", 'br',
  2548. "Make sure that ", "a", 'https://java.com', "a recent Java runtime",
  2549. " is installed, and the Java plugin is enabled."],
  2550. "jre:blocked": ["Please give Java permission to run. This will allow Java to present content provided on this page."],
  2551. "jre:unsupported": ["b", "Java is required to view this content but Java is currently unsupported on this platform.",
  2552. "br", "Please consult ", "a", "https://java.com", "the Java documentation",
  2553. " for list of supported platforms."],
  2554. "jre:browser" : ["b", "Java plugin is required to view this content but Java plugin is currently unsupported in this browser.",
  2555. "br", "Please try to launch this application using other browser. Please consult ",
  2556. "a", "https://java.com", "the Java documentation",
  2557. " for list of supported browsers for your OS."],
  2558. "javafx:unsupported" : ["b", "JavaFX 2.0 is required to view this content but JavaFX is currently unsupported on this platform.",
  2559. "br", "Please consult ", "a", javafxURL, "the JavaFX documentation",
  2560. " for list of supported platforms."],
  2561. "javafx:old" : [ 'This application requires newer version of JavaFX runtime. ',
  2562. 'Please download and install the latest JavaFX Runtime from ',
  2563. 'a', javafxURL, "java.com/javafx", '.'],
  2564. "javafx:none" : ["b", "JavaFX 2.0 is required to view this content.",
  2565. "br", "a", javafxURL, "Get the JavaFX runtime from java.com/javafx",
  2566. " and run the installer. Then restart the browser."],
  2567. "javafx:disabled" : ["JavaFX is disabled. Please open Java Control Panel, switch to Advanced tab and enable it. ",
  2568. "Then restart the browser."],
  2569. "jre:oldplugin" : ["New generation Java plugin is required to view this content." +
  2570. " Please open Java Control Panel and enable New Generation Java Plugin."],
  2571. "jre:disabled" : ["Java plugin appear to be disabled in your browser. ",
  2572. " Please enable Java in the browser options."]
  2573. };
  2574. //assume we get list of (tag, param, text) where both param and tag are optional
  2575. // Supported tags:
  2576. // ("a", href value, link text)
  2577. // ("b", text)
  2578. // ("br")
  2579. // (text) //text can not be the same as any of tag names
  2580. function msgAsDOM(lst, extra, onClickFunc) {
  2581. var i = 0;
  2582. var root = d.createElement("p");
  2583. if (extra != null) {
  2584. root.appendChild(extra);
  2585. }
  2586. var el;
  2587. while (i < lst.length) {
  2588. switch (lst[i]) {
  2589. case "a":
  2590. el = d.createElement(lst[i]);
  2591. el.href = lst[i + 1];
  2592. el.appendChild(d.createTextNode(lst[i + 2]));
  2593. i = i + 2;
  2594. break;
  2595. case "br":
  2596. el = d.createElement(lst[i]);
  2597. break;
  2598. case "b":
  2599. el = d.createElement(lst[i]);
  2600. el.appendChild(d.createTextNode(lst[i + 1]));
  2601. i++;
  2602. break;
  2603. case "onclick":
  2604. el = d.createElement("a");
  2605. el.href = "";
  2606. if (onClickFunc == null) {
  2607. onClickFunc = function() {return false;}
  2608. }
  2609. el.onclick = onClickFunc;
  2610. el.appendChild(d.createTextNode(lst[i + 1]));
  2611. i = i + 1;
  2612. break;
  2613. default:
  2614. el = d.createTextNode(lst[i]);
  2615. break;
  2616. }
  2617. root.appendChild(el);
  2618. i++;
  2619. }
  2620. return root;
  2621. }
  2622. function webstartErrorMsg(code) {
  2623. var m = "";
  2624. var lst = errorMessages[code];
  2625. var i = 0;
  2626. if (notNull(lst)) {
  2627. while (i < lst.length) {
  2628. if (lst[i] != 'a' && lst[i] != 'br' && lst[i] != 'b') {
  2629. m += lst[i];
  2630. } else if (lst[i] == 'a') { //next element is link => skip it
  2631. i++;
  2632. }
  2633. i++;
  2634. }
  2635. } else {
  2636. m = "Unknown error: ["+code+"]";
  2637. }
  2638. return m;
  2639. }
  2640. function getErrorDiv(id) {
  2641. return d.getElementById(id + "-error");
  2642. }
  2643. function showAppletError(id, code, onclickFunc) {
  2644. var pane = getErrorDiv(id);
  2645. if (!notNull(pane)) { //should not be possible, we add error pane right a way and then add it again before we add splash/app
  2646. return;
  2647. }
  2648. //remove old content in the ERROR PANE only (if any)
  2649. wipe(pane);
  2650. //populate and show pane
  2651. pane.appendChild(appletErrorMsg(code, onclickFunc));
  2652. pane.style.visibility = "visible";
  2653. //hide splash and applet
  2654. showHideDiv(d.getElementById(id+"-splash"), true);
  2655. showHideApplet(findAppletDiv(id), true);
  2656. }
  2657. //returns DOM subtree
  2658. function appletErrorMsg(code, onclickFunc) {
  2659. var out = d.createElement("div");
  2660. var img = d.createElement("img");
  2661. img.src = jscodebase + 'error.png';
  2662. img.width = '16px';
  2663. img.height = '16px';
  2664. img.alt = "";
  2665. img.style.cssFloat = "left";
  2666. img.style.styleFloat = "left"; //IE way
  2667. img.style.margin = "0px 10px 60px 10px";
  2668. img.style.verticalAlign="text-top";
  2669. var m = errorMessages[code];
  2670. //error message is missing => show code as fallback
  2671. if (!notNull(m)) {
  2672. m = [code];
  2673. }
  2674. var hideFunc = null;
  2675. if (isDef(onclickFunc)) {
  2676. hideFunc = function() {
  2677. if (notNull(out.parentNode)) {
  2678. out.parentNode.removeChild(out);
  2679. }
  2680. try {
  2681. onclickFunc();
  2682. } catch (e) {}
  2683. return false;
  2684. }
  2685. }
  2686. out.appendChild(msgAsDOM(m, img, hideFunc));
  2687. return out;
  2688. }
  2689. //returns DOM subtree
  2690. function appletInfoMsg(code) {
  2691. var out = d.createElement("div");
  2692. var m = errorMessages[code];
  2693. //error message is missing => show code as fallback
  2694. if (!notNull(m)) {
  2695. m = [code];
  2696. }
  2697. out.appendChild(msgAsDOM(m, null, null));
  2698. return out;
  2699. }
  2700. function normalizeApp(ld, acceptString) {
  2701. var app = null;
  2702. //normalize launch descriptor
  2703. if (notNull(ld)) {
  2704. //could be either url or set of parameters
  2705. if (acceptString && typeof ld === 'string') {
  2706. app = new dtjava.App(ld, null);
  2707. } else if (ld instanceof dtjava.App) {
  2708. app = ld;
  2709. } else {
  2710. app = new dtjava.App(ld.url, ld);
  2711. }
  2712. }
  2713. return app;
  2714. }
  2715. function setupAppletCallbacks(platform, callbacks) {
  2716. //set default callbacks
  2717. var cb = new dtjava.Callbacks(callbacks);
  2718. //disable splash if it is was not requested explicitly and
  2719. // it is not JavaFX app
  2720. if (platform.javafx == null && cb.onGetSplash === defaultGetSplashHandler) {
  2721. cb.onGetSplash = null;
  2722. }
  2723. return cb;
  2724. }
  2725. //width and height in styles need to have unit type explicitly referenced
  2726. // or they will not conform to strict doctypes
  2727. //On other hand we can have relative dimensions, e.g. 100% and these are fine without units
  2728. //
  2729. //This method will add unit type to numeric dimension specifications. E.g.
  2730. // 400 => 400px
  2731. // -10 => -10px
  2732. // 50% => 50%
  2733. function normalizeDimension(v) {
  2734. if (isFinite(v)) {
  2735. return v + 'px';
  2736. } else {
  2737. return v;
  2738. }
  2739. }
  2740. //wrap given node s in the div
  2741. function wrapInDiv(ld, s, suffix) {
  2742. var sid = ld.id + "-" + suffix;
  2743. var div = d.createElement("div");
  2744. div.id = sid;
  2745. div.style.width = normalizeDimension(ld.width);
  2746. //this does not work well for different browsers
  2747. //if height is relative ...
  2748. //For firefox it becomes better if 100% is hardcode
  2749. // but then image is off in Chrome and it does not work in IE too ...
  2750. div.style.height = normalizeDimension(ld.height);
  2751. div.style.position = "absolute";
  2752. //TODO: provide way to specify bgcolor
  2753. // Perhaps app.style.bgcolor, app.style.splash-image, ... ?
  2754. // What was the param name supported by regular applet?
  2755. div.style.backgroundColor = "white";
  2756. if (s != null) {
  2757. div.appendChild(s);
  2758. }
  2759. return div;
  2760. }
  2761. var pendingCallbacks = {};
  2762. function doInstallCallbacks(id, cb) {
  2763. if (cb == null) {
  2764. cb = pendingCallbacks[id];
  2765. if (notNull(cb)) {
  2766. pendingCallbacks[id] = null;
  2767. } else {
  2768. return;
  2769. }
  2770. }
  2771. var a = document.getElementById(id);
  2772. if (!notNull(a)) return;
  2773. if (isDef(cb.onJavascriptReady)) {
  2774. var onReady = cb.onJavascriptReady;
  2775. if (a.status < 2) { //not READY yet
  2776. a.onLoad = function() {
  2777. onReady(id);
  2778. a.onLoad = null; //workaround bug in plugin for IE in JRE7
  2779. }
  2780. }
  2781. }
  2782. if (isDef(cb.onRuntimeError)) {
  2783. if (a.status < 3) { //not ERROR or READY yet
  2784. a.onError = function() {
  2785. cb.onRuntimeError(id);
  2786. //This used to be added as
  2787. // "workaround bug in plugin for IE in JRE7"
  2788. //I do not have recollection what the bug was
  2789. // and can not reproduce it now
  2790. //(perhaps multiple calls into callback?)
  2791. //With FX 2.0 it cause restart of the applet in IE
  2792. // for reason that is not completely clear
  2793. //Disable it for now
  2794. /* a.onError = null; */
  2795. }
  2796. } else if (a.status == 3) { //already failed, call handler in place
  2797. cb.onRuntimeError(id);
  2798. }
  2799. }
  2800. }
  2801. //we can not install applet callbacks until applet is instantiated as
  2802. //hook entry points are not defined and we do not control when applet is
  2803. //instantiated as developer may not add it to the DOM tree for a while.
  2804. //
  2805. //Therefore what we do is we insert <script> element AFTER applet tag
  2806. //to initiate install after applet tag is parsed
  2807. //
  2808. //However, we can not
  2809. //
  2810. function getSnippetToInstallCallbacks(id, cb) {
  2811. if (!notNull(cb) || !(isDef(cb.onDeployError) || isDef(cb.onJavascriptReady))) {
  2812. return null;
  2813. }
  2814. var s = d.createElement("script");
  2815. pendingCallbacks[id] = cb;
  2816. s.text = "dtjava.installCallbacks('"+id+"')";
  2817. return s;
  2818. }
  2819. function getErrorPaneSnippet(app) {
  2820. var paneDiv = wrapInDiv(app, null, "error");
  2821. paneDiv.style.visibility = "hidden";
  2822. return paneDiv;
  2823. }
  2824. function doEmbed(ld, platform, callbacks) {
  2825. var app = normalizeApp(ld, false);
  2826. //required argument is missing
  2827. if (!(notNull(app) && notNull(app.url) &&
  2828. notNull(app.width) && notNull(app.height) && notNull(app.placeholder))) {
  2829. //deployment error, not runtime => exception is ok
  2830. throw "Required attributes are missing! (url, width, height and placeholder are required)";
  2831. }
  2832. app.id = prepareAppletID(app);
  2833. //if placeholder is passed as id => find DOM node
  2834. if ((typeof app.placeholder == "string")) {
  2835. var p = d.getElementById(app.placeholder);
  2836. if (p == null) {
  2837. throw "Application placeholder [id="+app.placeholder+"] not found.";
  2838. }
  2839. app.placeholder = p;
  2840. }
  2841. //we may fail before we even try to add splash. E.g. because it is unsupported platform
  2842. //make sure we have error pane in place to show error
  2843. app.placeholder.appendChild(getErrorPaneSnippet(app));
  2844. //if we got array we need to copy over!
  2845. platform = new dtjava.Platform(platform);
  2846. var cb = setupAppletCallbacks(platform, callbacks);
  2847. //allow family match to match next family
  2848. //Once we get to java layer we will deal with it there
  2849. var v = doValidateRelaxed(platform);
  2850. var launchFunction = function() {
  2851. var appSnippet = getAppletSnippet(app, platform, cb);
  2852. var splashSnippet = (cb.onGetSplash == null) ? null : cb.onGetSplash(ld);
  2853. //what we try to do:
  2854. // placeholder need to have relative positioning (then splash will pe position relative to it)
  2855. // if splash is present it needs to have position "absolute", then it will not occupy space
  2856. // and can be placed on top of applet
  2857. app.placeholder.style.position = "relative";
  2858. if (splashSnippet != null) {
  2859. //position splash on top of applet area and hide applet temporarily
  2860. var ss = wrapInDiv(app, splashSnippet, "splash");
  2861. showHideDiv(ss, false);
  2862. showHideApplet(appSnippet, true);
  2863. wipe(app.placeholder);
  2864. app.placeholder.appendChild(getErrorPaneSnippet(app));
  2865. app.placeholder.appendChild(ss);
  2866. app.placeholder.appendChild(appSnippet);
  2867. } else {
  2868. wipe(app.placeholder);
  2869. app.placeholder.appendChild(getErrorPaneSnippet(app));
  2870. app.placeholder.appendChild(appSnippet);
  2871. }
  2872. //Note: this is not needed as we use setTimeout for the same
  2873. //var cbSnippet = getSnippetToInstallCallbacks(app.id, cb);
  2874. //if (cbSnippet != null) {
  2875. // app.placeholder.appendChild(cbSnippet);
  2876. //}
  2877. setTimeout(function() {doInstallCallbacks(app.id, cb)}, 0);
  2878. };
  2879. //can not launch yet
  2880. if (v != null) {
  2881. resolveAndLaunch(app, platform, v, cb, launchFunction);
  2882. } else {
  2883. launchFunction();
  2884. }
  2885. }
  2886. function extractApp(e) {
  2887. if (notNull(e)) {
  2888. var w = e.width; //TODO: do we need to extract number? e.g. if it was 400px? or 100%?
  2889. var h = e.height;
  2890. var jnlp = "dummy"; //Can find it from list of parameters but it is not really needed in
  2891. //static deployment scenario
  2892. return new dtjava.App(jnlp, {
  2893. id: e.id,
  2894. width: w,
  2895. height: h,
  2896. placeholder: e.parentNode
  2897. });
  2898. } else {
  2899. throw "Can not find applet with null id";
  2900. }
  2901. }
  2902. function processStaticObject(id, platform, callbacks) {
  2903. var a = d.getElementById(id); //TODO: use findAppletDiv??
  2904. var app = extractApp(a);
  2905. var cb = setupAppletCallbacks(platform, callbacks);
  2906. //Ensure some platform is set
  2907. platform = new dtjava.Platform(platform);
  2908. var launchFunc = function() {
  2909. //add error pane
  2910. app.placeholder.insertBefore(getErrorPaneSnippet(app), a);
  2911. if (cb.onGetSplash != null) {
  2912. //TODO: show splash if it was not hidden yet!
  2913. var splashSnippet = cb.onGetSplash(app);
  2914. if (notNull(splashSnippet)) {
  2915. var ss = wrapInDiv(app, splashSnippet, "splash");
  2916. if (notNull(ss)) {
  2917. app.placeholder.style.position = "relative";
  2918. app.placeholder.insertBefore(ss, a);
  2919. showHideApplet(a, true);
  2920. }
  2921. }
  2922. }
  2923. //TODO: install applet callbacks if they are provided
  2924. //Note - in theory we need to check if callbacks are supported too
  2925. // but if detection was not possible then it is hard to do
  2926. //they always wotk for FX or jre 7+ but how validate this?
  2927. //otherwise attempt to set them will block js and then trigger exception ...
  2928. }
  2929. var v = doValidateRelaxed(platform);
  2930. if (v != null) {
  2931. //TODO: Problem
  2932. // if FX missing and static deployment
  2933. // then JRE will try to autoinstall itself - this will cause popup
  2934. // Then DT will detect problem and also initiate install too
  2935. // a) double install
  2936. // b) if popup is canceled then we still offer to install again but it will not help applet to launch
  2937. // c) popup is unconditional and really ugly ...
  2938. //But popup comes from JRE7 - can not fix it, on other hand 6 will go manual install route
  2939. resolveAndLaunch(app, platform, v, cb, launchFunc);
  2940. } else {
  2941. launchFunc();
  2942. }
  2943. }
  2944. function doRegister(id, platform, cb) {
  2945. //we will record static object and process it once onload is done
  2946. addOnDomReady(function() {
  2947. processStaticObject(id, platform, cb);
  2948. });
  2949. }
  2950. //perform basic (lightweight) initialization
  2951. init();
  2952. /**
  2953. The Java Deployment Toolkit is utility to deploy Java content in
  2954. the browser as applets or applications using right version of Java.
  2955. If needed it can initiate upgrade of user's system to install required
  2956. components of Java platform.
  2957. <p>
  2958. Note that some of Deployment Toolkit methods may not be fully operational if
  2959. used before web page body is loaded (because DT native plugins could not be instantiated).
  2960. If you intend to use it before web page DOM tree is ready then dtjava.js needs to be loaded inside the
  2961. body element of the page and before use of other DT APIs.
  2962. @class dtjava
  2963. @static */
  2964. return {
  2965. /**
  2966. Version of Javascript part of Deployment Toolkit.
  2967. Increasing date lexicographically.
  2968. @property version
  2969. @type string
  2970. */
  2971. version: "20150817",
  2972. /**
  2973. Validate that platform requirements are met.
  2974. @param platform {Platform}
  2975. (Optional) set of platform requirements.
  2976. <p>
  2977. Default settings are
  2978. <ul>
  2979. <li>platform.jvm : "1.6+"
  2980. <li>platform.javafx : null
  2981. <li>platform.plugin : "*"
  2982. </ul>
  2983. @return {PlatformMismatchEvent}
  2984. Returns null if all requirements are met.
  2985. Return PlatformMismatchEvent describing the problem otherwise.
  2986. */
  2987. validate: function(platform) {
  2988. return doValidate(platform, ua.noPluginWebBrowser);
  2989. },
  2990. /**
  2991. Perform install of missing components based on given
  2992. platform requirements. By default if automated install is
  2993. not possible then manual install will be offered.
  2994. @method install
  2995. @param platform {Platform}
  2996. Description of platform requirements.
  2997. @param callbacks {Callbacks}
  2998. Optional set of callbacks to customize install experience.
  2999. @return {boolean}
  3000. Returns true if install was initiated.
  3001. */
  3002. install: function(platform, callbacks) {
  3003. return doInstall(null, platform, callbacks, null);
  3004. },
  3005. // (TODO: AI: what are limitations on "connect back to origin host?"
  3006. // can someone provide us fake JNLP url to get access to other host?
  3007. // Perhaps we should support this for relative URLs only?)
  3008. /**
  3009. Launch application (not embedded into browser) based on given
  3010. application descriptor. If launch requirements are not met
  3011. then autoinstall may be initiated if requested and supported.
  3012. By default autoinstall is disabled.
  3013. @method launch
  3014. @param ld {App | string | array}
  3015. Application launch descriptor. Could be defined as one of following:
  3016. <ul>
  3017. <li>instance of App object,
  3018. <li>string with URL of application JNLP file
  3019. <li>or array (where URL attribute is required)
  3020. </ul>
  3021. At least link to JNLP file must be provided (could be full URL or relative to
  3022. document location).
  3023. <p>
  3024. Note that passing parameters through the Apps object is not supported by this method.
  3025. Any parameters specified will be ignored.
  3026. @param platform {Platform}
  3027. Optional platform requirements (such as JRE and JavaFX versions).
  3028. @param callbacks {Callbacks | array}
  3029. Optional set of callbacks. See Callbacks for details.
  3030. */
  3031. //this will not use jvargs either but we do not necessary need to document it
  3032. launch: function(ld, platform, callbacks) {
  3033. return doLaunch(ld, platform, callbacks);
  3034. },
  3035. /**
  3036. Embeds application into browser based on given application descriptor
  3037. (required elements: url of JNLP file, width and height, id or reference to placeholder node).
  3038. <p>
  3039. If JRE or JavaFX installation is required then default handler is to return "click to install" html snippet.
  3040. To enable autoinstall custom onDeployError handler need to be used.
  3041. <p>
  3042. If applet can not be launched because platform requirements are not met
  3043. (e.g. DT plugin is not available or mandatory parameters are missing)
  3044. return value will be null.
  3045. <p>
  3046. Set applet identifier in the launch descriptor if you want to name your
  3047. applet in the DOM tree (e.g. to use it from javascript later).
  3048. @method embed
  3049. @param ld {App | string | array}
  3050. Application launch descriptor. Could be defined as one of following:
  3051. <ul>
  3052. <li>instance of App object,
  3053. <li>array (where attribute names are same as in App object)
  3054. </ul>
  3055. At least link to JNLP file, width and height must be provided.
  3056. @param platform {Platform}
  3057. Optional platform requirements (such as JRE and JavaFX versions).
  3058. @param cb {Callbacks | array}
  3059. Optional set of callbacks. See Callbacks for details.
  3060. @return {void}
  3061. */
  3062. embed: function(ld, platform, cb) {
  3063. return doEmbed(ld, platform, cb);
  3064. },
  3065. /**
  3066. Registers statically deployed Java applet to customize loading experience
  3067. if Javascript is enabled.
  3068. <p>
  3069. Note that launch of statically deployed applet will be initiated
  3070. before this this function will get control. Hence platform
  3071. requirements listed here will NOT be validated prior to launch
  3072. and will be used if applet launch can not be initiated otherwise.
  3073. @method register
  3074. @param id
  3075. Identifier of application.
  3076. @param platform {Platform}
  3077. Optional platform requirements (such as JRE and JavaFX versions).
  3078. @param cb {Callbacks | array}
  3079. Optional set of callbacks. See Callbacks for details.
  3080. */
  3081. register: function(id, platform, callbacks) {
  3082. return doRegister(id, platform, callbacks);
  3083. },
  3084. /**
  3085. * Hides html splash panel for applet with given id.
  3086. * If splash panel does not exist this method has no effect.
  3087. * For JavaFX applications this method will be called automatically once application is ready.
  3088. * For Swing/AWT applets application code need to call into this method explicitly if they were deployed
  3089. * with custom splash handler.
  3090. *
  3091. * @method hideSplash
  3092. * @param id Identifier of applet whose splash panel need to be hidden
  3093. */
  3094. hideSplash: function(id) {
  3095. return doHideSplash(id);
  3096. },
  3097. /**
  3098. Helper function: cross-browser onLoad support
  3099. <p>
  3100. This will call fn() once document is loaded.
  3101. If page is already loaded when this method is
  3102. called then fn() is called immediately.
  3103. <p>
  3104. If strictMode is true then fn() is called once page
  3105. and all its assets are loaded (i.e. when document
  3106. ready state will be 'complete').
  3107. Otherwise fn() is called after DOM tree is fully created
  3108. (but some assets may not yet be loaded).
  3109. <p>
  3110. It is ok to call this function multiple times. It will append
  3111. to existing chain of events (and do not replace them).
  3112. @method addOnloadCallback
  3113. @param {function} fn
  3114. (required) function to call
  3115. @param strictMode {boolean} Flag indicating whether page assets need to
  3116. be loaded before launch (default is false).
  3117. */
  3118. addOnloadCallback: function(fn, strictMode) {
  3119. //WORKAROUND for RT-21574
  3120. // avoid using onDomReady because it leads to deadlocks
  3121. if (strictMode || (ua.chrome && !ua.win)) {
  3122. addOnload(fn);
  3123. } else {
  3124. addOnDomReady(fn);
  3125. }
  3126. },
  3127. /**
  3128. * Add onJavascriptReady and onDeployError callbacks
  3129. * to the existing Java applet or JavaFX application.
  3130. * Application need to be alive in the browser DOM tree for this to work
  3131. *
  3132. * @param id {string} applet id
  3133. * @param cb {array} Set of callbacks. If null then pending callbacks are installed (if any for this applet).
  3134. * @private
  3135. */
  3136. installCallbacks: function(id, cb) {
  3137. doInstallCallbacks(id, cb);
  3138. },
  3139. /** Platform requirements for application launch.
  3140. <p><br>
  3141. The version pattern strings are of the form #[.#[.#[_#]]][+|*],
  3142. which includes strings such as "1.6", * "2.0*", and "1.6.0_18+".
  3143. <p>
  3144. A star (*) means "any version within this family" where family is defined
  3145. by prefix and a plus (+) means "any version greater or equal to the specified version".
  3146. For example "1.6.0*" matches 1.6.0_25 but not 1.7.0_01,
  3147. whereas "1.6.0+" or "1.*" match both.
  3148. <p>
  3149. If the version pattern does not include all four version components
  3150. but does not end with a star or plus, it will be treated as if it
  3151. ended with a star. "2.0" is exactly equivalent to "2.0*", and will
  3152. match any version number beginning with "2.0".
  3153. <p>
  3154. Null version string is treated as "there is no requirement to have it installed".
  3155. Validation will pass whether this component is installed or not.
  3156. <p>
  3157. Both "+" and "*" will match any installed version of component. However if component is not
  3158. installed then validation will fail.
  3159. @class Platform
  3160. @for dtjava
  3161. @constructor
  3162. @param r {array}
  3163. Array describing platform requirements. Element names should match
  3164. Platform properties.
  3165. */
  3166. Platform: function(r) {
  3167. //init with defaults
  3168. /**
  3169. JRE/JVM version.
  3170. @property jvm
  3171. @type version pattern string
  3172. @default "1.6+"
  3173. */
  3174. this.jvm = "1.6+";
  3175. /**
  3176. Minimum JavaFX version.
  3177. @property javafx
  3178. @type version pattern string
  3179. @default null
  3180. */
  3181. this.javafx = null;
  3182. /**
  3183. Java Plugin version.
  3184. If set to null then browser plugin support for embedded content is not validated.
  3185. @property plugin
  3186. @type version pattern string
  3187. @default "*"
  3188. */
  3189. this.plugin = "*";
  3190. /**
  3191. List of requested JVM arguments.
  3192. @property jvmargs
  3193. @type string
  3194. @default null
  3195. */
  3196. this.jvmargs = null;
  3197. //copy over
  3198. for (var v in r) {
  3199. this[v] = r[v];
  3200. //we expect jvmargs to come as array. if not - convert to array
  3201. if (this["jvmargs"] != null && typeof this.jvmargs == "string") {
  3202. this["jvmargs"] = this["jvmargs"].split(" ");
  3203. }
  3204. }
  3205. /**
  3206. * @method toString
  3207. * @return {string}
  3208. * Returns string replesentation of platform spec. Useful for debugging.
  3209. */
  3210. this.toString = function() {
  3211. return "Platform [jvm=" + this.jvm + ", javafx=" + this.javafx
  3212. + ", plugin=" + this.plugin + ", jvmargs=" + this.jvmargs + "]";
  3213. };
  3214. },
  3215. /**
  3216. Application launch descriptor.
  3217. @class App
  3218. @for dtjava
  3219. @constructor
  3220. @param url {string}
  3221. (Required) location of JNLP file. Could be full URL or partial
  3222. relative to document base.
  3223. @param details {array}
  3224. (Optional) set of values for other object properties.
  3225. Name should match documented object properties.
  3226. */
  3227. App: function(url, details) {
  3228. /**
  3229. Location of application's JNLP file. Can not be null or undefined.
  3230. @property url
  3231. @type string
  3232. */
  3233. this.url = url;
  3234. //default behavior
  3235. this.scriptable = true;
  3236. this.sharedjvm = true;
  3237. if (details != undefined && details != null) {
  3238. /**
  3239. Identifier of this App. Expected to be unique on this page.
  3240. If null then it is autogenerated.
  3241. @property id
  3242. @type string
  3243. */
  3244. this.id = details.id;
  3245. /**
  3246. Base64 encoded content of JNLP file.
  3247. @property jnlp_content
  3248. @type string
  3249. */
  3250. this.jnlp_content = details.jnlp_content;
  3251. /**
  3252. Applet width. Could be absolute or relative (e.g. 50 or 50%)
  3253. @property width
  3254. @type string
  3255. */
  3256. this.width = details.width;
  3257. /**
  3258. Applet height. Could be absolute or relative (e.g. 50 or 50%)
  3259. @property height
  3260. @type int
  3261. */
  3262. this.height = details.height;
  3263. /**
  3264. Set of named parameters to pass to application.
  3265. @property params
  3266. @type array
  3267. */
  3268. this.params = details.params;
  3269. /**
  3270. If set to true then Javascript to Java bridge will be initialized.
  3271. Note that some platform requirements imply Javascript bridge is initialized anyways.
  3272. If set to false the Java to Javascript calls are still possible.
  3273. //TODO: AI: will it affect applet callbacks?
  3274. @property scriptable
  3275. @type boolean
  3276. @default true
  3277. */
  3278. this.scriptable = details.scriptable;
  3279. /**
  3280. True if application does not need JVM instance to be dedicated to this application.
  3281. Some of platform requirements may imply exclusive use of JVM.
  3282. <p>
  3283. Note that even if sharing is enabled java plugin may choose to run applets in different JVM
  3284. instances. There is no way to force java plugin to reuse same JVM.
  3285. @property sharedjvm
  3286. @type boolean
  3287. @default true
  3288. */
  3289. this.sharedjvm = details.sharedjvm;
  3290. /**
  3291. Reference to DOM node to embed application into.
  3292. If not provided by the user and application is embedded then will be allocated dynamically.
  3293. <p>
  3294. Note that element may be not inserted into the DOM tree yet.
  3295. <p>
  3296. User may also provide identifier of the existing DOM node to be used as placeholder.
  3297. @property placeholder
  3298. @type {DOM node | DOM node id}
  3299. @default null
  3300. */
  3301. this.placeholder = details.placeholder;
  3302. /**
  3303. Tookit used by the application.
  3304. By default it is "fx" (and null is treated as JavaFX too).
  3305. Swing applications embedding JavaFX components need to pass "swing"
  3306. */
  3307. this.toolkit = details.toolkit;
  3308. }
  3309. /**
  3310. * Returns string representation of this object.
  3311. *
  3312. * @return {string}
  3313. */
  3314. this.toString = function() {
  3315. var pstr = "null";
  3316. var first = true;
  3317. if (notNull(this.params)) {
  3318. pstr = "{";
  3319. for (p in this.params) {
  3320. pstr += ((first) ? "" : ", ") + p + " => " + this.params[p];
  3321. first = false;
  3322. }
  3323. pstr += "}";
  3324. }
  3325. return "dtjava.App: [url=" + this.url + ", id=" + this.id + ", dimensions=(" + this.width + "," + this.height + ")"
  3326. + ", toolkit=" + this.toolkit
  3327. + ", embedded_jnlp=" + (notNull(this.jnlp_content) ? (this.jnlp_content.length + " bytes") : "NO")
  3328. + ", params=" + pstr + "]";
  3329. }
  3330. },
  3331. /**
  3332. Set of callbacks to be used to customize user experience.
  3333. @class Callbacks
  3334. @for dtjava
  3335. @constructor
  3336. @param cb {list of callbacks}
  3337. set of callbacks to set
  3338. */
  3339. Callbacks: function(cb) {
  3340. /**
  3341. Callback to be called to obtain content of the splash panel. Gets application
  3342. launch descriptor as an input. If null is returned then splash is disabled.
  3343. Non-null return value is expected to be html snippet to be added into splash overlay.
  3344. Only applicable to embed().
  3345. <p>
  3346. Note that autohiding splash is not supported by all platforms. Splash will be hidden by default
  3347. for JavaFX application but not for Swing/AWT applets. In later case if use of splash is desirable
  3348. then app need to call dtjava.hideSplash() explicitly to initiate hiding splash.
  3349. @property onGetSplash
  3350. @type function(app)
  3351. @default Default splash panel for JavaFX applications embedded into web page, null otherwise.
  3352. */
  3353. this.onGetSplash = defaultGetSplashHandler;
  3354. /**
  3355. Called if embedding or launching application need
  3356. additional components to be installed. This callback is
  3357. responsible for handling such situation, e.g. reporting
  3358. need to install something to the user,
  3359. initiating installation using install() and
  3360. hiding splash panel for embedded apps (if needed).
  3361. After installation is complete callback implementation may
  3362. retry attempt to launch application using provided launch function.
  3363. <p>
  3364. This method is NOT called if platform requirement could not be met
  3365. (e.g. if platfrom is not supported or if installation
  3366. is not possible).
  3367. <p>Default handler provides "click to install" solution for
  3368. embedded application and attempt to perform installation without
  3369. additional questions for apps started using launch().
  3370. <p>
  3371. If handler is null then it is treated as no op handler.
  3372. <p>
  3373. Parameters:
  3374. <ul>
  3375. <li> <b>app</b> - application launch descriptor.
  3376. For embedded applications app.placeholder will refer to
  3377. the root of the applet area in the DOM tree (to be used for
  3378. visual feedback)
  3379. <li> <b>platform</b> - application platform requirements
  3380. <li> <b>cb</b> - set of callbacks to be used during
  3381. installation process
  3382. <li> <b>isAutoinstall</b> - true if install can be launched
  3383. automatically
  3384. <li> <b>needRestart</b> - true if browser restart will be required
  3385. once installation is complete
  3386. <li> <b>launchFunction</b> - function to be executed to
  3387. retry launching the application once installation is finished
  3388. </ul>
  3389. @property onInstallNeeded
  3390. @type function(app, platform, cb, isAutoinstall, needRelaunch, launchFunc)
  3391. @default Default implementation shows "click to install" banner
  3392. for embedded applications or initiates installation immediately
  3393. for applications launched from web page.
  3394. */
  3395. this.onInstallNeeded = defaultInstallHandler;
  3396. /**
  3397. Called before installation of required component is triggered.
  3398. For manual install scenario it is called before installation
  3399. page is opened.
  3400. <p>
  3401. This method can be used to provide visual feedback to the user
  3402. during the installation. Placeholder
  3403. points to the area that can be used for visualization,
  3404. for embedded applications it will be applet area.
  3405. If null then callee need to find place for visualization on its own.
  3406. <p>
  3407. In case of automatic launch of installation onInstallFinished will be called
  3408. once installation is complete (succesfully or not).
  3409. <p>
  3410. If handler is null then it is treated as no-op handler.
  3411. Parameters:
  3412. <ul>
  3413. <li> <b>placeholder</b> - DOM element to insert visual feedback into.
  3414. If null then callee need to add visual feedback to the document on its own
  3415. (e.g. placeholder will be null if installation is not happening in context of embedding application into
  3416. web page).
  3417. <li> <b>component</b> - String "Java", "JavaFX" or "Java bundle"
  3418. <li> <b>isAutoInstall</b> - true if installer will be launched
  3419. automatically
  3420. <li> <b>restartNeeded</b> - boolean to specify whether browser restart will be required
  3421. </ul>
  3422. @property onInstallStarted
  3423. @type function(placeholder, component, isAuto, restartNeeded)
  3424. @default No-op
  3425. */
  3426. this.onInstallStarted = defaultInstallStartedHandler;
  3427. /**
  3428. Called once installation of required component
  3429. is completed. This method will NOT be called if installation is
  3430. performed in manual mode.
  3431. Parameters:
  3432. <ul>
  3433. <li> <b>placeholder</b> - DOM element that was passed to
  3434. onInstallStarted to insert visual feedback into.
  3435. <li> <b>component</b> - String "jre" or "javafx"
  3436. <li> <b>status</b> - status code is string categorizing the status of install.
  3437. ("success", "error:generic", "error:download" or "error:canceled")
  3438. <li> <b>relaunchNeeded</b> - boolean to specify
  3439. whether browser restart is required to complete the installation
  3440. </ul>
  3441. @property onInstallFinished
  3442. @type function(placeholder, component, status, relaunchNeeded)
  3443. @default no op
  3444. */
  3445. this.onInstallFinished = defaultInstallFinishedHandler;
  3446. /**
  3447. This function is called if application can not be deployed because
  3448. current platform does not match given platform requirements.
  3449. It is also called if request to install missing components can not be
  3450. completed due to platform.
  3451. <p>
  3452. Problem can be fatal error or transient issue (e.g. relaunch needed). Further
  3453. details can be extracted from provided mismatchEvent. Here are some typical combinations:
  3454. <ul>
  3455. <li><em>Current browser is not supported by Java</em> - (r.isUnsupportedBrowser())
  3456. <li><em>Browser need to be restarted before application can be launched</em> - (r.isRelaunchNeeded())
  3457. <li>JRE specific codes
  3458. <ul>
  3459. <li><em>JRE is not supported on this platform</em> - (r.jreStatus() == "unsupported")
  3460. <li><em>JRE is not detected and need to be installed</em> - (r.jreStatus() == "none")
  3461. <li><em>Installed version of JRE does not match requirements</em> - (r.jreStatus() == "old")
  3462. <li><em>Matching JRE is detected but deprecated Java plugin is used and
  3463. it does not support JNLP applets</em> - (r.jreStatus() == "oldplugin")
  3464. </ul>
  3465. <li> JavaFX specific codes
  3466. <ul>
  3467. <li><em>JavaFX is not supported on this platform</em> - (r.javafxStatus() == "unsupported")
  3468. <li><em>JavaFX Runtime is missing and need to be installed manually</em> - (r.javafxStatus() == "none")
  3469. <li><em>Installed version of JavaFX Runtime does not match requirements</em> - (r.javafxStatus() == "old")
  3470. <li><em>JavaFX Runtime is installed but currently disabled</em> - (r.javafxStatus() == "disabled")
  3471. </ul>
  3472. </ul>
  3473. Default error handler handles both application launch errors and embedded content.
  3474. @property onDeployError
  3475. @type function(app, mismatchEvent)
  3476. */
  3477. this.onDeployError = defaultDeployErrorHandler;
  3478. /**
  3479. * Called to get content to be shown in the applet area if Java plugin is not installed
  3480. * and none of callbacks helped to resolve this.
  3481. *
  3482. * @property onGetNoPluginMessage
  3483. * @type function(app)
  3484. * @return DOM Element object representing content to be shown in the applet area if
  3485. * java plugin is not detected by browser.
  3486. */
  3487. this.onGetNoPluginMessage = defaultGetNoPluginMessageHandler;
  3488. /**
  3489. Called once applet is ready to accept Javascript calls.
  3490. Only supported for plugin version 10.0.0 or later
  3491. @property onJavascriptReady
  3492. @type function(id)
  3493. @default null
  3494. */
  3495. this.onJavascriptReady = null;
  3496. /**
  3497. Called if application failed to launch.
  3498. Only supported for plugin version 10.0.0 or later.
  3499. @property onRuntimeError
  3500. @type function(id)
  3501. @default no op
  3502. */
  3503. this.onRuntimeError = defaultRuntimeErrorHandler;
  3504. //overwrite with provided parameters
  3505. for (c in cb) {
  3506. this[c] = cb[c];
  3507. }
  3508. }
  3509. };
  3510. }();