Source: jsf-uncompressed.js

  1. /*
  2. * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
  3. * Copyright 2004 The Apache Software Foundation
  4. * Copyright 2004-2008 Emmanouil Batsis, mailto: mbatsis at users full stop sourceforge full stop net
  5. * Copyright 2004-2008 Emmanouil Batsis, mailto: mbatsis at users full stop sourceforge full stop net
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. */
  19. /**
  20. @project JSF JavaScript Library
  21. @version 2.2
  22. @description This is the standard implementation of the JSF JavaScript Library.
  23. */
  24. // Detect if this is already loaded, and if loaded, if it's a higher version
  25. if (!((jsf && jsf.specversion && jsf.specversion >= 23000 ) &&
  26. (jsf.implversion && jsf.implversion >= 3))) {
  27. /**
  28. * <span class="changed_modified_2_2">The top level global namespace
  29. * for JavaServer Faces functionality.</span>
  30. * @name jsf
  31. * @namespace
  32. */
  33. var jsf = {};
  34. /**
  35. * <span class="changed_modified_2_2 changed_modified_2_3">The namespace for Ajax
  36. * functionality.</span>
  37. * @name jsf.ajax
  38. * @namespace
  39. * @exec
  40. */
  41. jsf.ajax = function() {
  42. var eventListeners = [];
  43. var errorListeners = [];
  44. var delayHandler = null;
  45. /**
  46. * Determine if the current browser is part of Microsoft's failed attempt at
  47. * standards modification.
  48. * @ignore
  49. */
  50. var isIE = function isIE() {
  51. if (typeof isIECache !== "undefined") {
  52. return isIECache;
  53. }
  54. isIECache =
  55. document.all && window.ActiveXObject &&
  56. navigator.userAgent.toLowerCase().indexOf("msie") > -1 &&
  57. navigator.userAgent.toLowerCase().indexOf("opera") == -1;
  58. return isIECache;
  59. };
  60. var isIECache;
  61. /**
  62. * Determine the version of IE.
  63. * @ignore
  64. */
  65. var getIEVersion = function getIEVersion() {
  66. if (typeof IEVersionCache !== "undefined") {
  67. return IEVersionCache;
  68. }
  69. if (/MSIE ([0-9]+)/.test(navigator.userAgent)) {
  70. IEVersionCache = parseInt(RegExp.$1);
  71. } else {
  72. IEVersionCache = -1;
  73. }
  74. return IEVersionCache;
  75. }
  76. var IEVersionCache;
  77. /**
  78. * Determine if loading scripts into the page executes the script.
  79. * This is instead of doing a complicated browser detection algorithm. Some do, some don't.
  80. * @returns {boolean} does including a script in the dom execute it?
  81. * @ignore
  82. */
  83. var isAutoExec = function isAutoExec() {
  84. try {
  85. if (typeof isAutoExecCache !== "undefined") {
  86. return isAutoExecCache;
  87. }
  88. var autoExecTestString = "<script>var mojarra = mojarra || {};mojarra.autoExecTest = true;</script>";
  89. var tempElement = document.createElement('span');
  90. tempElement.innerHTML = autoExecTestString;
  91. var body = document.getElementsByTagName('body')[0];
  92. var tempNode = body.appendChild(tempElement);
  93. if (mojarra && mojarra.autoExecTest) {
  94. isAutoExecCache = true;
  95. delete mojarra.autoExecTest;
  96. } else {
  97. isAutoExecCache = false;
  98. }
  99. deleteNode(tempNode);
  100. return isAutoExecCache;
  101. } catch (ex) {
  102. // OK, that didn't work, we'll have to make an assumption
  103. if (typeof isAutoExecCache === "undefined") {
  104. isAutoExecCache = false;
  105. }
  106. return isAutoExecCache;
  107. }
  108. };
  109. var isAutoExecCache;
  110. /**
  111. * @ignore
  112. */
  113. var getTransport = function getTransport(context) {
  114. var returnVal;
  115. // Here we check for encoding type for file upload(s).
  116. // This is where we would also include a check for the existence of
  117. // input file control for the current form (see hasInputFileControl
  118. // function) but IE9 (at least) seems to render controls outside of
  119. // form.
  120. if (typeof context !== 'undefined' && context !== null &&
  121. context.includesInputFile &&
  122. context.form.enctype === "multipart/form-data") {
  123. returnVal = new FrameTransport(context);
  124. return returnVal;
  125. }
  126. var methods = [
  127. function() {
  128. return new XMLHttpRequest();
  129. },
  130. function() {
  131. return new ActiveXObject('Msxml2.XMLHTTP');
  132. },
  133. function() {
  134. return new ActiveXObject('Microsoft.XMLHTTP');
  135. }
  136. ];
  137. for (var i = 0, len = methods.length; i < len; i++) {
  138. try {
  139. returnVal = methods[i]();
  140. } catch(e) {
  141. continue;
  142. }
  143. return returnVal;
  144. }
  145. throw new Error('Could not create an XHR object.');
  146. };
  147. /**
  148. * Used for iframe based communication (instead of XHR).
  149. * @ignore
  150. */
  151. var FrameTransport = function FrameTransport(context) {
  152. this.context = context;
  153. this.frame = null;
  154. this.FRAME_ID = "JSFFrameId";
  155. this.FRAME_PARTIAL_ID = "Faces-Request";
  156. this.partial = null;
  157. this.aborted = false;
  158. this.responseText = null;
  159. this.responseXML = null;
  160. this.readyState = 0;
  161. this.requestHeader = {};
  162. this.status = null;
  163. this.method = null;
  164. this.url = null;
  165. this.requestParams = null;
  166. };
  167. /**
  168. * Extends FrameTransport an adds method functionality.
  169. * @ignore
  170. */
  171. FrameTransport.prototype = {
  172. /**
  173. *@ignore
  174. */
  175. setRequestHeader:function(key, value) {
  176. if (typeof(value) !== "undefined") {
  177. this.requestHeader[key] = value;
  178. }
  179. },
  180. /**
  181. * Creates the hidden iframe and sets readystate.
  182. * @ignore
  183. */
  184. open:function(method, url, async) {
  185. this.method = method;
  186. this.url = url;
  187. this.async = async;
  188. this.frame = document.getElementById(this.FRAME_ID);
  189. if (this.frame) {
  190. this.frame.parentNode.removeChild(this.frame);
  191. this.frame = null;
  192. }
  193. if (!this.frame) {
  194. if ((!isIE() && !isIE9Plus())) {
  195. this.frame = document.createElement('iframe');
  196. this.frame.src = "about:blank";
  197. this.frame.id = this.FRAME_ID;
  198. this.frame.name = this.FRAME_ID;
  199. this.frame.type = "content";
  200. this.frame.collapsed = "true";
  201. this.frame.style = "visibility:hidden";
  202. this.frame.width = "0";
  203. this.frame.height = "0";
  204. this.frame.style = "border:0";
  205. this.frame.frameBorder = 0;
  206. document.body.appendChild(this.frame);
  207. this.frame.onload = bind(this, this.callback);
  208. } else {
  209. var div = document.createElement("div");
  210. div.id = "frameDiv";
  211. div.innerHTML = "<iframe id='" + this.FRAME_ID + "' name='" + this.FRAME_ID + "' style='display:none;' src='about:blank' type='content' onload='this.onload_cb();' ></iframe>";
  212. document.body.appendChild(div);
  213. this.frame = document.getElementById(this.FRAME_ID);
  214. this.frame.onload_cb = bind(this, this.callback);
  215. }
  216. }
  217. // Create to send "Faces-Request" param with value "partial/ajax"
  218. // For iframe approach we are sending as request parameter
  219. // For non-iframe (xhr ajax) it is sent in the request header
  220. this.partial = document.createElement("input");
  221. this.partial.setAttribute("type", "hidden");
  222. this.partial.setAttribute("id", this.FRAME_PARTIAL_ID);
  223. this.partial.setAttribute("name", this.FRAME_PARTIAL_ID);
  224. this.partial.setAttribute("value", "partial/ajax");
  225. this.context.form.appendChild(this.partial);
  226. this.readyState = 1;
  227. },
  228. /**
  229. * Sets the form target to iframe, sets up request parameters
  230. * and submits the form.
  231. * @ignore
  232. */
  233. send: function(data) {
  234. var evt = {};
  235. this.context.form.target = this.frame.name;
  236. this.context.form.method = this.method;
  237. if (this.url) {
  238. this.context.form.action = this.url;
  239. }
  240. this.readyState = 3;
  241. this.onreadystatechange(evt);
  242. var ddata = decodeURIComponent(data);
  243. var dataArray = ddata.split("&");
  244. var input;
  245. this.requestParams = new Array();
  246. for (var i=0; i<dataArray.length; i++) {
  247. var nameValue = dataArray[i].split("=");
  248. if (nameValue[0] === this.context.namingContainerPrefix + "javax.faces.source" ||
  249. nameValue[0] === this.context.namingContainerPrefix + "javax.faces.partial.event" ||
  250. nameValue[0] === this.context.namingContainerPrefix + "javax.faces.partial.execute" ||
  251. nameValue[0] === this.context.namingContainerPrefix + "javax.faces.partial.render" ||
  252. nameValue[0] === this.context.namingContainerPrefix + "javax.faces.partial.ajax" ||
  253. nameValue[0] === this.context.namingContainerPrefix + "javax.faces.behavior.event") {
  254. input = document.createElement("input");
  255. input.setAttribute("type", "hidden");
  256. input.setAttribute("id", nameValue[0]);
  257. input.setAttribute("name", nameValue[0]);
  258. input.setAttribute("value", nameValue[1]);
  259. this.context.form.appendChild(input);
  260. this.requestParams.push(nameValue[0]);
  261. }
  262. }
  263. this.requestParams.push(this.FRAME_PARTIAL_ID);
  264. this.context.form.submit();
  265. },
  266. /**
  267. *@ignore
  268. */
  269. abort:function() {
  270. this.aborted = true;
  271. },
  272. /**
  273. *@ignore
  274. */
  275. onreadystatechange:function(evt) {
  276. },
  277. /**
  278. * Extracts response from iframe document, sets readystate.
  279. * @ignore
  280. */
  281. callback: function() {
  282. if (this.aborted) {
  283. return;
  284. }
  285. var iFrameDoc;
  286. var docBody;
  287. try {
  288. var evt = {};
  289. iFrameDoc = this.frame.contentWindow.document ||
  290. this.frame.contentDocument || this.frame.document;
  291. docBody = iFrameDoc.body || iFrameDoc.documentElement;
  292. this.responseText = docBody.innerHTML;
  293. this.responseXML = iFrameDoc.XMLDocument || iFrameDoc;
  294. this.status = 201;
  295. this.readyState = 4;
  296. this.onreadystatechange(evt);
  297. } finally {
  298. this.cleanupReqParams();
  299. }
  300. },
  301. /**
  302. *@ignore
  303. */
  304. cleanupReqParams: function() {
  305. for (var i=0; i<this.requestParams.length; i++) {
  306. var elements = this.context.form.childNodes;
  307. for (var j=0; j<elements.length; j++) {
  308. if (!elements[j].type === "hidden") {
  309. continue;
  310. }
  311. if (elements[j].name === this.requestParams[i]) {
  312. var node = this.context.form.removeChild(elements[j]);
  313. node = null;
  314. break;
  315. }
  316. }
  317. }
  318. }
  319. };
  320. /**
  321. *Utility function that binds function to scope.
  322. *@ignore
  323. */
  324. var bind = function(scope, fn) {
  325. return function () {
  326. fn.apply(scope, arguments);
  327. };
  328. };
  329. /**
  330. * Utility function that determines if a file control exists
  331. * for the form.
  332. * @ignore
  333. */
  334. var hasInputFileControl = function(form) {
  335. var returnVal = false;
  336. var inputs = form.getElementsByTagName("input");
  337. if (inputs !== null && typeof inputs !=="undefined") {
  338. for (var i=0; i<inputs.length; i++) {
  339. if (inputs[i].type === "file") {
  340. returnVal = true;
  341. break;
  342. }
  343. }
  344. }
  345. return returnVal;
  346. };
  347. /**
  348. * Find instance of passed String via getElementById
  349. * @ignore
  350. */
  351. var $ = function $() {
  352. var results = [], element;
  353. for (var i = 0; i < arguments.length; i++) {
  354. element = arguments[i];
  355. if (typeof element == 'string') {
  356. element = document.getElementById(element);
  357. }
  358. results.push(element);
  359. }
  360. return results.length > 1 ? results : results[0];
  361. };
  362. /**
  363. * Get the form element which encloses the supplied element.
  364. * @param element - element to act against in search
  365. * @returns form element representing enclosing form, or first form if none found.
  366. * @ignore
  367. */
  368. var getForm = function getForm(element) {
  369. if (element) {
  370. var form = $(element);
  371. while (form) {
  372. if (form.nodeName && (form.nodeName.toLowerCase() == 'form')) {
  373. return form;
  374. }
  375. if (form.form) {
  376. return form.form;
  377. }
  378. if (form.parentNode) {
  379. form = form.parentNode;
  380. } else {
  381. form = null;
  382. }
  383. }
  384. return document.forms[0];
  385. }
  386. return null;
  387. };
  388. /**
  389. * Get an array of all JSF form elements which need their view state to be updated.
  390. * This covers at least the form that submitted the request and any form that is covered in the render target list.
  391. *
  392. * @param context An object containing the request context, including the following properties:
  393. * the source element, per call onerror callback function, per call onevent callback function, the render
  394. * instructions, the submitting form ID, the naming container ID and naming container prefix.
  395. */
  396. var getFormsToUpdate = function getFormsToUpdate(context) {
  397. var formsToUpdate = [];
  398. var add = function(element) {
  399. if (element) {
  400. if (element.nodeName
  401. && element.nodeName.toLowerCase() == "form"
  402. && element.method == "post"
  403. && element.id
  404. && element.elements
  405. && element.id.indexOf(context.namingContainerPrefix) == 0)
  406. {
  407. formsToUpdate.push(element);
  408. }
  409. else {
  410. var forms = element.getElementsByTagName("form");
  411. for (var i = 0; i < forms.length; i++) {
  412. add(forms[i]);
  413. }
  414. }
  415. }
  416. }
  417. if (context.formId) {
  418. add(document.getElementById(context.formId));
  419. }
  420. if (context.render) {
  421. if (context.render.indexOf("@all") >= 0) {
  422. add(document);
  423. }
  424. else {
  425. var clientIds = context.render.split(" ");
  426. for (var i = 0; i < clientIds.length; i++) {
  427. if (clientIds.hasOwnProperty(i)) {
  428. add(document.getElementById(clientIds[i]));
  429. }
  430. }
  431. }
  432. }
  433. return formsToUpdate;
  434. }
  435. /**
  436. * <p>Namespace given space separated parameters if necessary (only
  437. * call this if there is a namingContainerPrefix!). This
  438. * function is here for backwards compatibility with manual
  439. * jsf.ajax.request() calls written before Spec790 changes.</p>
  440. * @param parameters Spaceseparated string of parameters as
  441. * usually specified in f:ajax execute and render attributes.
  442. * @param sourceClientId The client ID of the f:ajax
  443. * source. This is to be used for prefixing relative target
  444. * client IDs.
  445. * It's expected that this already starts with
  446. * namingContainerPrefix.
  447. * @param namingContainerPrefix The naming container prefix (the
  448. * view root ID suffixed with separator character).
  449. * This is to be used for prefixing absolute target client IDs.
  450. * @ignore
  451. */
  452. var namespaceParametersIfNecessary = function namespaceParametersIfNecessary(parameters, sourceClientId, namingContainerPrefix) {
  453. if (sourceClientId.indexOf(namingContainerPrefix) != 0) {
  454. return parameters; // Unexpected source client ID; let's silently do nothing.
  455. }
  456. var targetClientIds = parameters.replace(/^\s+|\s+$/g, '').split(/\s+/g);
  457. for (var i = 0; i < targetClientIds.length; i++) {
  458. var targetClientId = targetClientIds[i];
  459. if (targetClientId.indexOf(jsf.separatorchar) == 0) {
  460. targetClientId = targetClientId.substring(1);
  461. if (targetClientId.indexOf(namingContainerPrefix) != 0) {
  462. targetClientId = namingContainerPrefix + targetClientId;
  463. }
  464. }
  465. else if (targetClientId.indexOf(namingContainerPrefix) != 0) {
  466. var parentClientId = sourceClientId.substring(0, sourceClientId.lastIndexOf(jsf.separatorchar));
  467. if (namingContainerPrefix + targetClientId == parentClientId) {
  468. targetClientId = parentClientId;
  469. }
  470. else {
  471. targetClientId = parentClientId + jsf.separatorchar + targetClientId;
  472. }
  473. }
  474. targetClientIds[i] = targetClientId;
  475. }
  476. return targetClientIds.join(' ');
  477. };
  478. /**
  479. * Check if a value exists in an array
  480. * @ignore
  481. */
  482. var isInArray = function isInArray(array, value) {
  483. for (var i = 0; i < array.length; i++) {
  484. if (array[i] === value) {
  485. return true;
  486. }
  487. }
  488. return false;
  489. };
  490. /**
  491. * Evaluate JavaScript code in a global context.
  492. * @param src JavaScript code to evaluate
  493. * @ignore
  494. */
  495. var globalEval = function globalEval(src) {
  496. if (window.execScript) {
  497. window.execScript(src);
  498. return;
  499. }
  500. // We have to wrap the call in an anon function because of a firefox bug, where this is incorrectly set
  501. // We need to explicitly call window.eval because of a Chrome peculiarity
  502. /**
  503. * @ignore
  504. */
  505. var fn = function() {
  506. window.eval.call(window,src);
  507. };
  508. fn();
  509. };
  510. /**
  511. * Get all scripts from supplied string, return them as an array for later processing.
  512. * @param str
  513. * @returns {array} of script text
  514. * @ignore
  515. */
  516. var getScripts = function getScripts(str) {
  517. // Regex to find all scripts in a string
  518. var findscripts = /<script[^>]*>([\S\s]*?)<\/script>/igm;
  519. // Regex to find one script, to isolate it's content [2] and attributes [1]
  520. var findscript = /<script([^>]*)>([\S\s]*?)<\/script>/im;
  521. // Regex to find type attribute
  522. var findtype = /type="([\S]*?)"/im;
  523. var initialnodes = [];
  524. var scripts = [];
  525. initialnodes = str.match(findscripts);
  526. while (!!initialnodes && initialnodes.length > 0) {
  527. var scriptStr = [];
  528. scriptStr = initialnodes.shift().match(findscript);
  529. // check the type - skip if it not javascript type
  530. var type = [];
  531. type = scriptStr[1].match(findtype);
  532. if ( !!type && type[1]) {
  533. if (type[1] !== "text/javascript") {
  534. continue;
  535. }
  536. }
  537. scripts.push(scriptStr);
  538. }
  539. return scripts;
  540. };
  541. var removeScripts = function removeScripts(str) {
  542. return str.replace(/<script[^>]*type="text\/javascript"[^>]*>([\S\s]*?)<\/script>/igm,"");
  543. };
  544. /**
  545. * Run an array of script nodes,
  546. * @param scripts Array of script nodes.
  547. * @ignore
  548. */
  549. var runScripts = function runScripts(scripts) {
  550. if (!scripts || scripts.length === 0) {
  551. return;
  552. }
  553. var loadedScripts = document.getElementsByTagName("script");
  554. var loadedScriptUrls = [];
  555. for (var i = 0; i < loadedScripts.length; i++) {
  556. var scriptNode = loadedScripts[i];
  557. var url = scriptNode.getAttribute("src");
  558. if (url) {
  559. loadedScriptUrls.push(url);
  560. }
  561. }
  562. var head = document.head || document.getElementsByTagName('head')[0] || document.documentElement;
  563. runScript(head, loadedScriptUrls, scripts, 0);
  564. };
  565. /**
  566. * Run script at given index.
  567. * @param head Document's head.
  568. * @param loadedScriptUrls URLs of scripts which are already loaded.
  569. * @param scripts Array of script nodes.
  570. * @param index Index of script to be loaded.
  571. * @ignore
  572. */
  573. var runScript = function runScript(head, loadedScriptUrls, scripts, index) {
  574. if (index >= scripts.length) {
  575. return;
  576. }
  577. // Regex to find src attribute
  578. var findsrc = /src="([\S]*?)"/im;
  579. // Regex to remove leading cruft
  580. var stripStart = /^\s*(<!--)*\s*(\/\/)*\s*(\/\*)*\s*\n*\**\n*\s*\*.*\n*\s*\*\/(<!\[CDATA\[)*/;
  581. var scriptStr = scripts[index];
  582. var src = scriptStr[1].match(findsrc);
  583. var scriptLoadedViaUrl = false;
  584. if (!!src && src[1]) {
  585. // if this is a file, load it
  586. var url = unescapeHTML(src[1]);
  587. // if this is already loaded, don't load it
  588. // it's never necessary, and can make debugging difficult
  589. if (loadedScriptUrls.indexOf(url) < 0) {
  590. // create script node
  591. var scriptNode = document.createElement('script');
  592. var parserElement = document.createElement('div');
  593. parserElement.innerHTML = scriptStr[0];
  594. cloneAttributes(scriptNode, parserElement.firstChild);
  595. deleteNode(parserElement);
  596. scriptNode.type = 'text/javascript';
  597. scriptNode.src = url; // add the src to the script node
  598. scriptNode.onload = scriptNode.onreadystatechange = function(_, abort) {
  599. if (abort || !scriptNode.readyState || /loaded|complete/.test(scriptNode.readyState)) {
  600. scriptNode.onload = scriptNode.onreadystatechange = null; // IE memory leak fix.
  601. scriptNode = null;
  602. runScript(head, loadedScriptUrls, scripts, index + 1); // Run next script.
  603. }
  604. };
  605. head.insertBefore(scriptNode, null); // add it to end of the head (and don't remove it)
  606. scriptLoadedViaUrl = true;
  607. }
  608. } else if (!!scriptStr && scriptStr[2]) {
  609. // else get content of tag, without leading CDATA and such
  610. var script = scriptStr[2].replace(stripStart,"");
  611. if (!!script) {
  612. // create script node
  613. var scriptNode = document.createElement('script');
  614. scriptNode.type = 'text/javascript';
  615. scriptNode.text = script; // add the code to the script node
  616. head.appendChild(scriptNode); // add it to the head
  617. head.removeChild(scriptNode); // then remove it
  618. }
  619. }
  620. if (!scriptLoadedViaUrl) {
  621. runScript(head, loadedScriptUrls, scripts, index + 1); // Run next script.
  622. }
  623. };
  624. /**
  625. * Get all stylesheets from supplied string and run them all.
  626. * @param str
  627. * @ignore
  628. */
  629. var runStylesheets = function runStylesheets(str) {
  630. // Regex to find all links in a string
  631. var findlinks = /<link[^>]*\/>/igm;
  632. // Regex to find one link, to isolate its attributes [1]
  633. var findlink = /<link([^>]*)\/>/im;
  634. // Regex to find type attribute
  635. var findtype = /type="([\S]*?)"/im;
  636. var findhref = /href="([\S]*?)"/im;
  637. var stylesheets = [];
  638. var loadedStylesheetUrls = null;
  639. var head = document.head || document.getElementsByTagName('head')[0] || document.documentElement;
  640. var parserElement = null;
  641. var initialnodes = str.match(findlinks);
  642. while (!!initialnodes && initialnodes.length > 0) {
  643. var linkStr = initialnodes.shift().match(findlink);
  644. // check the type - skip if it not css type
  645. var type = linkStr[1].match(findtype);
  646. if (!type || type[1] !== "text/css") {
  647. continue;
  648. }
  649. var href = linkStr[1].match(findhref);
  650. if (!!href && href[1]) {
  651. if (loadedStylesheetUrls === null) {
  652. var loadedLinks = document.getElementsByTagName("link");
  653. loadedStylesheetUrls = [];
  654. for (var i = 0; i < loadedLinks.length; i++) {
  655. var linkNode = loadedLinks[i];
  656. if (linkNode.getAttribute("type") === "text/css") {
  657. var url = linkNode.getAttribute("href");
  658. if (url) {
  659. loadedStylesheetUrls.push(url);
  660. }
  661. }
  662. }
  663. }
  664. var url = unescapeHTML(href[1]);
  665. if (loadedStylesheetUrls.indexOf(url) < 0) {
  666. // create stylesheet node
  667. parserElement = parserElement !== null ? parserElement : document.createElement('div');
  668. parserElement.innerHTML = linkStr[0];
  669. var linkNode = parserElement.firstChild;
  670. linkNode.type = 'text/css';
  671. linkNode.rel = 'stylesheet';
  672. linkNode.href = url;
  673. head.insertBefore(linkNode, null); // add it to end of the head (and don't remove it)
  674. }
  675. }
  676. }
  677. deleteNode(parserElement);
  678. };
  679. /**
  680. * Replace DOM element with a new tagname and supplied innerHTML
  681. * @param element element to replace
  682. * @param tempTagName new tag name to replace with
  683. * @param src string new content for element
  684. * @ignore
  685. */
  686. var elementReplaceStr = function elementReplaceStr(element, tempTagName, src) {
  687. var temp = document.createElement(tempTagName);
  688. if (element.id) {
  689. temp.id = element.id;
  690. }
  691. // Creating a head element isn't allowed in IE, and faulty in most browsers,
  692. // so it is not allowed
  693. if (element.nodeName.toLowerCase() === "head") {
  694. throw new Error("Attempted to replace a head element - this is not allowed.");
  695. } else {
  696. var scripts = [];
  697. if (isAutoExec()) {
  698. temp.innerHTML = src;
  699. } else {
  700. // Get scripts from text
  701. scripts = getScripts(src);
  702. // Remove scripts from text
  703. src = removeScripts(src);
  704. temp.innerHTML = src;
  705. }
  706. }
  707. replaceNode(temp, element);
  708. cloneAttributes(temp, element);
  709. runScripts(scripts);
  710. };
  711. /**
  712. * Get a string with the concatenated values of all string nodes under the given node
  713. * @param oNode the given DOM node
  714. * @param deep boolean - whether to recursively scan the children nodes of the given node for text as well. Default is <code>false</code>
  715. * @ignore
  716. * Note: This code originally from Sarissa: http://dev.abiss.gr/sarissa
  717. * It has been modified to fit into the overall codebase
  718. */
  719. var getText = function getText(oNode, deep) {
  720. var Node = {ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4,
  721. ENTITY_REFERENCE_NODE: 5, ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7,
  722. COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10,
  723. DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12};
  724. var s = "";
  725. var nodes = oNode.childNodes;
  726. for (var i = 0; i < nodes.length; i++) {
  727. var node = nodes[i];
  728. var nodeType = node.nodeType;
  729. if (nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE) {
  730. s += node.data;
  731. } else if (deep === true && (nodeType == Node.ELEMENT_NODE ||
  732. nodeType == Node.DOCUMENT_NODE ||
  733. nodeType == Node.DOCUMENT_FRAGMENT_NODE)) {
  734. s += getText(node, true);
  735. }
  736. }
  737. return s;
  738. };
  739. var PARSED_OK = "Document contains no parsing errors";
  740. var PARSED_EMPTY = "Document is empty";
  741. var PARSED_UNKNOWN_ERROR = "Not well-formed or other error";
  742. var getParseErrorText;
  743. if (isIE()) {
  744. /**
  745. * Note: This code orginally from Sarissa: http://dev.abiss.gr/sarissa
  746. * @ignore
  747. */
  748. getParseErrorText = function (oDoc) {
  749. var parseErrorText = PARSED_OK;
  750. if (oDoc && oDoc.parseError && oDoc.parseError.errorCode && oDoc.parseError.errorCode !== 0) {
  751. parseErrorText = "XML Parsing Error: " + oDoc.parseError.reason +
  752. "\nLocation: " + oDoc.parseError.url +
  753. "\nLine Number " + oDoc.parseError.line + ", Column " +
  754. oDoc.parseError.linepos +
  755. ":\n" + oDoc.parseError.srcText +
  756. "\n";
  757. for (var i = 0; i < oDoc.parseError.linepos; i++) {
  758. parseErrorText += "-";
  759. }
  760. parseErrorText += "^\n";
  761. }
  762. else if (oDoc.documentElement === null) {
  763. parseErrorText = PARSED_EMPTY;
  764. }
  765. return parseErrorText;
  766. };
  767. } else { // (non-IE)
  768. /**
  769. * <p>Returns a human readable description of the parsing error. Useful
  770. * for debugging. Tip: append the returned error string in a &lt;pre&gt;
  771. * element if you want to render it.</p>
  772. * @param oDoc The target DOM document
  773. * @returns {String} The parsing error description of the target Document in
  774. * human readable form (preformated text)
  775. * @ignore
  776. * Note: This code orginally from Sarissa: http://dev.abiss.gr/sarissa
  777. */
  778. getParseErrorText = function (oDoc) {
  779. var parseErrorText = PARSED_OK;
  780. if ((!oDoc) || (!oDoc.documentElement)) {
  781. parseErrorText = PARSED_EMPTY;
  782. } else if (oDoc.documentElement.tagName == "parsererror") {
  783. parseErrorText = oDoc.documentElement.firstChild.data;
  784. parseErrorText += "\n" + oDoc.documentElement.firstChild.nextSibling.firstChild.data;
  785. } else if (oDoc.getElementsByTagName("parsererror").length > 0) {
  786. var parsererror = oDoc.getElementsByTagName("parsererror")[0];
  787. parseErrorText = getText(parsererror, true) + "\n";
  788. } else if (oDoc.parseError && oDoc.parseError.errorCode !== 0) {
  789. parseErrorText = PARSED_UNKNOWN_ERROR;
  790. }
  791. return parseErrorText;
  792. };
  793. }
  794. if ((typeof(document.importNode) == "undefined") && isIE()) {
  795. try {
  796. /**
  797. * Implementation of importNode for the context window document in IE.
  798. * If <code>oNode</code> is a TextNode, <code>bChildren</code> is ignored.
  799. * @param oNode the Node to import
  800. * @param bChildren whether to include the children of oNode
  801. * @returns the imported node for further use
  802. * @ignore
  803. * Note: This code orginally from Sarissa: http://dev.abiss.gr/sarissa
  804. */
  805. document.importNode = function(oNode, bChildren) {
  806. var tmp;
  807. if (oNode.nodeName == '#text') {
  808. return document.createTextNode(oNode.data);
  809. }
  810. else {
  811. if (oNode.nodeName == "tbody" || oNode.nodeName == "tr") {
  812. tmp = document.createElement("table");
  813. }
  814. else if (oNode.nodeName == "td") {
  815. tmp = document.createElement("tr");
  816. }
  817. else if (oNode.nodeName == "option") {
  818. tmp = document.createElement("select");
  819. }
  820. else {
  821. tmp = document.createElement("div");
  822. }
  823. if (bChildren) {
  824. tmp.innerHTML = oNode.xml ? oNode.xml : oNode.outerHTML;
  825. } else {
  826. tmp.innerHTML = oNode.xml ? oNode.cloneNode(false).xml : oNode.cloneNode(false).outerHTML;
  827. }
  828. return tmp.getElementsByTagName("*")[0];
  829. }
  830. };
  831. } catch(e) {
  832. }
  833. }
  834. // Setup Node type constants for those browsers that don't have them (IE)
  835. var Node = {ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4,
  836. ENTITY_REFERENCE_NODE: 5, ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7,
  837. COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10,
  838. DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12};
  839. // PENDING - add support for removing handlers added via DOM 2 methods
  840. /**
  841. * Delete all events attached to a node
  842. * @param node
  843. * @ignore
  844. */
  845. var clearEvents = function clearEvents(node) {
  846. if (!node) {
  847. return;
  848. }
  849. // don't do anything for text and comment nodes - unnecessary
  850. if (node.nodeType == Node.TEXT_NODE || node.nodeType == Node.COMMENT_NODE) {
  851. return;
  852. }
  853. var events = ['abort', 'blur', 'change', 'error', 'focus', 'load', 'reset', 'resize', 'scroll', 'select', 'submit', 'unload',
  854. 'keydown', 'keypress', 'keyup', 'click', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'dblclick' ];
  855. try {
  856. for (var e in events) {
  857. if (events.hasOwnProperty(e)) {
  858. node[e] = null;
  859. }
  860. }
  861. } catch (ex) {
  862. // it's OK if it fails, at least we tried
  863. }
  864. };
  865. /**
  866. * Determine if this current browser is IE9 or greater
  867. * @param node
  868. * @ignore
  869. */
  870. var isIE9Plus = function isIE9Plus() {
  871. var iev = getIEVersion();
  872. if (iev >= 9) {
  873. return true;
  874. } else {
  875. return false;
  876. }
  877. }
  878. /**
  879. * Deletes node
  880. * @param node
  881. * @ignore
  882. */
  883. var deleteNode = function deleteNode(node) {
  884. if (!node) {
  885. return;
  886. }
  887. if (!node.parentNode) {
  888. // if there's no parent, there's nothing to do
  889. return;
  890. }
  891. if (!isIE() || (isIE() && isIE9Plus())) {
  892. // nothing special required
  893. node.parentNode.removeChild(node);
  894. return;
  895. }
  896. // The rest of this code is specialcasing for IE
  897. if (node.nodeName.toLowerCase() === "body") {
  898. // special case for removing body under IE.
  899. deleteChildren(node);
  900. try {
  901. node.outerHTML = '';
  902. } catch (ex) {
  903. // fails under some circumstances, but not in RI
  904. // supplied responses. If we've gotten here, it's
  905. // fairly safe to leave a lingering body tag rather than
  906. // fail outright
  907. }
  908. return;
  909. }
  910. var temp = node.ownerDocument.createElement('div');
  911. var parent = node.parentNode;
  912. temp.appendChild(parent.removeChild(node));
  913. // Now clean up the temporary element
  914. try {
  915. temp.outerHTML = ''; //prevent leak in IE
  916. } catch (ex) {
  917. // at least we tried. Fails in some circumstances,
  918. // but not in RI supplied responses. Better to leave a lingering
  919. // temporary div than to fail outright.
  920. }
  921. };
  922. /**
  923. * Deletes all children of a node
  924. * @param node
  925. * @ignore
  926. */
  927. var deleteChildren = function deleteChildren(node) {
  928. if (!node) {
  929. return;
  930. }
  931. for (var x = node.childNodes.length - 1; x >= 0; x--) { //delete all of node's children
  932. var childNode = node.childNodes[x];
  933. deleteNode(childNode);
  934. }
  935. };
  936. /**
  937. * <p> Copies the childNodes of nodeFrom to nodeTo</p>
  938. *
  939. * @param nodeFrom the Node to copy the childNodes from
  940. * @param nodeTo the Node to copy the childNodes to
  941. * @ignore
  942. * Note: This code originally from Sarissa: http://dev.abiss.gr/sarissa
  943. * It has been modified to fit into the overall codebase
  944. */
  945. var copyChildNodes = function copyChildNodes(nodeFrom, nodeTo) {
  946. if ((!nodeFrom) || (!nodeTo)) {
  947. throw "Both source and destination nodes must be provided";
  948. }
  949. deleteChildren(nodeTo);
  950. var nodes = nodeFrom.childNodes;
  951. // if within the same doc, just move, else copy and delete
  952. if (nodeFrom.ownerDocument == nodeTo.ownerDocument) {
  953. while (nodeFrom.firstChild) {
  954. nodeTo.appendChild(nodeFrom.firstChild);
  955. }
  956. } else {
  957. var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;
  958. var i;
  959. if (typeof(ownerDoc.importNode) != "undefined") {
  960. for (i = 0; i < nodes.length; i++) {
  961. nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));
  962. }
  963. } else {
  964. for (i = 0; i < nodes.length; i++) {
  965. nodeTo.appendChild(nodes[i].cloneNode(true));
  966. }
  967. }
  968. }
  969. };
  970. /**
  971. * Replace one node with another. Necessary for handling IE memory leak.
  972. * @param node
  973. * @param newNode
  974. * @ignore
  975. */
  976. var replaceNode = function replaceNode(newNode, node) {
  977. if(isIE()){
  978. node.parentNode.insertBefore(newNode, node);
  979. deleteNode(node);
  980. } else {
  981. node.parentNode.replaceChild(newNode, node);
  982. }
  983. };
  984. /**
  985. * @ignore
  986. */
  987. var propertyToAttribute = function propertyToAttribute(name) {
  988. if (name === 'className') {
  989. return 'class';
  990. } else if (name === 'xmllang') {
  991. return 'xml:lang';
  992. } else {
  993. return name.toLowerCase();
  994. }
  995. };
  996. /**
  997. * @ignore
  998. */
  999. var isFunctionNative = function isFunctionNative(func) {
  1000. return /^\s*function[^{]+{\s*\[native code\]\s*}\s*$/.test(String(func));
  1001. };
  1002. /**
  1003. * @ignore
  1004. */
  1005. var detectAttributes = function detectAttributes(element) {
  1006. //test if 'hasAttribute' method is present and its native code is intact
  1007. //for example, Prototype can add its own implementation if missing
  1008. if (element.hasAttribute && isFunctionNative(element.hasAttribute)) {
  1009. return function(name) {
  1010. return element.hasAttribute(name);
  1011. }
  1012. } else {
  1013. try {
  1014. //when accessing .getAttribute method without arguments does not throw an error then the method is not available
  1015. element.getAttribute;
  1016. var html = element.outerHTML;
  1017. var startTag = html.match(/^<[^>]*>/)[0];
  1018. return function(name) {
  1019. return startTag.indexOf(name + '=') > -1;
  1020. }
  1021. } catch (ex) {
  1022. return function(name) {
  1023. return element.getAttribute(name);
  1024. }
  1025. }
  1026. }
  1027. };
  1028. /**
  1029. * copy all attributes from one element to another - except id
  1030. * @param target element to copy attributes to
  1031. * @param source element to copy attributes from
  1032. * @ignore
  1033. */
  1034. var cloneAttributes = function cloneAttributes(target, source) {
  1035. // enumerate core element attributes - without 'dir' as special case
  1036. var coreElementProperties = ['className', 'title', 'lang', 'xmllang'];
  1037. // enumerate additional input element attributes
  1038. var inputElementProperties = [
  1039. 'name', 'value', 'size', 'maxLength', 'src', 'alt', 'useMap', 'tabIndex', 'accessKey', 'accept', 'type'
  1040. ];
  1041. // enumerate additional boolean input attributes
  1042. var inputElementBooleanProperties = [
  1043. 'checked', 'disabled', 'readOnly'
  1044. ];
  1045. // Enumerate all the names of the event listeners
  1046. var listenerNames =
  1047. [ 'onclick', 'ondblclick', 'onmousedown', 'onmousemove', 'onmouseout',
  1048. 'onmouseover', 'onmouseup', 'onkeydown', 'onkeypress', 'onkeyup',
  1049. 'onhelp', 'onblur', 'onfocus', 'onchange', 'onload', 'onunload', 'onabort',
  1050. 'onreset', 'onselect', 'onsubmit'
  1051. ];
  1052. var sourceAttributeDetector = detectAttributes(source);
  1053. var targetAttributeDetector = detectAttributes(target);
  1054. var isInputElement = target.nodeName.toLowerCase() === 'input';
  1055. var propertyNames = isInputElement ? coreElementProperties.concat(inputElementProperties) : coreElementProperties;
  1056. var isXML = !source.ownerDocument.contentType || source.ownerDocument.contentType == 'text/xml';
  1057. for (var iIndex = 0, iLength = propertyNames.length; iIndex < iLength; iIndex++) {
  1058. var propertyName = propertyNames[iIndex];
  1059. var attributeName = propertyToAttribute(propertyName);
  1060. if (sourceAttributeDetector(attributeName)) {
  1061. //With IE 7 (quirks or standard mode) and IE 8/9 (quirks mode only),
  1062. //you cannot get the attribute using 'class'. You must use 'className'
  1063. //which is the same value you use to get the indexed property. The only
  1064. //reliable way to detect this (without trying to evaluate the browser
  1065. //mode and version) is to compare the two return values using 'className'
  1066. //to see if they exactly the same. If they are, then use the property
  1067. //name when using getAttribute.
  1068. if( attributeName == 'class'){
  1069. if( isIE() && (source.getAttribute(propertyName) === source[propertyName]) ){
  1070. attributeName = propertyName;
  1071. }
  1072. }
  1073. var newValue = isXML ? source.getAttribute(attributeName) : source[propertyName];
  1074. var oldValue = target[propertyName];
  1075. if (oldValue != newValue) {
  1076. target[propertyName] = newValue;
  1077. }
  1078. } else {
  1079. //setting property to '' seems to be the only cross-browser method for removing an attribute
  1080. //avoid setting 'value' property to '' for checkbox and radio input elements because then the
  1081. //'value' is used instead of the 'checked' property when the form is serialized by the browser
  1082. if (attributeName == "value" && (target.type != 'checkbox' && target.type != 'radio')) {
  1083. target[propertyName] = '';
  1084. }
  1085. target.removeAttribute(attributeName);
  1086. }
  1087. }
  1088. var booleanPropertyNames = isInputElement ? inputElementBooleanProperties : [];
  1089. for (var jIndex = 0, jLength = booleanPropertyNames.length; jIndex < jLength; jIndex++) {
  1090. var booleanPropertyName = booleanPropertyNames[jIndex];
  1091. var newBooleanValue = source[booleanPropertyName];
  1092. var oldBooleanValue = target[booleanPropertyName];
  1093. if (oldBooleanValue != newBooleanValue) {
  1094. target[booleanPropertyName] = newBooleanValue;
  1095. }
  1096. }
  1097. //'style' attribute special case
  1098. if (sourceAttributeDetector('style')) {
  1099. var newStyle;
  1100. var oldStyle;
  1101. if (isIE()) {
  1102. newStyle = source.style.cssText;
  1103. oldStyle = target.style.cssText;
  1104. if (newStyle != oldStyle) {
  1105. target.style.cssText = newStyle;
  1106. }
  1107. } else {
  1108. newStyle = source.getAttribute('style');
  1109. oldStyle = target.getAttribute('style');
  1110. if (newStyle != oldStyle) {
  1111. target.setAttribute('style', newStyle);
  1112. }
  1113. }
  1114. } else if (targetAttributeDetector('style')){
  1115. target.removeAttribute('style');
  1116. }
  1117. // Special case for 'dir' attribute
  1118. if (!isIE() && source.dir != target.dir) {
  1119. if (sourceAttributeDetector('dir')) {
  1120. target.dir = source.dir;
  1121. } else if (targetAttributeDetector('dir')) {
  1122. target.dir = '';
  1123. }
  1124. }
  1125. for (var lIndex = 0, lLength = listenerNames.length; lIndex < lLength; lIndex++) {
  1126. var name = listenerNames[lIndex];
  1127. target[name] = source[name] ? source[name] : null;
  1128. if (source[name]) {
  1129. source[name] = null;
  1130. }
  1131. }
  1132. //clone HTML5 data-* attributes
  1133. try{
  1134. var targetDataset = target.dataset;
  1135. var sourceDataset = source.dataset;
  1136. if (targetDataset || sourceDataset) {
  1137. //cleanup the dataset
  1138. for (var tp in targetDataset) {
  1139. delete targetDataset[tp];
  1140. }
  1141. //copy dataset's properties
  1142. for (var sp in sourceDataset) {
  1143. targetDataset[sp] = sourceDataset[sp];
  1144. }
  1145. }
  1146. } catch (ex) {
  1147. //most probably dataset properties are not supported
  1148. }
  1149. };
  1150. /**
  1151. * Replace an element from one document into another
  1152. * @param newElement new element to put in document
  1153. * @param origElement original element to replace
  1154. * @ignore
  1155. */
  1156. var elementReplace = function elementReplace(newElement, origElement) {
  1157. copyChildNodes(newElement, origElement);
  1158. // sadly, we have to reparse all over again
  1159. // to reregister the event handlers and styles
  1160. // PENDING do some performance tests on large pages
  1161. origElement.innerHTML = origElement.innerHTML;
  1162. try {
  1163. cloneAttributes(origElement, newElement);
  1164. } catch (ex) {
  1165. // if in dev mode, report an error, else try to limp onward
  1166. if (jsf.getProjectStage() == "Development") {
  1167. throw new Error("Error updating attributes");
  1168. }
  1169. }
  1170. deleteNode(newElement);
  1171. };
  1172. /**
  1173. * Create a new document, then select the body element within it
  1174. * @param docStr Stringified version of document to create
  1175. * @return element the body element
  1176. * @ignore
  1177. */
  1178. var getBodyElement = function getBodyElement(docStr) {
  1179. var doc; // intermediate document we'll create
  1180. var body; // Body element to return
  1181. if (typeof DOMParser !== "undefined") { // FF, S, Chrome
  1182. doc = (new DOMParser()).parseFromString(docStr, "text/xml");
  1183. } else if (typeof ActiveXObject !== "undefined") { // IE
  1184. doc = new ActiveXObject("MSXML2.DOMDocument");
  1185. doc.loadXML(docStr);
  1186. } else {
  1187. throw new Error("You don't seem to be running a supported browser");
  1188. }
  1189. if (getParseErrorText(doc) !== PARSED_OK) {
  1190. throw new Error(getParseErrorText(doc));
  1191. }
  1192. body = doc.getElementsByTagName("body")[0];
  1193. if (!body) {
  1194. throw new Error("Can't find body tag in returned document.");
  1195. }
  1196. return body;
  1197. };
  1198. /**
  1199. * Find encoded url field for a given form.
  1200. * @param form
  1201. * @ignore
  1202. */
  1203. var getEncodedUrlElement = function getEncodedUrlElement(form) {
  1204. var encodedUrlElement = form['javax.faces.encodedURL'];
  1205. if (encodedUrlElement) {
  1206. return encodedUrlElement;
  1207. } else {
  1208. var formElements = form.elements;
  1209. for (var i = 0, length = formElements.length; i < length; i++) {
  1210. var formElement = formElements[i];
  1211. if (formElement.name && (formElement.name.indexOf('javax.faces.encodedURL') >= 0)) {
  1212. return formElement;
  1213. }
  1214. }
  1215. }
  1216. return undefined;
  1217. };
  1218. /**
  1219. * Update hidden state fields from the server into the DOM for any JSF forms which need to be updated.
  1220. * This covers at least the form that submitted the request and any form that is covered in the render target list.
  1221. *
  1222. * @param updateElement The update element of partial response holding the state value.
  1223. * @param context An object containing the request context, including the following properties:
  1224. * the source element, per call onerror callback function, per call onevent callback function, the render
  1225. * instructions, the submitting form ID, the naming container ID and naming container prefix.
  1226. * @param hiddenStateFieldName The hidden state field name, e.g. javax.faces.ViewState or javax.faces.ClientWindow
  1227. */
  1228. var updateHiddenStateFields = function updateHiddenStateFields(updateElement, context, hiddenStateFieldName) {
  1229. var firstChild = updateElement.firstChild;
  1230. var state = (typeof firstChild.wholeText !== 'undefined') ? firstChild.wholeText : firstChild.nodeValue;
  1231. var formsToUpdate = getFormsToUpdate(context);
  1232. for (var i = 0; i < formsToUpdate.length; i++) {
  1233. var formToUpdate = formsToUpdate[i];
  1234. var field = getHiddenStateField(formToUpdate, hiddenStateFieldName, context.namingContainerPrefix);
  1235. if (typeof field == "undefined") {
  1236. field = document.createElement("input");
  1237. field.type = "hidden";
  1238. field.name = context.namingContainerPrefix + hiddenStateFieldName;
  1239. formToUpdate.appendChild(field);
  1240. }
  1241. field.value = state;
  1242. }
  1243. }
  1244. /**
  1245. * Find hidden state field for a given form.
  1246. * @param form The form to find hidden state field in.
  1247. * @param hiddenStateFieldName The hidden state field name, e.g. javax.faces.ViewState or javax.faces.ClientWindow
  1248. * @param namingContainerPrefix The naming container prefix, if any (the view root ID suffixed with separator character).
  1249. * @ignore
  1250. */
  1251. var getHiddenStateField = function getHiddenStateField(form, hiddenStateFieldName, namingContainerPrefix) {
  1252. namingContainerPrefix = namingContainerPrefix || "";
  1253. var field = form[namingContainerPrefix + hiddenStateFieldName];
  1254. if (field) {
  1255. return field;
  1256. }
  1257. else {
  1258. var formElements = form.elements;
  1259. for (var i = 0, length = formElements.length; i < length; i++) {
  1260. var formElement = formElements[i];
  1261. if (formElement.name && (formElement.name.indexOf(hiddenStateFieldName) >= 0)) {
  1262. return formElement;
  1263. }
  1264. }
  1265. }
  1266. return undefined;
  1267. };
  1268. /**
  1269. * Do update.
  1270. * @param updateElement The update element of partial response.
  1271. * @param context An object containing the request context, including the following properties:
  1272. * the source element, per call onerror callback function, per call onevent callback function, the render
  1273. * instructions, the submitting form ID, the naming container ID and naming container prefix.
  1274. * @ignore
  1275. */
  1276. var doUpdate = function doUpdate(updateElement, context) {
  1277. var id, content, markup;
  1278. var scripts = []; // temp holding value for array of script nodes
  1279. id = updateElement.getAttribute('id');
  1280. var viewStateRegex = new RegExp(context.namingContainerPrefix + "javax.faces.ViewState" + jsf.separatorchar + ".+$");
  1281. var windowIdRegex = new RegExp(context.namingContainerPrefix + "javax.faces.ClientWindow" + jsf.separatorchar + ".+$");
  1282. if (id.match(viewStateRegex)) {
  1283. updateHiddenStateFields(updateElement, context, "javax.faces.ViewState");
  1284. return;
  1285. } else if (id.match(windowIdRegex)) {
  1286. updateHiddenStateFields(updateElement, context, "javax.faces.ClientWindow");
  1287. return;
  1288. }
  1289. // join the CDATA sections in the markup
  1290. markup = '';
  1291. for (var j = 0; j < updateElement.childNodes.length; j++) {
  1292. content = updateElement.childNodes[j];
  1293. markup += content.nodeValue;
  1294. }
  1295. var src = markup;
  1296. // If our special render all markup is present..
  1297. if (id === "javax.faces.ViewRoot" || id === "javax.faces.ViewBody") {
  1298. // spec790: If UIViewRoot is currently being updated,
  1299. // then it means that ajax navigation has taken place.
  1300. // So, ensure that context.render has correct value for this condition,
  1301. // because this is not necessarily correclty specified during the request.
  1302. context.render = "@all";
  1303. var bodyStartEx = new RegExp("< *body[^>]*>", "gi");
  1304. var bodyEndEx = new RegExp("< */ *body[^>]*>", "gi");
  1305. var newsrc;
  1306. var docBody = document.getElementsByTagName("body")[0];
  1307. var bodyStart = bodyStartEx.exec(src);
  1308. if (bodyStart !== null) { // replace body tag
  1309. // First, try with XML manipulation
  1310. try {
  1311. runStylesheets(src);
  1312. // Get scripts from text
  1313. scripts = getScripts(src);
  1314. // Remove scripts from text
  1315. newsrc = removeScripts(src);
  1316. elementReplace(getBodyElement(newsrc), docBody);
  1317. runScripts(scripts);
  1318. } catch (e) {
  1319. // OK, replacing the body didn't work with XML - fall back to quirks mode insert
  1320. var srcBody, bodyEnd;
  1321. // if src contains </body>
  1322. bodyEnd = bodyEndEx.exec(src);
  1323. if (bodyEnd !== null) {
  1324. srcBody = src.substring(bodyStartEx.lastIndex, bodyEnd.index);
  1325. } else { // can't find the </body> tag, punt
  1326. srcBody = src.substring(bodyStartEx.lastIndex);
  1327. }
  1328. // replace body contents with innerHTML - note, script handling happens within function
  1329. elementReplaceStr(docBody, "body", srcBody);
  1330. }
  1331. } else { // replace body contents with innerHTML - note, script handling happens within function
  1332. elementReplaceStr(docBody, "body", src);
  1333. }
  1334. } else if (id === "javax.faces.ViewHead") {
  1335. throw new Error("javax.faces.ViewHead not supported - browsers cannot reliably replace the head's contents");
  1336. } else if (id === "javax.faces.Resource") {
  1337. runStylesheets(src);
  1338. scripts = getScripts(src);
  1339. runScripts(scripts);
  1340. } else {
  1341. var element = $(id);
  1342. if (!element) {
  1343. throw new Error("During update: " + id + " not found");
  1344. }
  1345. if (context.namingContainerId && id == context.namingContainerId) {
  1346. // spec790: If UIViewRoot is a NamingContainer and this is currently being updated,
  1347. // then it means that ajax navigation has taken place.
  1348. // So, ensure that context.render has correct value for this condition,
  1349. // because this is not necessarily correclty specified during the request.
  1350. context.render = context.namingContainerId;
  1351. }
  1352. var parent = element.parentNode;
  1353. // Trim space padding before assigning to innerHTML
  1354. var html = src.replace(/^\s+/g, '').replace(/\s+$/g, '');
  1355. var parserElement = document.createElement('div');
  1356. var tag = element.nodeName.toLowerCase();
  1357. var tableElements = ['td', 'th', 'tr', 'tbody', 'thead', 'tfoot'];
  1358. var isInTable = false;
  1359. for (var tei = 0, tel = tableElements.length; tei < tel; tei++) {
  1360. if (tableElements[tei] == tag) {
  1361. isInTable = true;
  1362. break;
  1363. }
  1364. }
  1365. if (isInTable) {
  1366. if (isAutoExec()) {
  1367. // Create html
  1368. parserElement.innerHTML = '<table>' + html + '</table>';
  1369. } else {
  1370. // Get the scripts from the text
  1371. scripts = getScripts(html);
  1372. // Remove scripts from text
  1373. html = removeScripts(html);
  1374. parserElement.innerHTML = '<table>' + html + '</table>';
  1375. }
  1376. var newElement = parserElement.firstChild;
  1377. //some browsers will also create intermediary elements such as table>tbody>tr>td
  1378. while ((null !== newElement) && (id !== newElement.id)) {
  1379. newElement = newElement.firstChild;
  1380. }
  1381. parent.replaceChild(newElement, element);
  1382. runScripts(scripts);
  1383. } else if (element.nodeName.toLowerCase() === 'input') {
  1384. // special case handling for 'input' elements
  1385. // in order to not lose focus when updating,
  1386. // input elements need to be added in place.
  1387. parserElement = document.createElement('div');
  1388. parserElement.innerHTML = html;
  1389. newElement = parserElement.firstChild;
  1390. cloneAttributes(element, newElement);
  1391. deleteNode(parserElement);
  1392. } else if (html.length > 0) {
  1393. if (isAutoExec()) {
  1394. // Create html
  1395. parserElement.innerHTML = html;
  1396. } else {
  1397. // Get the scripts from the text
  1398. scripts = getScripts(html);
  1399. // Remove scripts from text
  1400. html = removeScripts(html);
  1401. parserElement.innerHTML = html;
  1402. }
  1403. replaceNode(parserElement.firstChild, element);
  1404. deleteNode(parserElement);
  1405. runScripts(scripts);
  1406. }
  1407. }
  1408. };
  1409. /**
  1410. * Delete a node specified by the element.
  1411. * @param element
  1412. * @ignore
  1413. */
  1414. var doDelete = function doDelete(element) {
  1415. var id = element.getAttribute('id');
  1416. var target = $(id);
  1417. deleteNode(target);
  1418. };
  1419. /**
  1420. * Insert a node specified by the element.
  1421. * @param element
  1422. * @ignore
  1423. */
  1424. var doInsert = function doInsert(element) {
  1425. var tablePattern = new RegExp("<\\s*(td|th|tr|tbody|thead|tfoot)", "i");
  1426. var scripts = [];
  1427. var target = $(element.firstChild.getAttribute('id'));
  1428. var parent = target.parentNode;
  1429. var html = element.firstChild.firstChild.nodeValue;
  1430. var isInTable = tablePattern.test(html);
  1431. if (!isAutoExec()) {
  1432. // Get the scripts from the text
  1433. scripts = getScripts(html);
  1434. // Remove scripts from text
  1435. html = removeScripts(html);
  1436. }
  1437. var tempElement = document.createElement('div');
  1438. var newElement = null;
  1439. if (isInTable) {
  1440. tempElement.innerHTML = '<table>' + html + '</table>';
  1441. newElement = tempElement.firstChild;
  1442. //some browsers will also create intermediary elements such as table>tbody>tr>td
  1443. //test for presence of id on the new element since we do not have it directly
  1444. while ((null !== newElement) && ("" == newElement.id)) {
  1445. newElement = newElement.firstChild;
  1446. }
  1447. } else {
  1448. tempElement.innerHTML = html;
  1449. newElement = tempElement.firstChild;
  1450. }
  1451. if (element.firstChild.nodeName === 'after') {
  1452. // Get the next in the list, to insert before
  1453. target = target.nextSibling;
  1454. } // otherwise, this is a 'before' element
  1455. if (!!tempElement.innerHTML) { // check if only scripts were inserted - if so, do nothing here
  1456. parent.insertBefore(newElement, target);
  1457. }
  1458. runScripts(scripts);
  1459. deleteNode(tempElement);
  1460. };
  1461. /**
  1462. * Modify attributes of given element id.
  1463. * @param element
  1464. * @ignore
  1465. */
  1466. var doAttributes = function doAttributes(element) {
  1467. // Get id of element we'll act against
  1468. var id = element.getAttribute('id');
  1469. var target = $(id);
  1470. if (!target) {
  1471. throw new Error("The specified id: " + id + " was not found in the page.");
  1472. }
  1473. // There can be multiple attributes modified. Loop through the list.
  1474. var nodes = element.childNodes;
  1475. for (var i = 0; i < nodes.length; i++) {
  1476. var name = nodes[i].getAttribute('name');
  1477. var value = nodes[i].getAttribute('value');
  1478. //boolean attribute handling code for all browsers
  1479. if (name === 'disabled') {
  1480. target.disabled = value === 'disabled' || value === 'true';
  1481. return;
  1482. } else if (name === 'checked') {
  1483. target.checked = value === 'checked' || value === 'on' || value === 'true';
  1484. return;
  1485. } else if (name == 'readonly') {
  1486. target.readOnly = value === 'readonly' || value === 'true';
  1487. return;
  1488. }
  1489. if (!isIE()) {
  1490. if (name === 'value') {
  1491. target.value = value;
  1492. } else {
  1493. target.setAttribute(name, value);
  1494. }
  1495. } else { // if it's IE, then quite a bit more work is required
  1496. if (name === 'class') {
  1497. target.className = value;
  1498. } else if (name === "for") {
  1499. name = 'htmlFor';
  1500. target.setAttribute(name, value, 0);
  1501. } else if (name === 'style') {
  1502. target.style.setAttribute('cssText', value, 0);
  1503. } else if (name.substring(0, 2) === 'on') {
  1504. var c = document.body.appendChild(document.createElement('span'));
  1505. try {
  1506. c.innerHTML = '<span ' + name + '="' + value + '"/>';
  1507. target[name] = c.firstChild[name];
  1508. } finally {
  1509. document.body.removeChild(c);
  1510. }
  1511. } else if (name === 'dir') {
  1512. if (jsf.getProjectStage() == 'Development') {
  1513. throw new Error("Cannot set 'dir' attribute in IE");
  1514. }
  1515. } else {
  1516. target.setAttribute(name, value, 0);
  1517. }
  1518. }
  1519. }
  1520. };
  1521. /**
  1522. * Eval the CDATA of the element.
  1523. * @param element to eval
  1524. * @ignore
  1525. */
  1526. var doEval = function doEval(element) {
  1527. var evalText = '';
  1528. var childNodes = element.childNodes;
  1529. for (var i = 0; i < childNodes.length; i++) {
  1530. evalText += childNodes[i].nodeValue;
  1531. }
  1532. globalEval(evalText);
  1533. };
  1534. /**
  1535. * Ajax Request Queue
  1536. * @ignore
  1537. */
  1538. var Queue = new function Queue() {
  1539. // Create the internal queue
  1540. var queue = [];
  1541. // the amount of space at the front of the queue, initialised to zero
  1542. var queueSpace = 0;
  1543. /** Returns the size of this Queue. The size of a Queue is equal to the number
  1544. * of elements that have been enqueued minus the number of elements that have
  1545. * been dequeued.
  1546. * @ignore
  1547. */
  1548. this.getSize = function getSize() {
  1549. return queue.length - queueSpace;
  1550. };
  1551. /** Returns true if this Queue is empty, and false otherwise. A Queue is empty
  1552. * if the number of elements that have been enqueued equals the number of
  1553. * elements that have been dequeued.
  1554. * @ignore
  1555. */
  1556. this.isEmpty = function isEmpty() {
  1557. return (queue.length === 0);
  1558. };
  1559. /** Enqueues the specified element in this Queue.
  1560. *
  1561. * @param element - the element to enqueue
  1562. * @ignore
  1563. */
  1564. this.enqueue = function enqueue(element) {
  1565. // Queue the request
  1566. queue.push(element);
  1567. };
  1568. /** Dequeues an element from this Queue. The oldest element in this Queue is
  1569. * removed and returned. If this Queue is empty then undefined is returned.
  1570. *
  1571. * @returns Object The element that was removed from the queue.
  1572. * @ignore
  1573. */
  1574. this.dequeue = function dequeue() {
  1575. // initialise the element to return to be undefined
  1576. var element = undefined;
  1577. // check whether the queue is empty
  1578. if (queue.length) {
  1579. // fetch the oldest element in the queue
  1580. element = queue[queueSpace];
  1581. // update the amount of space and check whether a shift should occur
  1582. if (++queueSpace * 2 >= queue.length) {
  1583. // set the queue equal to the non-empty portion of the queue
  1584. queue = queue.slice(queueSpace);
  1585. // reset the amount of space at the front of the queue
  1586. queueSpace = 0;
  1587. }
  1588. }
  1589. // return the removed element
  1590. try {
  1591. return element;
  1592. } finally {
  1593. element = null; // IE 6 leak prevention
  1594. }
  1595. };
  1596. /** Returns the oldest element in this Queue. If this Queue is empty then
  1597. * undefined is returned. This function returns the same value as the dequeue
  1598. * function, but does not remove the returned element from this Queue.
  1599. * @ignore
  1600. */
  1601. this.getOldestElement = function getOldestElement() {
  1602. // initialise the element to return to be undefined
  1603. var element = undefined;
  1604. // if the queue is not element then fetch the oldest element in the queue
  1605. if (queue.length) {
  1606. element = queue[queueSpace];
  1607. }
  1608. // return the oldest element
  1609. try {
  1610. return element;
  1611. } finally {
  1612. element = null; //IE 6 leak prevention
  1613. }
  1614. };
  1615. }();
  1616. /**
  1617. * AjaxEngine handles Ajax implementation details.
  1618. * @ignore
  1619. */
  1620. var AjaxEngine = function AjaxEngine(context) {
  1621. var req = {}; // Request Object
  1622. req.url = null; // Request URL
  1623. req.context = context; // Context of request and response
  1624. req.context.sourceid = null; // Source of this request
  1625. req.context.onerror = null; // Error handler for request
  1626. req.context.onevent = null; // Event handler for request
  1627. req.context.namingContainerId = null; // If UIViewRoot is an instance of NamingContainer this represents its ID.
  1628. req.context.namingContainerPrefix = null; // If UIViewRoot is an instance of NamingContainer this represents its ID suffixed with separator character, else an empty string.
  1629. req.xmlReq = null; // XMLHttpRequest Object
  1630. req.async = true; // Default - Asynchronous
  1631. req.parameters = {}; // Parameters For GET or POST
  1632. req.queryString = null; // Encoded Data For GET or POST
  1633. req.method = null; // GET or POST
  1634. req.status = null; // Response Status Code From Server
  1635. req.fromQueue = false; // Indicates if the request was taken off the queue before being sent. This prevents the request from entering the queue redundantly.
  1636. req.que = Queue;
  1637. // Get a transport Handle
  1638. // The transport will be an iframe transport if the form
  1639. // has multipart encoding type. This is where we could
  1640. // handle XMLHttpRequest Level2 as well (perhaps
  1641. // something like: if ('upload' in req.xmlReq)'
  1642. req.xmlReq = getTransport(context);
  1643. if (req.xmlReq === null) {
  1644. return null;
  1645. }
  1646. /**
  1647. * @ignore
  1648. */
  1649. function noop() {}
  1650. // Set up request/response state callbacks
  1651. /**
  1652. * @ignore
  1653. */
  1654. req.xmlReq.onreadystatechange = function() {
  1655. if (req.xmlReq.readyState === 4) {
  1656. req.onComplete();
  1657. // next two lines prevent closure/ciruclar reference leaks
  1658. // of XHR instances in IE
  1659. req.xmlReq.onreadystatechange = noop;
  1660. req.xmlReq = null;
  1661. }
  1662. };
  1663. /**
  1664. * This function is called when the request/response interaction
  1665. * is complete. If the return status code is successfull,
  1666. * dequeue all requests from the queue that have completed. If a
  1667. * request has been found on the queue that has not been sent,
  1668. * send the request.
  1669. * @ignore
  1670. */
  1671. req.onComplete = function onComplete() {
  1672. if (req.xmlReq.status && (req.xmlReq.status >= 200 && req.xmlReq.status < 300)) {
  1673. sendEvent(req.xmlReq, req.context, "complete");
  1674. jsf.ajax.response(req.xmlReq, req.context);
  1675. } else {
  1676. sendEvent(req.xmlReq, req.context, "complete");
  1677. sendError(req.xmlReq, req.context, "httpError");
  1678. }
  1679. // Regardless of whether the request completed successfully (or not),
  1680. // dequeue requests that have been completed (readyState 4) and send
  1681. // requests that ready to be sent (readyState 0).
  1682. var nextReq = req.que.getOldestElement();
  1683. if (nextReq === null || typeof nextReq === 'undefined') {
  1684. return;
  1685. }
  1686. while ((typeof nextReq.xmlReq !== 'undefined' && nextReq.xmlReq !== null) &&
  1687. nextReq.xmlReq.readyState === 4) {
  1688. req.que.dequeue();
  1689. nextReq = req.que.getOldestElement();
  1690. if (nextReq === null || typeof nextReq === 'undefined') {
  1691. break;
  1692. }
  1693. }
  1694. if (nextReq === null || typeof nextReq === 'undefined') {
  1695. return;
  1696. }
  1697. if ((typeof nextReq.xmlReq !== 'undefined' && nextReq.xmlReq !== null) &&
  1698. nextReq.xmlReq.readyState === 0) {
  1699. nextReq.fromQueue = true;
  1700. nextReq.sendRequest();
  1701. }
  1702. };
  1703. /**
  1704. * Utility method that accepts additional arguments for the AjaxEngine.
  1705. * If an argument is passed in that matches an AjaxEngine property, the
  1706. * argument value becomes the value of the AjaxEngine property.
  1707. * Arguments that don't match AjaxEngine properties are added as
  1708. * request parameters.
  1709. * @ignore
  1710. */
  1711. req.setupArguments = function(args) {
  1712. for (var i in args) {
  1713. if (args.hasOwnProperty(i)) {
  1714. if (typeof req[i] === 'undefined') {
  1715. req.parameters[i] = args[i];
  1716. } else {
  1717. req[i] = args[i];
  1718. }
  1719. }
  1720. }
  1721. };
  1722. /**
  1723. * This function does final encoding of parameters, determines the request method
  1724. * (GET or POST) and sends the request using the specified url.
  1725. * @ignore
  1726. */
  1727. req.sendRequest = function() {
  1728. if (req.xmlReq !== null) {
  1729. // if there is already a request on the queue waiting to be processed..
  1730. // just queue this request
  1731. if (!req.que.isEmpty()) {
  1732. if (!req.fromQueue) {
  1733. req.que.enqueue(req);
  1734. return;
  1735. }
  1736. }
  1737. // If the queue is empty, queue up this request and send
  1738. if (!req.fromQueue) {
  1739. req.que.enqueue(req);
  1740. }
  1741. // Some logic to get the real request URL
  1742. if (req.generateUniqueUrl && req.method == "GET") {
  1743. req.parameters["AjaxRequestUniqueId"] = new Date().getTime() + "" + req.requestIndex;
  1744. }
  1745. var content = null; // For POST requests, to hold query string
  1746. for (var i in req.parameters) {
  1747. if (req.parameters.hasOwnProperty(i)) {
  1748. if (req.queryString.length > 0) {
  1749. req.queryString += "&";
  1750. }
  1751. req.queryString += encodeURIComponent(i) + "=" + encodeURIComponent(req.parameters[i]);
  1752. }
  1753. }
  1754. if (req.method === "GET") {
  1755. if (req.queryString.length > 0) {
  1756. req.url += ((req.url.indexOf("?") > -1) ? "&" : "?") + req.queryString;
  1757. }
  1758. }
  1759. req.xmlReq.open(req.method, req.url, req.async);
  1760. // note that we are including the charset=UTF-8 as part of the content type (even
  1761. // if encodeURIComponent encodes as UTF-8), because with some
  1762. // browsers it will not be set in the request. Some server implementations need to
  1763. // determine the character encoding from the request header content type.
  1764. if (req.method === "POST") {
  1765. if (typeof req.xmlReq.setRequestHeader !== 'undefined') {
  1766. req.xmlReq.setRequestHeader('Faces-Request', 'partial/ajax');
  1767. req.xmlReq.setRequestHeader('Content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
  1768. }
  1769. content = req.queryString;
  1770. }
  1771. // note that async == false is not a supported feature. We may change it in ways
  1772. // that break existing programs at any time, with no warning.
  1773. if(!req.async) {
  1774. req.xmlReq.onreadystatechange = null; // no need for readystate change listening
  1775. }
  1776. sendEvent(req.xmlReq, req.context, "begin");
  1777. req.xmlReq.send(content);
  1778. if(!req.async){
  1779. req.onComplete();
  1780. }
  1781. }
  1782. };
  1783. return req;
  1784. };
  1785. /**
  1786. * Error handling callback.
  1787. * Assumes that the request has completed.
  1788. * @ignore
  1789. */
  1790. var sendError = function sendError(request, context, status, description, serverErrorName, serverErrorMessage) {
  1791. // Possible errornames:
  1792. // httpError
  1793. // emptyResponse
  1794. // serverError
  1795. // malformedXML
  1796. var sent = false;
  1797. var data = {}; // data payload for function
  1798. data.type = "error";
  1799. data.status = status;
  1800. data.source = context.sourceid;
  1801. data.responseCode = request.status;
  1802. data.responseXML = request.responseXML;
  1803. data.responseText = request.responseText;
  1804. // ensure data source is the dom element and not the ID
  1805. // per 14.4.1 of the 2.0 specification.
  1806. if (typeof data.source === 'string') {
  1807. data.source = document.getElementById(data.source);
  1808. }
  1809. if (description) {
  1810. data.description = description;
  1811. } else if (status == "httpError") {
  1812. if (data.responseCode === 0) {
  1813. data.description = "The Http Transport returned a 0 status code. This is usually the result of mixing ajax and full requests. This is usually undesired, for both performance and data integrity reasons.";
  1814. } else {
  1815. data.description = "There was an error communicating with the server, status: " + data.responseCode;
  1816. }
  1817. } else if (status == "serverError") {
  1818. data.description = serverErrorMessage;
  1819. } else if (status == "emptyResponse") {
  1820. data.description = "An empty response was received from the server. Check server error logs.";
  1821. } else if (status == "malformedXML") {
  1822. if (getParseErrorText(data.responseXML) !== PARSED_OK) {
  1823. data.description = getParseErrorText(data.responseXML);
  1824. } else {
  1825. data.description = "An invalid XML response was received from the server.";
  1826. }
  1827. }
  1828. if (status == "serverError") {
  1829. data.errorName = serverErrorName;
  1830. data.errorMessage = serverErrorMessage;
  1831. }
  1832. // If we have a registered callback, send the error to it.
  1833. if (context.onerror) {
  1834. context.onerror.call(null, data);
  1835. sent = true;
  1836. }
  1837. for (var i in errorListeners) {
  1838. if (errorListeners.hasOwnProperty(i)) {
  1839. errorListeners[i].call(null, data);
  1840. sent = true;
  1841. }
  1842. }
  1843. if (!sent && jsf.getProjectStage() === "Development") {
  1844. if (status == "serverError") {
  1845. alert("serverError: " + serverErrorName + " " + serverErrorMessage);
  1846. } else {
  1847. alert(status + ": " + data.description);
  1848. }
  1849. }
  1850. };
  1851. /**
  1852. * Event handling callback.
  1853. * Request is assumed to have completed, except in the case of event = 'begin'.
  1854. * @ignore
  1855. */
  1856. var sendEvent = function sendEvent(request, context, status) {
  1857. var data = {};
  1858. data.type = "event";
  1859. data.status = status;
  1860. data.source = context.sourceid;
  1861. // ensure data source is the dom element and not the ID
  1862. // per 14.4.1 of the 2.0 specification.
  1863. if (typeof data.source === 'string') {
  1864. data.source = document.getElementById(data.source);
  1865. }
  1866. if (status !== 'begin') {
  1867. data.responseCode = request.status;
  1868. data.responseXML = request.responseXML;
  1869. data.responseText = request.responseText;
  1870. }
  1871. if (context.onevent) {
  1872. context.onevent.call(null, data);
  1873. }
  1874. for (var i in eventListeners) {
  1875. if (eventListeners.hasOwnProperty(i)) {
  1876. eventListeners[i].call(null, data);
  1877. }
  1878. }
  1879. };
  1880. var unescapeHTML = function unescapeHTML(escapedHTML) {
  1881. return escapedHTML
  1882. .replace(/&apos;/g, "'")
  1883. .replace(/&quot;/g, '"')
  1884. .replace(/&gt;/g, '>')
  1885. .replace(/&lt;/g, '<')
  1886. .replace(/&amp;/g, '&');
  1887. };
  1888. // Use module pattern to return the functions we actually expose
  1889. return {
  1890. /**
  1891. * Register a callback for error handling.
  1892. * <p><b>Usage:</b></p>
  1893. * <pre><code>
  1894. * jsf.ajax.addOnError(handleError);
  1895. * ...
  1896. * var handleError = function handleError(data) {
  1897. * ...
  1898. * }
  1899. * </pre></code>
  1900. * <p><b>Implementation Requirements:</b></p>
  1901. * This function must accept a reference to an existing JavaScript function.
  1902. * The JavaScript function reference must be added to a list of callbacks, making it possible
  1903. * to register more than one callback by invoking <code>jsf.ajax.addOnError</code>
  1904. * more than once. This function must throw an error if the <code>callback</code>
  1905. * argument is not a function.
  1906. *
  1907. * @member jsf.ajax
  1908. * @param callback a reference to a function to call on an error
  1909. */
  1910. addOnError: function addOnError(callback) {
  1911. if (typeof callback === 'function') {
  1912. errorListeners[errorListeners.length] = callback;
  1913. } else {
  1914. throw new Error("jsf.ajax.addOnError: Added a callback that was not a function.");
  1915. }
  1916. },
  1917. /**
  1918. * Register a callback for event handling.
  1919. * <p><b>Usage:</b></p>
  1920. * <pre><code>
  1921. * jsf.ajax.addOnEvent(statusUpdate);
  1922. * ...
  1923. * var statusUpdate = function statusUpdate(data) {
  1924. * ...
  1925. * }
  1926. * </pre></code>
  1927. * <p><b>Implementation Requirements:</b></p>
  1928. * This function must accept a reference to an existing JavaScript function.
  1929. * The JavaScript function reference must be added to a list of callbacks, making it possible
  1930. * to register more than one callback by invoking <code>jsf.ajax.addOnEvent</code>
  1931. * more than once. This function must throw an error if the <code>callback</code>
  1932. * argument is not a function.
  1933. *
  1934. * @member jsf.ajax
  1935. * @param callback a reference to a function to call on an event
  1936. */
  1937. addOnEvent: function addOnEvent(callback) {
  1938. if (typeof callback === 'function') {
  1939. eventListeners[eventListeners.length] = callback;
  1940. } else {
  1941. throw new Error("jsf.ajax.addOnEvent: Added a callback that was not a function");
  1942. }
  1943. },
  1944. /**
  1945. * <p><span class="changed_modified_2_2">Send</span> an
  1946. * asynchronous Ajax req uest to the server.
  1947. * <p><b>Usage:</b></p>
  1948. * <pre><code>
  1949. * Example showing all optional arguments:
  1950. *
  1951. * &lt;commandButton id="button1" value="submit"
  1952. * onclick="jsf.ajax.request(this,event,
  1953. * {execute:'button1',render:'status',onevent: handleEvent,onerror: handleError});return false;"/&gt;
  1954. * &lt;/commandButton/&gt;
  1955. * </pre></code>
  1956. * <p><b>Implementation Requirements:</b></p>
  1957. * This function must:
  1958. * <ul>
  1959. * <li>Be used within the context of a <code>form</code><span class="changed_added_2_3">,
  1960. * else throw an error</span>.</li>
  1961. * <li>Capture the element that triggered this Ajax request
  1962. * (from the <code>source</code> argument, also known as the
  1963. * <code>source</code> element.</li>
  1964. * <li>If the <code>source</code> element is <code>null</code> or
  1965. * <code>undefined</code> throw an error.</li>
  1966. * <li>If the <code>source</code> argument is not a <code>string</code> or
  1967. * DOM element object, throw an error.</li>
  1968. * <li>If the <code>source</code> argument is a <code>string</code>, find the
  1969. * DOM element for that <code>string</code> identifier.
  1970. * <li>If the DOM element could not be determined, throw an error.</li>
  1971. * <li class="changed_added_2_3">If the <code>javax.faces.ViewState</code>
  1972. * element could not be found, throw an error.</li>
  1973. * <li class="changed_added_2_3">If the ID of the <code>javax.faces.ViewState</code>
  1974. * element has a <code>&lt;VIEW_ROOT_CONTAINER_CLIENT_ID&gt;&lt;SEP&gt;</code>
  1975. * prefix, where &lt;SEP&gt; is the currently configured
  1976. * <code>UINamingContainer.getSeparatorChar()</code> and
  1977. * &lt;VIEW_ROOT_CONTAINER_CLIENT_ID&gt; is the return from
  1978. * <code>UIViewRoot.getContainerClientId()</code> on the
  1979. * view from whence this state originated, then remember it as <i>namespace prefix</i>.
  1980. * This is needed during encoding of the set of post data arguments.</li>
  1981. * <li>If the <code>onerror</code> and <code>onevent</code> arguments are set,
  1982. * they must be functions, or throw an error.
  1983. * <li>Determine the <code>source</code> element's <code>form</code>
  1984. * element.</li>
  1985. * <li>Get the <code>form</code> view state by calling
  1986. * {@link jsf.getViewState} passing the
  1987. * <code>form</code> element as the argument.</li>
  1988. * <li>Collect post data arguments for the Ajax request.
  1989. * <ul>
  1990. * <li>The following name/value pairs are required post data arguments:
  1991. * <table border="1">
  1992. * <tr>
  1993. * <th>name</th>
  1994. * <th>value</th>
  1995. * </tr>
  1996. * <tr>
  1997. * <td><code>javax.faces.ViewState</code></td>
  1998. * <td><code>Contents of javax.faces.ViewState hidden field. This is included when
  1999. * {@link jsf.getViewState} is used.</code></td>
  2000. * </tr>
  2001. * <tr>
  2002. * <td><code>javax.faces.partial.ajax</code></td>
  2003. * <td><code>true</code></td>
  2004. * </tr>
  2005. * <tr>
  2006. * <td><code>javax.faces.source</code></td>
  2007. * <td><code>The identifier of the element that triggered this request.</code></td>
  2008. * </tr>
  2009. * <tr class="changed_added_2_2">
  2010. * <td><code>javax.faces.ClientWindow</code></td>
  2011. * <td><code>Call jsf.getClientWindow(), passing the current
  2012. * form. If the return is non-null, it must be set as the
  2013. * value of this name/value pair, otherwise, a name/value
  2014. * pair for client window must not be sent.</code></td>
  2015. * </tr>
  2016. * </table>
  2017. * </li>
  2018. * </ul>
  2019. * </li>
  2020. * <li>Collect optional post data arguments for the Ajax request.
  2021. * <ul>
  2022. * <li>Determine additional arguments (if any) from the <code>options</code>
  2023. * argument. If <code>options.execute</code> exists:
  2024. * <ul>
  2025. * <li>If the keyword <code>@none</code> is present, do not create and send
  2026. * the post data argument <code>javax.faces.partial.execute</code>.</li>
  2027. * <li>If the keyword <code>@all</code> is present, create the post data argument with
  2028. * the name <code>javax.faces.partial.execute</code> and the value <code>@all</code>.</li>
  2029. * <li>Otherwise, there are specific identifiers that need to be sent. Create the post
  2030. * data argument with the name <code>javax.faces.partial.execute</code> and the value as a
  2031. * space delimited <code>string</code> of client identifiers.</li>
  2032. * </ul>
  2033. * </li>
  2034. * <li>If <code>options.execute</code> does not exist, create the post data argument with the
  2035. * name <code>javax.faces.partial.execute</code> and the value as the identifier of the
  2036. * element that caused this request.</li>
  2037. * <li>If <code>options.render</code> exists:
  2038. * <ul>
  2039. * <li>If the keyword <code>@none</code> is present, do not create and send
  2040. * the post data argument <code>javax.faces.partial.render</code>.</li>
  2041. * <li>If the keyword <code>@all</code> is present, create the post data argument with
  2042. * the name <code>javax.faces.partial.render</code> and the value <code>@all</code>.</li>
  2043. * <li>Otherwise, there are specific identifiers that need to be sent. Create the post
  2044. * data argument with the name <code>javax.faces.partial.render</code> and the value as a
  2045. * space delimited <code>string</code> of client identifiers.</li>
  2046. * </ul>
  2047. * <li>If <code>options.render</code> does not exist do not create and send the
  2048. * post data argument <code>javax.faces.partial.render</code>.</li>
  2049. * <li class="changed_added_2_2">If
  2050. * <code>options.delay</code> exists let it be the value
  2051. * <em>delay</em>, for this discussion. If
  2052. * <code>options.delay</code> does not exist, or is the
  2053. * literal string <code>'none'</code>, without the quotes,
  2054. * no delay is used. If less than <em>delay</em>
  2055. * milliseconds elapses between calls to <em>request()</em>
  2056. * only the most recent one is sent and all other requests
  2057. * are discarded.</li>
  2058. * <li class="changed_added_2_2">If
  2059. * <code>options.resetValues</code> exists and its value is
  2060. * <code>true</code>, ensure a post data argument with the
  2061. * name <code>javax.faces.partial.resetValues</code> and the
  2062. * value <code>true</code> is sent in addition to the other
  2063. * post data arguments. This will cause
  2064. * <code>UIViewRoot.resetValues()</code> to be called,
  2065. * passing the value of the "render" attribute. Note: do
  2066. * not use any of the <code>@</code> keywords such as
  2067. * <code>@form</code> or <code>@this</code> with this option
  2068. * because <code>UIViewRoot.resetValues()</code> does not
  2069. * descend into the children of the listed components.</li>
  2070. * <li>Determine additional arguments (if any) from the <code>event</code>
  2071. * argument. The following name/value pairs may be used from the
  2072. * <code>event</code> object:
  2073. * <ul>
  2074. * <li><code>target</code> - the ID of the element that triggered the event.</li>
  2075. * <li><code>captured</code> - the ID of the element that captured the event.</li>
  2076. * <li><code>type</code> - the type of event (ex: onkeypress)</li>
  2077. * <li><code>alt</code> - <code>true</code> if ALT key was pressed.</li>
  2078. * <li><code>ctrl</code> - <code>true</code> if CTRL key was pressed.</li>
  2079. * <li><code>shift</code> - <code>true</code> if SHIFT key was pressed. </li>
  2080. * <li><code>meta</code> - <code>true</code> if META key was pressed. </li>
  2081. * <li><code>right</code> - <code>true</code> if right mouse button
  2082. * was pressed. </li>
  2083. * <li><code>left</code> - <code>true</code> if left mouse button
  2084. * was pressed. </li>
  2085. * <li><code>keycode</code> - the key code.
  2086. * </ul>
  2087. * </li>
  2088. * </ul>
  2089. * </li>
  2090. * <li>Encode the set of post data arguments. <span class="changed_added_2_3">
  2091. * If the <code>javax.faces.ViewState</code> element has a namespace prefix, then
  2092. * make sure that all post data arguments are prefixed with this namespace prefix.
  2093. * </span></li>
  2094. * <li>Join the encoded view state with the encoded set of post data arguments
  2095. * to form the <code>query string</code> that will be sent to the server.</li>
  2096. * <li>Create a request <code>context</code> object and set the properties:
  2097. * <ul><li><code>source</code> (the source DOM element for this request)</li>
  2098. * <li><code>onerror</code> (the error handler for this request)</li>
  2099. * <li><code>onevent</code> (the event handler for this request)</li></ul>
  2100. * The request context will be used during error/event handling.</li>
  2101. * <li>Send a <code>begin</code> event following the procedure as outlined
  2102. * in the Chapter 13 "Sending Events" section of the spec prose document <a
  2103. * href="../../javadocs/overview-summary.html#prose_document">linked in the
  2104. * overview summary</a></li>
  2105. * <li>Set the request header with the name: <code>Faces-Request</code> and the
  2106. * value: <code>partial/ajax</code>.</li>
  2107. * <li>Determine the <code>posting URL</code> as follows: If the hidden field
  2108. * <code>javax.faces.encodedURL</code> is present in the submitting form, use its
  2109. * value as the <code>posting URL</code>. Otherwise, use the <code>action</code>
  2110. * property of the <code>form</code> element as the <code>URL</code>.</li>
  2111. * <li>
  2112. * <p><span class="changed_modified_2_2">Determine whether
  2113. * or not the submitting form is using
  2114. * <code>multipart/form-data</code> as its
  2115. * <code>enctype</code> attribute. If not, send the request
  2116. * as an <code>asynchronous POST</code> using the
  2117. * <code>posting URL</code> that was determined in the
  2118. * previous step.</span> <span
  2119. * class="changed_added_2_2">Otherwise, send the request
  2120. * using a multi-part capable transport layer, such as a
  2121. * hidden inline frame. Note that using a hidden inline
  2122. * frame does <strong>not</strong> use
  2123. * <code>XMLHttpRequest</code>, but the request must be sent
  2124. * with all the parameters that a JSF
  2125. * <code>XMLHttpRequest</code> would have been sent with.
  2126. * In this way, the server side processing of the request
  2127. * will be identical whether or the request is multipart or
  2128. * not.</span></p>
  2129. * <div class="changed_added_2_2">
  2130. * <p>The <code>begin</code>, <code>complete</code>, and
  2131. * <code>success</code> events must be emulated when using
  2132. * the multipart transport. This allows any listeners to
  2133. * behave uniformly regardless of the multipart or
  2134. * <code>XMLHttpRequest</code> nature of the transport.</p>
  2135. * </div></li>
  2136. * </ul>
  2137. * Form serialization should occur just before the request is sent to minimize
  2138. * the amount of time between the creation of the serialized form data and the
  2139. * sending of the serialized form data (in the case of long requests in the queue).
  2140. * Before the request is sent it must be put into a queue to ensure requests
  2141. * are sent in the same order as when they were initiated. The request callback function
  2142. * must examine the queue and determine the next request to be sent. The behavior of the
  2143. * request callback function must be as follows:
  2144. * <ul>
  2145. * <li>If the request completed successfully invoke {@link jsf.ajax.response}
  2146. * passing the <code>request</code> object.</li>
  2147. * <li>If the request did not complete successfully, notify the client.</li>
  2148. * <li>Regardless of the outcome of the request (success or error) every request in the
  2149. * queue must be handled. Examine the status of each request in the queue starting from
  2150. * the request that has been in the queue the longest. If the status of the request is
  2151. * <code>complete</code> (readyState 4), dequeue the request (remove it from the queue).
  2152. * If the request has not been sent (readyState 0), send the request. Requests that are
  2153. * taken off the queue and sent should not be put back on the queue.</li>
  2154. * </ul>
  2155. *
  2156. * </p>
  2157. *
  2158. * @param source The DOM element that triggered this Ajax request, or an id string of the
  2159. * element to use as the triggering element.
  2160. * @param event The DOM event that triggered this Ajax request. The
  2161. * <code>event</code> argument is optional.
  2162. * @param options The set of available options that can be sent as
  2163. * request parameters to control client and/or server side
  2164. * request processing. Acceptable name/value pair options are:
  2165. * <table border="1">
  2166. * <tr>
  2167. * <th>name</th>
  2168. * <th>value</th>
  2169. * </tr>
  2170. * <tr>
  2171. * <td><code>execute</code></td>
  2172. * <td><code>space seperated list of client identifiers</code></td>
  2173. * </tr>
  2174. * <tr>
  2175. * <td><code>render</code></td>
  2176. * <td><code>space seperated list of client identifiers</code></td>
  2177. * </tr>
  2178. * <tr>
  2179. * <td><code>onevent</code></td>
  2180. * <td><code>function to callback for event</code></td>
  2181. * </tr>
  2182. * <tr>
  2183. * <td><code>onerror</code></td>
  2184. * <td><code>function to callback for error</code></td>
  2185. * </tr>
  2186. * <tr>
  2187. * <td><code>params</code></td>
  2188. * <td><code>object containing parameters to include in the request</code></td>
  2189. * </tr>
  2190. * <tr class="changed_added_2_2">
  2191. * <td><code>delay</code></td>
  2192. * <td>If less than <em>delay</em> milliseconds elapses
  2193. * between calls to <em>request()</em> only the most recent
  2194. * one is sent and all other requests are discarded. If the
  2195. * value of <em>delay</em> is the literal string
  2196. * <code>'none'</code> without the quotes, or no delay is
  2197. * specified, no delay is used. </td>
  2198. * </tr>
  2199. * <tr class="changed_added_2_2">
  2200. * <td><code>resetValues</code></td>
  2201. * <td>If true, ensure a post data argument with the name
  2202. * javax.faces.partial.resetValues and the value true is
  2203. * sent in addition to the other post data arguments. This
  2204. * will cause UIViewRoot.resetValues() to be called, passing
  2205. * the value of the "render" attribute. Note: do not use any
  2206. * of the @ keywords such as @form or @this with this option
  2207. * because UIViewRoot.resetValues() does not descend into
  2208. * the children of the listed components.</td>
  2209. * </tr>
  2210. * </table>
  2211. * The <code>options</code> argument is optional.
  2212. * @member jsf.ajax
  2213. * @function jsf.ajax.request
  2214. * @throws Error if first required argument
  2215. * <code>element</code> is not specified, or if one or more
  2216. * of the components in the <code>options.execute</code>
  2217. * list is a file upload component, but the form's enctype
  2218. * is not set to <code>multipart/form-data</code>
  2219. */
  2220. request: function request(source, event, options) {
  2221. var element, form, viewStateElement; // Element variables
  2222. var all, none;
  2223. var context = {};
  2224. if (typeof source === 'undefined' || source === null) {
  2225. throw new Error("jsf.ajax.request: source not set");
  2226. }
  2227. if(delayHandler) {
  2228. clearTimeout(delayHandler);
  2229. delayHandler = null;
  2230. }
  2231. // set up the element based on source
  2232. if (typeof source === 'string') {
  2233. element = document.getElementById(source);
  2234. } else if (typeof source === 'object') {
  2235. element = source;
  2236. } else {
  2237. throw new Error("jsf.ajax.request: source must be object or string");
  2238. }
  2239. // attempt to handle case of name unset
  2240. // this might be true in a badly written composite component
  2241. if (!element.name) {
  2242. element.name = element.id;
  2243. }
  2244. context.element = element;
  2245. if (typeof(options) === 'undefined' || options === null) {
  2246. options = {};
  2247. }
  2248. // Error handler for this request
  2249. var onerror = false;
  2250. if (options.onerror && typeof options.onerror === 'function') {
  2251. onerror = options.onerror;
  2252. } else if (options.onerror && typeof options.onerror !== 'function') {
  2253. throw new Error("jsf.ajax.request: Added an onerror callback that was not a function");
  2254. }
  2255. // Event handler for this request
  2256. var onevent = false;
  2257. if (options.onevent && typeof options.onevent === 'function') {
  2258. onevent = options.onevent;
  2259. } else if (options.onevent && typeof options.onevent !== 'function') {
  2260. throw new Error("jsf.ajax.request: Added an onevent callback that was not a function");
  2261. }
  2262. form = getForm(element);
  2263. if (!form) {
  2264. throw new Error("jsf.ajax.request: Method must be called within a form");
  2265. }
  2266. viewStateElement = getHiddenStateField(form, "javax.faces.ViewState");
  2267. if (!viewStateElement) {
  2268. throw new Error("jsf.ajax.request: Form has no view state element");
  2269. }
  2270. context.form = form;
  2271. context.formId = form.id;
  2272. var viewState = jsf.getViewState(form);
  2273. // Set up additional arguments to be used in the request..
  2274. // Make sure "javax.faces.source" is set up.
  2275. // If there were "execute" ids specified, make sure we
  2276. // include the identifier of the source element in the
  2277. // "execute" list. If there were no "execute" ids
  2278. // specified, determine the default.
  2279. var args = {};
  2280. var namingContainerPrefix = viewStateElement.name.substring(0, viewStateElement.name.indexOf("javax.faces.ViewState"));
  2281. args[namingContainerPrefix + "javax.faces.source"] = element.id;
  2282. if (event && !!event.type) {
  2283. args[namingContainerPrefix + "javax.faces.partial.event"] = event.type;
  2284. }
  2285. if ("resetValues" in options) {
  2286. args[namingContainerPrefix + "javax.faces.partial.resetValues"] = options.resetValues;
  2287. }
  2288. // If we have 'execute' identifiers:
  2289. // Handle any keywords that may be present.
  2290. // If @none present anywhere, do not send the
  2291. // "javax.faces.partial.execute" parameter.
  2292. // The 'execute' and 'render' lists must be space
  2293. // delimited.
  2294. if (options.execute) {
  2295. none = options.execute.indexOf("@none");
  2296. if (none < 0) {
  2297. all = options.execute.indexOf("@all");
  2298. if (all < 0) {
  2299. options.execute = options.execute.replace("@this", element.id);
  2300. options.execute = options.execute.replace("@form", form.id);
  2301. var temp = options.execute.split(' ');
  2302. if (!isInArray(temp, element.name)) {
  2303. options.execute = element.name + " " + options.execute;
  2304. }
  2305. if (namingContainerPrefix) {
  2306. options.execute = namespaceParametersIfNecessary(options.execute, element.name, namingContainerPrefix);
  2307. }
  2308. } else {
  2309. options.execute = "@all";
  2310. }
  2311. args[namingContainerPrefix + "javax.faces.partial.execute"] = options.execute;
  2312. }
  2313. } else {
  2314. options.execute = element.name + " " + element.id;
  2315. args[namingContainerPrefix + "javax.faces.partial.execute"] = options.execute;
  2316. }
  2317. if (options.render) {
  2318. none = options.render.indexOf("@none");
  2319. if (none < 0) {
  2320. all = options.render.indexOf("@all");
  2321. if (all < 0) {
  2322. options.render = options.render.replace("@this", element.id);
  2323. options.render = options.render.replace("@form", form.id);
  2324. if (namingContainerPrefix) {
  2325. options.render = namespaceParametersIfNecessary(options.render, element.name, namingContainerPrefix);
  2326. }
  2327. } else {
  2328. options.render = "@all";
  2329. }
  2330. args[namingContainerPrefix + "javax.faces.partial.render"] = options.render;
  2331. }
  2332. }
  2333. var explicitlyDoNotDelay = ((typeof options.delay == 'undefined') || (typeof options.delay == 'string') &&
  2334. (options.delay.toLowerCase() == 'none'));
  2335. var delayValue;
  2336. if (typeof options.delay == 'number') {
  2337. delayValue = options.delay;
  2338. } else {
  2339. var converted = parseInt(options.delay);
  2340. if (!explicitlyDoNotDelay && isNaN(converted)) {
  2341. throw new Error('invalid value for delay option: ' + options.delay);
  2342. }
  2343. delayValue = converted;
  2344. }
  2345. var checkForTypeFile
  2346. // check the execute ids to see if any include an input of type "file"
  2347. context.includesInputFile = false;
  2348. var ids = options.execute.split(" ");
  2349. if (ids == "@all") { ids = [ form.id ]; }
  2350. if (ids) {
  2351. for (i = 0; i < ids.length; i++) {
  2352. var elem = document.getElementById(ids[i]);
  2353. if (elem) {
  2354. var nodeType = elem.nodeType;
  2355. if (nodeType == Node.ELEMENT_NODE) {
  2356. var elemAttributeDetector = detectAttributes(elem);
  2357. if (elemAttributeDetector("type")) {
  2358. if (elem.getAttribute("type") === "file") {
  2359. context.includesInputFile = true;
  2360. break;
  2361. }
  2362. } else {
  2363. if (hasInputFileControl(elem)) {
  2364. context.includesInputFile = true;
  2365. break;
  2366. }
  2367. }
  2368. }
  2369. }
  2370. }
  2371. }
  2372. // copy all params to args
  2373. var params = options.params || {};
  2374. for (var property in params) {
  2375. if (params.hasOwnProperty(property)) {
  2376. args[namingContainerPrefix + property] = params[property];
  2377. }
  2378. }
  2379. // remove non-passthrough options
  2380. delete options.execute;
  2381. delete options.render;
  2382. delete options.onerror;
  2383. delete options.onevent;
  2384. delete options.delay;
  2385. delete options.resetValues;
  2386. delete options.params;
  2387. // copy all other options to args (for backwards compatibility on issue 4115)
  2388. for (var property in options) {
  2389. if (options.hasOwnProperty(property)) {
  2390. args[namingContainerPrefix + property] = options[property];
  2391. }
  2392. }
  2393. args[namingContainerPrefix + "javax.faces.partial.ajax"] = "true";
  2394. args["method"] = "POST";
  2395. // Determine the posting url
  2396. var encodedUrlField = getEncodedUrlElement(form);
  2397. if (typeof encodedUrlField == 'undefined') {
  2398. args["url"] = form.action;
  2399. } else {
  2400. args["url"] = encodedUrlField.value;
  2401. }
  2402. var sendRequest = function() {
  2403. var ajaxEngine = new AjaxEngine(context);
  2404. ajaxEngine.setupArguments(args);
  2405. ajaxEngine.queryString = viewState;
  2406. ajaxEngine.context.onevent = onevent;
  2407. ajaxEngine.context.onerror = onerror;
  2408. ajaxEngine.context.sourceid = element.id;
  2409. ajaxEngine.context.render = args[namingContainerPrefix + "javax.faces.partial.render"] || "";
  2410. ajaxEngine.context.namingContainerPrefix = namingContainerPrefix;
  2411. ajaxEngine.sendRequest();
  2412. // null out element variables to protect against IE memory leak
  2413. element = null;
  2414. form = null;
  2415. sendRequest = null;
  2416. context = null;
  2417. };
  2418. if (explicitlyDoNotDelay) {
  2419. sendRequest();
  2420. } else {
  2421. delayHandler = setTimeout(sendRequest, delayValue);
  2422. }
  2423. },
  2424. /**
  2425. * <p><span class="changed_modified_2_2">Receive</span> an Ajax response
  2426. * from the server.
  2427. * <p><b>Usage:</b></p>
  2428. * <pre><code>
  2429. * jsf.ajax.response(request, context);
  2430. * </pre></code>
  2431. * <p><b>Implementation Requirements:</b></p>
  2432. * This function must evaluate the markup returned in the
  2433. * <code>request.responseXML</code> object and perform the following action:
  2434. * <ul>
  2435. * <p>If there is no XML response returned, signal an <code>emptyResponse</code>
  2436. * error. If the XML response does not follow the format as outlined
  2437. * in Appendix A of the spec prose document <a
  2438. * href="../../javadocs/overview-summary.html#prose_document">linked in the
  2439. * overview summary</a> signal a <code>malformedError</code> error. Refer to
  2440. * section "Signaling Errors" in Chapter 13 of the spec prose document <a
  2441. * href="../../javadocs/overview-summary.html#prose_document">linked in the
  2442. * overview summary</a>.</p>
  2443. * <p>If the response was successfully processed, send a <code>success</code>
  2444. * event as outlined in Chapter 13 "Sending Events" section of the spec prose
  2445. * document <a
  2446. * href="../../javadocs/overview-summary.html#prose_document">linked in the
  2447. * overview summary</a>.</p>
  2448. * <p><i>Update Element Processing</i></p>
  2449. * The <code>update</code> element is used to update a single DOM element. The
  2450. * "id" attribute of the <code>update</code> element refers to the DOM element that
  2451. * will be updated. The contents of the <code>CDATA</code> section is the data that
  2452. * will be used when updating the contents of the DOM element as specified by the
  2453. * <code>&lt;update&gt;</code> element identifier.
  2454. * <li>If an <code>&lt;update&gt;</code> element is found in the response
  2455. * with the identifier <code>javax.faces.ViewRoot</code>:
  2456. * <pre><code>&lt;update id="javax.faces.ViewRoot"&gt;
  2457. * &lt;![CDATA[...]]&gt;
  2458. * &lt;/update&gt;</code></pre>
  2459. * Update the entire DOM replacing the appropriate <code>head</code> and/or
  2460. * <code>body</code> sections with the content from the response.</li>
  2461. * <li class="changed_modified_2_2">If an
  2462. * <code>&lt;update&gt;</code> element is found in the
  2463. * response with an identifier containing
  2464. * <code>javax.faces.ViewState</code>:
  2465. * <pre><code>&lt;update id="&lt;VIEW_ROOT_CONTAINER_CLIENT_ID&gt;&lt;SEP&gt;javax.faces.ViewState&lt;SEP&gt;&lt;UNIQUE_PER_VIEW_NUMBER&gt;"&gt;
  2466. * &lt;![CDATA[...]]&gt;
  2467. * &lt;/update&gt;</code></pre>
  2468. * locate and update the submitting form's
  2469. * <code>javax.faces.ViewState</code> value with the
  2470. * <code>CDATA</code> contents from the response.
  2471. * &lt;SEP&gt; is the currently configured
  2472. * <code>UINamingContainer.getSeparatorChar()</code>.
  2473. * &lt;VIEW_ROOT_CONTAINER_CLIENT_ID&gt; is the return from
  2474. * <code>UIViewRoot.getContainerClientId()</code> on the
  2475. * view from whence this state originated.
  2476. * &lt;UNIQUE_PER_VIEW_NUMBER&gt; is a number that must be
  2477. * unique within this view, but must not be included in the
  2478. * view state. This requirement is simply to satisfy XML
  2479. * correctness in parity with what is done in the
  2480. * corresponding non-partial JSF view. Locate and update
  2481. * the <code>javax.faces.ViewState</code> value for all
  2482. * JSF forms covered in the <code>render</code> target
  2483. * list whose ID starts with the same
  2484. * &lt;VIEW_ROOT_CONTAINER_CLIENT_ID&gt; value.</li>
  2485. * <li class="changed_added_2_2">If an
  2486. * <code>update</code> element is found in the response with
  2487. * an identifier containing
  2488. * <code>javax.faces.ClientWindow</code>:
  2489. * <pre><code>&lt;update id="&lt;VIEW_ROOT_CONTAINER_CLIENT_ID&gt;&lt;SEP&gt;javax.faces.ClientWindow&lt;SEP&gt;&lt;UNIQUE_PER_VIEW_NUMBER&gt;"&gt;
  2490. * &lt;![CDATA[...]]&gt;
  2491. * &lt;/update&gt;</code></pre>
  2492. * locate and update the submitting form's
  2493. * <code>javax.faces.ClientWindow</code> value with the
  2494. * <code>CDATA</code> contents from the response.
  2495. * &lt;SEP&gt; is the currently configured
  2496. * <code>UINamingContainer.getSeparatorChar()</code>.
  2497. * &lt;VIEW_ROOT_CONTAINER_CLIENT_ID&gt; is the return from
  2498. * <code>UIViewRoot.getContainerClientId()</code> on the
  2499. * view from whence this state originated.
  2500. * &lt;UNIQUE_PER_VIEW_NUMBER&gt; is a number that must be
  2501. * unique within this view, but must not be included in the
  2502. * view state. This requirement is simply to satisfy XML
  2503. * correctness in parity with what is done in the
  2504. * corresponding non-partial JSF view. Locate and update
  2505. * the <code>javax.faces.ClientWindow</code> value for all
  2506. * JSF forms covered in the <code>render</code> target
  2507. * list whose ID starts with the same
  2508. * &lt;VIEW_ROOT_CONTAINER_CLIENT_ID&gt; value.</li>
  2509. * <li class="changed_added_2_3">If an <code>update</code> element is found in the response with the
  2510. * identifier <code>javax.faces.Resource</code>:
  2511. * <pre><code>&lt;update id="javax.faces.Resource"&gt;
  2512. * &lt;![CDATA[...]]&gt;
  2513. * &lt;/update&gt;</code></pre>
  2514. * append any element found in the <code>CDATA</code> contents which is absent in the document to the
  2515. * document's <code>head</code> section.
  2516. * </li>
  2517. * <li>If an <code>update</code> element is found in the response with the identifier
  2518. * <code>javax.faces.ViewHead</code>:
  2519. * <pre><code>&lt;update id="javax.faces.ViewHead"&gt;
  2520. * &lt;![CDATA[...]]&gt;
  2521. * &lt;/update&gt;</code></pre>
  2522. * update the document's <code>head</code> section with the <code>CDATA</code>
  2523. * contents from the response.</li>
  2524. * <li>If an <code>update</code> element is found in the response with the identifier
  2525. * <code>javax.faces.ViewBody</code>:
  2526. * <pre><code>&lt;update id="javax.faces.ViewBody"&gt;
  2527. * &lt;![CDATA[...]]&gt;
  2528. * &lt;/update&gt;</code></pre>
  2529. * update the document's <code>body</code> section with the <code>CDATA</code>
  2530. * contents from the response.</li>
  2531. * <li>For any other <code>&lt;update&gt;</code> element:
  2532. * <pre><code>&lt;update id="update id"&gt;
  2533. * &lt;![CDATA[...]]&gt;
  2534. * &lt;/update&gt;</code></pre>
  2535. * Find the DOM element with the identifier that matches the
  2536. * <code>&lt;update&gt;</code> element identifier, and replace its contents with
  2537. * the <code>&lt;update&gt;</code> element's <code>CDATA</code> contents.</li>
  2538. * </li>
  2539. * <p><i>Insert Element Processing</i></p>
  2540. * <li>If an <code>&lt;insert&gt;</code> element is found in
  2541. * the response with a nested <code>&lt;before&gt;</code>
  2542. * element:
  2543. * <pre><code>&lt;insert&gt;
  2544. * &lt;before id="before id"&gt;
  2545. * &lt;![CDATA[...]]&gt;
  2546. * &lt;/before&gt;
  2547. * &lt;/insert&gt;</code></pre>
  2548. *
  2549. * <ul>
  2550. * <li>Extract this <code>&lt;before&gt;</code> element's <code>CDATA</code> contents
  2551. * from the response.</li>
  2552. * <li>Find the DOM element whose identifier matches <code>before id</code> and insert
  2553. * the <code>&lt;before&gt;</code> element's <code>CDATA</code> content before
  2554. * the DOM element in the document.</li>
  2555. * </ul>
  2556. * </li>
  2557. *
  2558. * <li>If an <code>&lt;insert&gt;</code> element is found in
  2559. * the response with a nested <code>&lt;after&gt;</code>
  2560. * element:
  2561. *
  2562. * <pre><code>&lt;insert&gt;
  2563. * &lt;after id="after id"&gt;
  2564. * &lt;![CDATA[...]]&gt;
  2565. * &lt;/after&gt;
  2566. * &lt;/insert&gt;</code></pre>
  2567. *
  2568. * <ul>
  2569. * <li>Extract this <code>&lt;after&gt;</code> element's <code>CDATA</code> contents
  2570. * from the response.</li>
  2571. * <li>Find the DOM element whose identifier matches <code>after id</code> and insert
  2572. * the <code>&lt;after&gt;</code> element's <code>CDATA</code> content after
  2573. * the DOM element in the document.</li>
  2574. * </ul>
  2575. * </li>
  2576. * <p><i>Delete Element Processing</i></p>
  2577. * <li>If a <code>&lt;delete&gt;</code> element is found in the response:
  2578. * <pre><code>&lt;delete id="delete id"/&gt;</code></pre>
  2579. * Find the DOM element whose identifier matches <code>delete id</code> and remove it
  2580. * from the DOM.</li>
  2581. * <p><i>Element Attribute Update Processing</i></p>
  2582. * <li>If an <code>&lt;attributes&gt;</code> element is found in the response:
  2583. * <pre><code>&lt;attributes id="id of element with attribute"&gt;
  2584. * &lt;attribute name="attribute name" value="attribute value"&gt;
  2585. * ...
  2586. * &lt/attributes&gt;</code></pre>
  2587. * <ul>
  2588. * <li>Find the DOM element that matches the <code>&lt;attributes&gt;</code> identifier.</li>
  2589. * <li>For each nested <code>&lt;attribute&gt;</code> element in <code>&lt;attribute&gt;</code>,
  2590. * update the DOM element attribute value (whose name matches <code>attribute name</code>),
  2591. * with <code>attribute value</code>.</li>
  2592. * </ul>
  2593. * </li>
  2594. * <p><i>JavaScript Processing</i></p>
  2595. * <li>If an <code>&lt;eval&gt;</code> element is found in the response:
  2596. * <pre><code>&lt;eval&gt;
  2597. * &lt;![CDATA[...JavaScript...]]&gt;
  2598. * &lt;/eval&gt;</code></pre>
  2599. * <ul>
  2600. * <li>Extract this <code>&lt;eval&gt;</code> element's <code>CDATA</code> contents
  2601. * from the response and execute it as if it were JavaScript code.</li>
  2602. * </ul>
  2603. * </li>
  2604. * <p><i>Redirect Processing</i></p>
  2605. * <li>If a <code>&lt;redirect&gt;</code> element is found in the response:
  2606. * <pre><code>&lt;redirect url="redirect url"/&gt;</code></pre>
  2607. * Cause a redirect to the url <code>redirect url</code>.</li>
  2608. * <p><i>Error Processing</i></p>
  2609. * <li>If an <code>&lt;error&gt;</code> element is found in the response:
  2610. * <pre><code>&lt;error&gt;
  2611. * &lt;error-name&gt;..fully qualified class name string...&lt;error-name&gt;
  2612. * &lt;error-message&gt;&lt;![CDATA[...]]&gt;&lt;error-message&gt;
  2613. * &lt;/error&gt;</code></pre>
  2614. * Extract this <code>&lt;error&gt;</code> element's <code>error-name</code> contents
  2615. * and the <code>error-message</code> contents. Signal a <code>serverError</code> passing
  2616. * the <code>errorName</code> and <code>errorMessage</code>. Refer to
  2617. * section "Signaling Errors" in Chapter 13 of the spec prose document <a
  2618. * href="../../javadocs/overview-summary.html#prose_document">linked in the
  2619. * overview summary</a>.</li>
  2620. * <p><i>Extensions</i></p>
  2621. * <li>The <code>&lt;extensions&gt;</code> element provides a way for framework
  2622. * implementations to provide their own information.</li>
  2623. * <p><li>The implementation must check if &lt;script&gt; elements in the response can
  2624. * be automatically run, as some browsers support this feature and some do not.
  2625. * If they can not be run, then scripts should be extracted from the response and
  2626. * run separately.</li></p>
  2627. * </ul>
  2628. *
  2629. * </p>
  2630. *
  2631. * @param request The <code>XMLHttpRequest</code> instance that
  2632. * contains the status code and response message from the server.
  2633. *
  2634. * @param context An object containing the request context, including the following properties:
  2635. * the source element, per call onerror callback function, and per call onevent callback function.
  2636. *
  2637. * @throws Error if request contains no data
  2638. *
  2639. * @function jsf.ajax.response
  2640. */
  2641. response: function response(request, context) {
  2642. if (!request) {
  2643. throw new Error("jsf.ajax.response: Request parameter is unset");
  2644. }
  2645. // ensure context source is the dom element and not the ID
  2646. // per 14.4.1 of the 2.0 specification. We're doing it here
  2647. // *before* any errors or events are propagated becasue the
  2648. // DOM element may be removed after the update has been processed.
  2649. if (typeof context.sourceid === 'string') {
  2650. context.sourceid = document.getElementById(context.sourceid);
  2651. }
  2652. var xml = request.responseXML;
  2653. if (xml === null) {
  2654. sendError(request, context, "emptyResponse");
  2655. return;
  2656. }
  2657. if (getParseErrorText(xml) !== PARSED_OK) {
  2658. sendError(request, context, "malformedXML");
  2659. return;
  2660. }
  2661. var partialResponse = xml.getElementsByTagName("partial-response")[0];
  2662. var namingContainerId = partialResponse.getAttribute("id");
  2663. var namingContainerPrefix = namingContainerId ? (namingContainerId + jsf.separatorchar) : "";
  2664. var responseType = partialResponse.firstChild;
  2665. context.namingContainerId = namingContainerId;
  2666. context.namingContainerPrefix = namingContainerPrefix;
  2667. for (var i = 0; i < partialResponse.childNodes.length; i++) {
  2668. if (partialResponse.childNodes[i].nodeName === "error") {
  2669. responseType = partialResponse.childNodes[i];
  2670. break;
  2671. }
  2672. }
  2673. if (responseType.nodeName === "error") { // it's an error
  2674. var errorName = "";
  2675. var errorMessage = "";
  2676. var element = responseType.firstChild;
  2677. if (element.nodeName === "error-name") {
  2678. if (null != element.firstChild) {
  2679. errorName = element.firstChild.nodeValue;
  2680. }
  2681. }
  2682. element = responseType.firstChild.nextSibling;
  2683. if (element.nodeName === "error-message") {
  2684. if (null != element.firstChild) {
  2685. errorMessage = element.firstChild.nodeValue;
  2686. }
  2687. }
  2688. sendError(request, context, "serverError", null, errorName, errorMessage);
  2689. sendEvent(request, context, "success");
  2690. return;
  2691. }
  2692. if (responseType.nodeName === "redirect") {
  2693. window.location = responseType.getAttribute("url");
  2694. return;
  2695. }
  2696. if (responseType.nodeName !== "changes") {
  2697. sendError(request, context, "malformedXML", "Top level node must be one of: changes, redirect, error, received: " + responseType.nodeName + " instead.");
  2698. return;
  2699. }
  2700. var changes = responseType.childNodes;
  2701. try {
  2702. for (var i = 0; i < changes.length; i++) {
  2703. switch (changes[i].nodeName) {
  2704. case "update":
  2705. doUpdate(changes[i], context);
  2706. break;
  2707. case "delete":
  2708. doDelete(changes[i]);
  2709. break;
  2710. case "insert":
  2711. doInsert(changes[i]);
  2712. break;
  2713. case "attributes":
  2714. doAttributes(changes[i]);
  2715. break;
  2716. case "eval":
  2717. doEval(changes[i]);
  2718. break;
  2719. case "extension":
  2720. // no action
  2721. break;
  2722. default:
  2723. sendError(request, context, "malformedXML", "Changes allowed are: update, delete, insert, attributes, eval, extension. Received " + changes[i].nodeName + " instead.");
  2724. return;
  2725. }
  2726. }
  2727. } catch (ex) {
  2728. sendError(request, context, "malformedXML", ex.message);
  2729. return;
  2730. }
  2731. sendEvent(request, context, "success");
  2732. }
  2733. };
  2734. }();
  2735. /**
  2736. *
  2737. * <p>Return the value of <code>Application.getProjectStage()</code> for
  2738. * the currently running application instance. Calling this method must
  2739. * not cause any network transaction to happen to the server.</p>
  2740. * <p><b>Usage:</b></p>
  2741. * <pre><code>
  2742. * var stage = jsf.getProjectStage();
  2743. * if (stage === ProjectStage.Development) {
  2744. * ...
  2745. * } else if stage === ProjectStage.Production) {
  2746. * ...
  2747. * }
  2748. * </code></pre>
  2749. *
  2750. * @returns String <code>String</code> representing the current state of the
  2751. * running application in a typical product development lifecycle. Refer
  2752. * to <code>javax.faces.application.Application.getProjectStage</code> and
  2753. * <code>javax.faces.application.ProjectStage</code>.
  2754. * @function jsf.getProjectStage
  2755. */
  2756. jsf.getProjectStage = function() {
  2757. // First, return cached value if available
  2758. if (typeof mojarra !== 'undefined' && typeof mojarra.projectStageCache !== 'undefined') {
  2759. return mojarra.projectStageCache;
  2760. }
  2761. var scripts = document.getElementsByTagName("script"); // nodelist of scripts
  2762. var script; // jsf.js script
  2763. var s = 0; // incremental variable for for loop
  2764. var stage; // temp value for stage
  2765. var match; // temp value for match
  2766. while (s < scripts.length) {
  2767. if (typeof scripts[s].src === 'string' && scripts[s].src.match('\/javax\.faces\.resource\/jsf\.js\?.*ln=javax\.faces')) {
  2768. script = scripts[s].src;
  2769. break;
  2770. }
  2771. s++;
  2772. }
  2773. if (typeof script == "string") {
  2774. match = script.match("stage=(.*)");
  2775. if (match) {
  2776. stage = match[1];
  2777. }
  2778. }
  2779. if (typeof stage === 'undefined' || !stage) {
  2780. stage = "Production";
  2781. }
  2782. mojarra = mojarra || {};
  2783. mojarra.projectStageCache = stage;
  2784. return mojarra.projectStageCache;
  2785. };
  2786. /**
  2787. * <p>Collect and encode state for input controls associated
  2788. * with the specified <code>form</code> element. This will include
  2789. * all input controls of type <code>hidden</code>.</p>
  2790. * <p><b>Usage:</b></p>
  2791. * <pre><code>
  2792. * var state = jsf.getViewState(form);
  2793. * </pre></code>
  2794. *
  2795. * @param form The <code>form</code> element whose contained
  2796. * <code>input</code> controls will be collected and encoded.
  2797. * Only successful controls will be collected and encoded in
  2798. * accordance with: <a href="http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2">
  2799. * Section 17.13.2 of the HTML Specification</a>.
  2800. *
  2801. * @returns String The encoded state for the specified form's input controls.
  2802. * @function jsf.getViewState
  2803. */
  2804. jsf.getViewState = function(form) {
  2805. if (!form) {
  2806. throw new Error("jsf.getViewState: form must be set");
  2807. }
  2808. var els = form.elements;
  2809. var len = els.length;
  2810. // create an array which we'll use to hold all the intermediate strings
  2811. // this bypasses a problem in IE when repeatedly concatenating very
  2812. // large strings - we'll perform the concatenation once at the end
  2813. var qString = [];
  2814. var addField = function(name, value) {
  2815. var tmpStr = "";
  2816. if (qString.length > 0) {
  2817. tmpStr = "&";
  2818. }
  2819. tmpStr += encodeURIComponent(name) + "=" + encodeURIComponent(value);
  2820. qString.push(tmpStr);
  2821. };
  2822. for (var i = 0; i < len; i++) {
  2823. var el = els[i];
  2824. if (el.name === "") {
  2825. continue;
  2826. }
  2827. if (!el.disabled) {
  2828. switch (el.type) {
  2829. case 'submit':
  2830. case 'reset':
  2831. case 'image':
  2832. case 'file':
  2833. break;
  2834. case 'select-one':
  2835. if (el.selectedIndex >= 0) {
  2836. addField(el.name, el.options[el.selectedIndex].value);
  2837. }
  2838. break;
  2839. case 'select-multiple':
  2840. for (var j = 0; j < el.options.length; j++) {
  2841. if (el.options[j].selected) {
  2842. addField(el.name, el.options[j].value);
  2843. }
  2844. }
  2845. break;
  2846. case 'checkbox':
  2847. case 'radio':
  2848. if (el.checked) {
  2849. addField(el.name, el.value || 'on');
  2850. }
  2851. break;
  2852. default:
  2853. // this is for any input incl. text', 'password', 'hidden', 'textarea'
  2854. var nodeName = el.nodeName.toLowerCase();
  2855. if (nodeName === "input" || nodeName === "select" ||
  2856. nodeName === "button" || nodeName === "object" ||
  2857. nodeName === "textarea") {
  2858. addField(el.name, el.value);
  2859. }
  2860. break;
  2861. }
  2862. }
  2863. }
  2864. // concatenate the array
  2865. return qString.join("");
  2866. };
  2867. /**
  2868. * <p class="changed_added_2_2">Return the windowId of the window
  2869. * in which the argument form is rendered.</p>
  2870. * @param {optional String|DomNode} node. Determine the nature of
  2871. * the argument. If not present, search for the windowId within
  2872. * <code>document.forms</code>. If present and the value is a
  2873. * string, assume the string is a DOM id and get the element with
  2874. * that id and start the search from there. If present and the
  2875. * value is a DOM element, start the search from there.
  2876. * @returns String The windowId of the current window, or null
  2877. * if the windowId cannot be determined.
  2878. * @throws an error if more than one unique WindowId is found.
  2879. * @function jsf.getClientWindow
  2880. */
  2881. jsf.getClientWindow = function(node) {
  2882. var FORM = "form";
  2883. var WIN_ID = "javax.faces.ClientWindow";
  2884. /**
  2885. * Find javax.faces.ClientWindow field for a given form.
  2886. * @param form
  2887. * @ignore
  2888. */
  2889. var getWindowIdElement = function getWindowIdElement(form) {
  2890. var windowIdElement = form[WIN_ID];
  2891. if (windowIdElement) {
  2892. return windowIdElement;
  2893. } else {
  2894. var formElements = form.elements;
  2895. for (var i = 0, length = formElements.length; i < length; i++) {
  2896. var formElement = formElements[i];
  2897. if (formElement.name && (formElement.name.indexOf(WIN_ID) >= 0)) {
  2898. return formElement;
  2899. }
  2900. }
  2901. }
  2902. return undefined;
  2903. };
  2904. var fetchWindowIdFromForms = function (forms) {
  2905. var result_idx = {};
  2906. var result;
  2907. var foundCnt = 0;
  2908. for (var cnt = forms.length - 1; cnt >= 0; cnt--) {
  2909. var UDEF = 'undefined';
  2910. var currentForm = forms[cnt];
  2911. var windowIdElement = getWindowIdElement(currentForm);
  2912. var windowId = windowIdElement && windowIdElement.value;
  2913. if (UDEF != typeof windowId) {
  2914. if (foundCnt > 0 && UDEF == typeof result_idx[windowId]) throw Error("Multiple different windowIds found in document");
  2915. result = windowId;
  2916. result_idx[windowId] = true;
  2917. foundCnt++;
  2918. }
  2919. }
  2920. return result;
  2921. }
  2922. /**
  2923. * @ignore
  2924. */
  2925. var getChildForms = function (currentElement) {
  2926. //Special condition no element we return document forms
  2927. //as search parameter, ideal would be to
  2928. //have the viewroot here but the frameworks
  2929. //can deal with that themselves by using
  2930. //the viewroot as currentElement
  2931. if (!currentElement) {
  2932. return document.forms;
  2933. }
  2934. var targetArr = [];
  2935. if (!currentElement.tagName) return [];
  2936. else if (currentElement.tagName.toLowerCase() == FORM) {
  2937. targetArr.push(currentElement);
  2938. return targetArr;
  2939. }
  2940. //if query selectors are supported we can take
  2941. //a non recursive shortcut
  2942. if (currentElement.querySelectorAll) {
  2943. return currentElement.querySelectorAll(FORM);
  2944. }
  2945. //old recursive way, due to flakeyness of querySelectorAll
  2946. for (var cnt = currentElement.childNodes.length - 1; cnt >= 0; cnt--) {
  2947. var currentChild = currentElement.childNodes[cnt];
  2948. targetArr = targetArr.concat(getChildForms(currentChild, FORM));
  2949. }
  2950. return targetArr;
  2951. }
  2952. /**
  2953. * @ignore
  2954. */
  2955. var fetchWindowIdFromURL = function () {
  2956. var href = window.location.href;
  2957. var windowId = "windowId";
  2958. var regex = new RegExp("[\\?&]" + windowId + "=([^&#\\;]*)");
  2959. var results = regex.exec(href);
  2960. //initial trial over the url and a regexp
  2961. if (results != null) return results[1];
  2962. return null;
  2963. }
  2964. //byId ($)
  2965. var finalNode = (node && (typeof node == "string" || node instanceof String)) ?
  2966. document.getElementById(node) : (node || null);
  2967. var forms = getChildForms(finalNode);
  2968. var result = fetchWindowIdFromForms(forms);
  2969. return (null != result) ? result : fetchWindowIdFromURL();
  2970. };
  2971. /**
  2972. * <p class="changed_added_2_3">
  2973. * The Push functionality.
  2974. * </p>
  2975. * @name jsf.push
  2976. * @namespace
  2977. * @exec
  2978. */
  2979. jsf.push = (function(window) {
  2980. // "Constant" fields ----------------------------------------------------------------------------------------------
  2981. var URL_PROTOCOL = window.location.protocol.replace("http", "ws") + "//";
  2982. var RECONNECT_INTERVAL = 500;
  2983. var MAX_RECONNECT_ATTEMPTS = 25;
  2984. var REASON_EXPIRED = "Expired";
  2985. // Private static fields ------------------------------------------------------------------------------------------
  2986. var sockets = {};
  2987. var self = {};
  2988. // Private constructor functions ----------------------------------------------------------------------------------
  2989. /**
  2990. * Creates a reconnecting websocket. When the websocket successfully connects on first attempt, then it will
  2991. * automatically reconnect on timeout with cumulative intervals of 500ms with a maximum of 25 attempts (~3 minutes).
  2992. * The <code>onclose</code> function will be called with the error code of the last attempt.
  2993. * @constructor
  2994. * @param {string} url The URL of the websocket.
  2995. * @param {string} channel The channel name of the websocket.
  2996. * @param {function} onopen The function to be invoked when the websocket is opened.
  2997. * @param {function} onmessage The function to be invoked when a message is received.
  2998. * @param {function} onclose The function to be invoked when the websocket is closed.
  2999. * @param {Object} behaviors Client behavior functions to be invoked when specific message is received.
  3000. */
  3001. function ReconnectingWebsocket(url, channel, onopen, onmessage, onclose, behaviors) {
  3002. // Private fields -----------------------------------------------------------------------------------------
  3003. var socket;
  3004. var reconnectAttempts;
  3005. var self = this;
  3006. // Public functions ---------------------------------------------------------------------------------------
  3007. /**
  3008. * Opens the reconnecting websocket.
  3009. */
  3010. self.open = function() {
  3011. if (socket && socket.readyState == 1) {
  3012. return;
  3013. }
  3014. socket = new WebSocket(url);
  3015. socket.onopen = function(event) {
  3016. if (reconnectAttempts == null) {
  3017. onopen(channel);
  3018. }
  3019. reconnectAttempts = 0;
  3020. }
  3021. socket.onmessage = function(event) {
  3022. var message = JSON.parse(event.data).data;
  3023. onmessage(message, channel, event);
  3024. var functions = behaviors[message];
  3025. if (functions && functions.length) {
  3026. for (var i = 0; i < functions.length; i++) {
  3027. functions[i]();
  3028. }
  3029. }
  3030. }
  3031. socket.onclose = function(event) {
  3032. if (!socket
  3033. || (event.code == 1000 && event.reason == REASON_EXPIRED)
  3034. || (event.code == 1008)
  3035. || (reconnectAttempts == null)
  3036. || (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS))
  3037. {
  3038. onclose(event.code, channel, event);
  3039. }
  3040. else {
  3041. setTimeout(self.open, RECONNECT_INTERVAL * reconnectAttempts++);
  3042. }
  3043. }
  3044. }
  3045. /**
  3046. * Closes the reconnecting websocket.
  3047. */
  3048. self.close = function() {
  3049. if (socket) {
  3050. var s = socket;
  3051. socket = null;
  3052. reconnectAttempts == null;
  3053. s.close();
  3054. }
  3055. }
  3056. }
  3057. // Public static functions ----------------------------------------------------------------------------------------
  3058. /**
  3059. * Initialize a websocket on the given client identifier. When connected, it will stay open and reconnect as
  3060. * long as URL is valid and <code>jsf.push.close()</code> hasn't explicitly been called on the same client
  3061. * identifier.
  3062. * @param {string} clientId The client identifier of the websocket.
  3063. * @param {string} url The URL of the websocket. All open websockets on the same URL will receive the
  3064. * same push notification from the server.
  3065. * @param {string} channel The channel name of the websocket.
  3066. * @param {function} onopen The JavaScript event handler function that is invoked when the websocket is opened.
  3067. * The function will be invoked with one argument: the client identifier.
  3068. * @param {function} onmessage The JavaScript event handler function that is invoked when a message is received from
  3069. * the server. The function will be invoked with three arguments: the push message, the client identifier and
  3070. * the raw <code>MessageEvent</code> itself.
  3071. * @param {function} onclose The JavaScript event handler function that is invoked when the websocket is closed.
  3072. * The function will be invoked with three arguments: the close reason code, the client identifier and the raw
  3073. * <code>CloseEvent</code> itself. Note that this will also be invoked on errors and that you can inspect the
  3074. * close reason code if an error occurred and which one (i.e. when the code is not 1000). See also
  3075. * <a href="http://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455 section 7.4.1</a> and
  3076. * <a href="http://docs.oracle.com/javaee/7/api/javax/websocket/CloseReason.CloseCodes.html">CloseCodes</a> API
  3077. * for an elaborate list.
  3078. * @param {Object} behaviors Client behavior functions to be invoked when specific message is received.
  3079. * @param {boolean} autoconnect Whether or not to automatically connect the socket. Defaults to <code>false</code>.
  3080. * @member jsf.push
  3081. * @function jsf.push.init
  3082. */
  3083. self.init = function(clientId, url, channel, onopen, onmessage, onclose, behaviors, autoconnect) {
  3084. onclose = resolveFunction(onclose);
  3085. if (!window.WebSocket) { // IE6-9.
  3086. onclose(-1, clientId);
  3087. return;
  3088. }
  3089. if (!sockets[clientId]) {
  3090. sockets[clientId] = new ReconnectingWebsocket(url, channel, resolveFunction(onopen), resolveFunction(onmessage), onclose, behaviors);
  3091. }
  3092. if (autoconnect) {
  3093. self.open(clientId);
  3094. }
  3095. }
  3096. /**
  3097. * Open the websocket on the given client identifier.
  3098. * @param {string} clientId The client identifier of the websocket.
  3099. * @throws {Error} When client identifier is unknown. You may need to initialize it first via <code>init()</code> function.
  3100. * @member jsf.push
  3101. * @function jsf.push.open
  3102. */
  3103. self.open = function(clientId) {
  3104. getSocket(clientId).open();
  3105. }
  3106. /**
  3107. * Close the websocket on the given client identifier.
  3108. * @param {string} clientId The client identifier of the websocket.
  3109. * @throws {Error} When client identifier is unknown. You may need to initialize it first via <code>init()</code> function.
  3110. * @member jsf.push
  3111. * @function jsf.push.close
  3112. */
  3113. self.close = function(clientId) {
  3114. getSocket(clientId).close();
  3115. }
  3116. // Private static functions ---------------------------------------------------------------------------------------
  3117. /**
  3118. * If given function is actually not a function, then try to interpret it as name of a global function.
  3119. * If it still doesn't resolve to anything, then return a NOOP function.
  3120. * @param {Object} fn Can be function, or string representing function name, or undefined.
  3121. * @return {function} The intented function, or a NOOP function when undefined.
  3122. */
  3123. function resolveFunction(fn) {
  3124. return (typeof fn !== "function") && (fn = window[fn] || function(){}), fn;
  3125. }
  3126. /**
  3127. * Get socket associated with given client identifier.
  3128. * @param {string} clientId The client identifier of the websocket.
  3129. * @return {Socket} Socket associated with given client identifier.
  3130. * @throws {Error} When client identifier is unknown. You may need to initialize it first via <code>init()</code> function.
  3131. */
  3132. function getSocket(clientId) {
  3133. var socket = sockets[clientId];
  3134. if (socket) {
  3135. return socket;
  3136. }
  3137. else {
  3138. throw new Error("Unknown clientId: " + clientId);
  3139. }
  3140. }
  3141. // Expose self to public ------------------------------------------------------------------------------------------
  3142. return self;
  3143. })(window);
  3144. /**
  3145. * The namespace for JavaServer Faces JavaScript utilities.
  3146. * @name jsf.util
  3147. * @namespace
  3148. */
  3149. jsf.util = {};
  3150. /**
  3151. * <p>A varargs function that invokes an arbitrary number of scripts.
  3152. * If any script in the chain returns false, the chain is short-circuited
  3153. * and subsequent scripts are not invoked. Any number of scripts may
  3154. * specified after the <code>event</code> argument.</p>
  3155. *
  3156. * @param source The DOM element that triggered this Ajax request, or an
  3157. * id string of the element to use as the triggering element.
  3158. * @param event The DOM event that triggered this Ajax request. The
  3159. * <code>event</code> argument is optional.
  3160. *
  3161. * @returns boolean <code>false</code> if any scripts in the chain return <code>false</code>,
  3162. * otherwise returns <code>true</code>
  3163. *
  3164. * @function jsf.util.chain
  3165. */
  3166. jsf.util.chain = function(source, event) {
  3167. if (arguments.length < 3) {
  3168. return true;
  3169. }
  3170. // RELEASE_PENDING rogerk - shouldn't this be getElementById instead of null
  3171. var thisArg = (typeof source === 'object') ? source : null;
  3172. // Call back any scripts that were passed in
  3173. for (var i = 2; i < arguments.length; i++) {
  3174. var f = new Function("event", arguments[i]);
  3175. var returnValue = f.call(thisArg, event);
  3176. if (returnValue === false) {
  3177. return false;
  3178. }
  3179. }
  3180. return true;
  3181. };
  3182. /**
  3183. * <p class="changed_added_2_2">The result of calling
  3184. * <code>UINamingContainer.getNamingContainerSeparatorChar().</code></p>
  3185. */
  3186. jsf.separatorchar = '#{facesContext.namingContainerSeparatorChar}';
  3187. /**
  3188. * <p class="changed_added_2_3">
  3189. * The result of calling <code>ExternalContext.getRequestContextPath()</code>.
  3190. */
  3191. jsf.contextpath = '#{facesContext.externalContext.requestContextPath}';
  3192. /**
  3193. * <p>An integer specifying the specification version that this file implements.
  3194. * Its format is: rightmost two digits, bug release number, next two digits,
  3195. * minor release number, leftmost digits, major release number.
  3196. * This number may only be incremented by a new release of the specification.</p>
  3197. */
  3198. jsf.specversion = 23000;
  3199. /**
  3200. * <p>An integer specifying the implementation version that this file implements.
  3201. * It's a monotonically increasing number, reset with every increment of
  3202. * <code>jsf.specversion</code>
  3203. * This number is implementation dependent.</p>
  3204. */
  3205. jsf.implversion = 3;
  3206. } //end if version detection block
  3207. /*
  3208. * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
  3209. * Copyright 2004 The Apache Software Foundation
  3210. *
  3211. * Licensed under the Apache License, Version 2.0 (the "License");
  3212. * you may not use this file except in compliance with the License.
  3213. * You may obtain a copy of the License at
  3214. *
  3215. * http://www.apache.org/licenses/LICENSE-2.0
  3216. *
  3217. * Unless required by applicable law or agreed to in writing, software
  3218. * distributed under the License is distributed on an "AS IS" BASIS,
  3219. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  3220. * See the License for the specific language governing permissions and
  3221. * limitations under the License.
  3222. */
  3223. /**
  3224. @project JSF Ajax Library
  3225. @version 2.0
  3226. @description This is the standard implementation of the JSF Ajax Library.
  3227. */
  3228. /**
  3229. * Register with OpenAjax
  3230. */
  3231. if (typeof OpenAjax !== "undefined" &&
  3232. typeof OpenAjax.hub.registerLibrary !== "undefined") {
  3233. OpenAjax.hub.registerLibrary("mojarra", "www.sun.com", "1.0", null);
  3234. }
  3235. /**
  3236. * @name mojarra
  3237. * @namespace
  3238. */
  3239. /*
  3240. * Create our top level namespaces - mojarra
  3241. */
  3242. var mojarra = mojarra || {};
  3243. /**
  3244. * This function deletes any hidden parameters added
  3245. * to the form by checking for a variable called 'adp'
  3246. * defined on the form. If present, this variable will
  3247. * contain all the params added by 'apf'.
  3248. *
  3249. * @param f - the target form
  3250. */
  3251. mojarra.dpf = function dpf(f) {
  3252. var adp = f.adp;
  3253. if (adp !== null) {
  3254. for (var i = 0; i < adp.length; i++) {
  3255. f.removeChild(adp[i]);
  3256. }
  3257. }
  3258. };
  3259. /*
  3260. * This function adds any parameters specified by the
  3261. * parameter 'pvp' to the form represented by param 'f'.
  3262. * Any parameters added will be stored in a variable
  3263. * called 'adp' and stored on the form.
  3264. *
  3265. * @param f - the target form
  3266. * @param pvp - associative array of parameter
  3267. * key/value pairs to be added to the form as hidden input
  3268. * fields.
  3269. */
  3270. mojarra.apf = function apf(f, pvp) {
  3271. var adp = new Array();
  3272. f.adp = adp;
  3273. var i = 0;
  3274. for (var k in pvp) {
  3275. if (pvp.hasOwnProperty(k)) {
  3276. var p = document.createElement("input");
  3277. p.type = "hidden";
  3278. p.name = k;
  3279. p.value = pvp[k];
  3280. f.appendChild(p);
  3281. adp[i++] = p;
  3282. }
  3283. }
  3284. };
  3285. /*
  3286. * This is called by command link and command button. It provides
  3287. * the form it is nested in, the parameters that need to be
  3288. * added and finally, the target of the action. This function
  3289. * will delete any parameters added <em>after</em> the form
  3290. * has been submitted to handle DOM caching issues.
  3291. *
  3292. * @param f - the target form
  3293. * @param pvp - associative array of parameter
  3294. * key/value pairs to be added to the form as hidden input
  3295. * fields.
  3296. * @param t - the target of the form submission
  3297. */
  3298. mojarra.jsfcljs = function jsfcljs(f, pvp, t) {
  3299. mojarra.apf(f, pvp);
  3300. var ft = f.target;
  3301. if (t) {
  3302. f.target = t;
  3303. }
  3304. var input = document.createElement('input');
  3305. input.type = 'submit';
  3306. f.appendChild(input);
  3307. input.click();
  3308. f.removeChild(input);
  3309. f.target = ft;
  3310. mojarra.dpf(f);
  3311. };
  3312. /*
  3313. * This is called by functions that need access to their calling
  3314. * context, in the form of <code>this</code> and <code>event</code>
  3315. * objects.
  3316. *
  3317. * @param f the function to execute
  3318. * @param t this of the calling function
  3319. * @param e event of the calling function
  3320. * @return object that f returns
  3321. */
  3322. mojarra.jsfcbk = function jsfcbk(f, t, e) {
  3323. return f.call(t,e);
  3324. };
  3325. /*
  3326. * This is called by the AjaxBehaviorRenderer script to
  3327. * trigger a jsf.ajax.request() call.
  3328. *
  3329. * @param s the source element or id
  3330. * @param e event of the calling function
  3331. * @param n name of the behavior event that has fired
  3332. * @param ex execute list
  3333. * @param re render list
  3334. * @param op options object
  3335. */
  3336. mojarra.ab = function ab(s, e, n, ex, re, op) {
  3337. if (!op) {
  3338. op = {};
  3339. }
  3340. if (n) {
  3341. op["javax.faces.behavior.event"] = n;
  3342. }
  3343. if (ex) {
  3344. op["execute"] = ex;
  3345. }
  3346. if (re) {
  3347. op["render"] = re;
  3348. }
  3349. jsf.ajax.request(s, e, op);
  3350. };
  3351. /*
  3352. * This is called by command script when autorun=true.
  3353. *
  3354. * @param l window onload callback function
  3355. */
  3356. mojarra.l = function l(l) {
  3357. if (document.readyState === "complete") {
  3358. setTimeout(l);
  3359. }
  3360. else if (window.addEventListener) {
  3361. window.addEventListener("load", l, false);
  3362. }
  3363. else if (window.attachEvent) {
  3364. window.attachEvent("onload", l);
  3365. }
  3366. else if (typeof window.onload === "function") {
  3367. var oldListener = window.onload;
  3368. window.onload = function() { oldListener(); l(); };
  3369. }
  3370. else {
  3371. window.onload = l;
  3372. }
  3373. };