1 /* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to you under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /** 18 * @class 19 * @name _AjaxResponse 20 * @memberOf myfaces._impl.xhrCore 21 * @extends myfaces._impl.xhrCore._FinalizeableObj 22 * @description 23 * This class is responsible for handling the standardized xml ajax response 24 */ 25 myfaces._impl.core._Runtime.extendClass("myfaces._impl.xhrCore._AjaxResponse", myfaces._impl.xhrCore._FinalizeableObj, 26 /** @lends myfaces._impl.xhrCore._AjaxResponse.prototype */ 27 { 28 29 /*partial response types*/ 30 RESP_PARTIAL : "partial-response", 31 RESP_TYPE_ERROR : "error", 32 RESP_TYPE_REDIRECT : "redirect", 33 RESP_TYPE_CHANGES : "changes", 34 35 /*partial commands*/ 36 CMD_CHANGES : "changes", 37 CMD_UPDATE : "update", 38 CMD_DELETE : "delete", 39 CMD_INSERT : "insert", 40 CMD_EVAL : "eval", 41 CMD_ERROR : "error", 42 CMD_ATTRIBUTES : "attributes", 43 CMD_EXTENSION : "extension", 44 CMD_REDIRECT : "redirect", 45 46 /*other constants*/ 47 P_VIEWSTATE: "javax.faces.ViewState", 48 P_VIEWROOT: "javax.faces.ViewRoot", 49 P_VIEWHEAD: "javax.faces.ViewHead", 50 P_VIEWBODY: "javax.faces.ViewBody", 51 52 53 /** 54 * Standard constructor 55 * 56 * @param {function} base request classed parent object 57 * @param {function} onException 58 * @param {function} onWarning 59 */ 60 constructor_: function(onException, onWarning) { 61 //List of non form elements to be updated (which can have forms embedded) 62 this._updateElems = []; 63 // List of forms to be updated if any inner block is updated 64 this._updateForms = []; 65 this._onException = onException; 66 this._onWarning = onWarning; 67 68 this.appliedViewState = null; 69 70 this._Lang = myfaces._impl._util._Lang; 71 this._Dom = myfaces._impl._util._Dom; 72 this._RT = myfaces._impl.core._Runtime; 73 this._Impl = this._RT.getGlobalConfig("jsfAjaxImpl", myfaces._impl.core.Impl); 74 }, 75 /** 76 * uses response to start Html element replacement 77 * 78 * @param {Object} request (xhrRequest) - xhr request object 79 * @param {Object} context (Map) - AJAX context 80 * 81 * A special handling has to be added to the update cycle 82 * according to the JSDoc specs if the CDATA block contains html tags the outer rim must be stripped 83 * if the CDATA block contains a head section the document head must be replaced 84 * and if the CDATA block contains a body section the document body must be replaced! 85 * 86 */ 87 processResponse : function(request, context) { 88 try { 89 var _Impl = this._Impl; 90 91 // TODO: 92 // Solution from 93 // http://www.codingforums.com/archive/index.php/t-47018.html 94 // to solve IE error 1072896658 when a Java server sends iso88591 95 // istead of ISO-8859-1 96 97 if (!request) { 98 throw Exception(this._Lang.getMessage("ERR_EMPTY_RESPONSE",null,"jsf.ajaxResponse")); 99 } 100 101 if (!this._Lang.exists(request, "responseXML")) { 102 _Impl.sendError(request, context, myfaces._impl.core.Impl.EMPTY_RESPONSE); 103 return; 104 } 105 //check for a parseError under certain browsers 106 107 var xmlContent = request.responseXML; 108 //ie6+ keeps the parsing response under xmlContent.parserError 109 //while the rest of the world keeps it as element under the first node 110 111 if (this._Lang.isXMLParseError(xmlContent)) { 112 _Impl.sendError(request, context, myfaces._impl.core.Impl.MALFORMEDXML); 113 return; 114 } 115 var partials = xmlContent.childNodes[0]; 116 if ('undefined' == typeof partials || partials == null) { 117 _Impl.sendError(request, context, _Impl.MALFORMEDXML); 118 return; 119 } else { 120 if (partials.tagName != this.RESP_PARTIAL) { 121 // IE 8 sees XML Header as first sibling ... 122 partials = partials.nextSibling; 123 if (!partials || partials.tagName != this.RESP_PARTIAL) { 124 _Impl.sendError(request, context, myfaces._impl.core.Impl.MALFORMEDXML); 125 return; 126 } 127 } 128 } 129 130 var childNodesLength = partials.childNodes.length; 131 132 for (var loop = 0; loop < childNodesLength; loop++) { 133 var childNode = partials.childNodes[loop]; 134 var tagName = childNode.tagName; 135 /** 136 * <eval> 137 * <![CDATA[javascript]]> 138 * </eval> 139 */ 140 141 //this ought to be enough for eval 142 //however the run scripts still makes sense 143 //in the update and insert area for components 144 //which do not use the response writer properly 145 //we might add this one as custom option in update and 146 //insert! 147 if (tagName == this.CMD_ERROR) { 148 this.processError(request, context, childNode); 149 return; 150 } else if (tagName == this.CMD_REDIRECT) { 151 if (!this.processRedirect(request, context, childNode)) return; 152 } else if (tagName == this.CMD_CHANGES) { 153 if (!this.processChanges(request, context, childNode)) return; 154 } 155 } 156 157 //fixup missing viewStates due to spec deficiencies 158 this.fixViewStates(context); 159 } catch (e) { 160 this._onException(request, context, "myfaces._impl.xhrCore._AjaxResponse", "processResponse", e); 161 } 162 }, 163 164 /** 165 * fixes the viewstates in the current page 166 * 167 * @param context 168 */ 169 fixViewStates : function(context) { 170 171 if (null == this.appliedViewState) { 172 return; 173 } 174 //if we set our no portlet env we safely can update all forms with 175 //the new viewstate 176 if (this._RT.getLocalOrGlobalConfig(context, "no_portlet_env", false)) { 177 for (var cnt = document.forms.length - 1; cnt >= 0; cnt --) { 178 this._setVSTForm(document.forms[cnt]); 179 } 180 return; 181 } 182 183 // Now update the forms that were not replaced but forced to be updated, because contains child ajax tags 184 // we should only update forms with view state hidden field. If by some reason, the form was set to be 185 // updated but the form was replaced, it does not have hidden view state, so later in changeTrace processing the 186 // view state is updated. 187 188 //set the viewstates of all outer forms parents of our updated elements 189 this._Lang.arrForEach(this._updateForms, this._setVSTForm, 0, this); 190 191 //set the viewstate of all forms within our updated elements 192 this._Lang.arrForEach(this._updateElems, this._setVSTInnerForms, 0, this); 193 }, 194 195 /** 196 * sets the viewstate element in a given form 197 * 198 * @param theForm the form to which the element has to be set to 199 * @param doNotChange if set to true no change is performed if the element is found already to be rendered 200 */ 201 _setVSTForm: function(theForm) { 202 theForm = this._Lang.byId(theForm); 203 if(!theForm) return; 204 205 var viewStateField = (theForm.elements) ? theForm.elements[this.P_VIEWSTATE] : null;//this._Dom.findFormElement(elem, this.P_VIEWSTATE); 206 207 if (viewStateField) { 208 this._Dom.setAttribute(viewStateField, "value", this.appliedViewState); 209 } else if (!viewStateField) { 210 var element = this._Dom.getDummyPlaceHolder(); 211 element.innerHTML = ["<input type='hidden'", "id='", this.P_VIEWSTATE ,"' name='", this.P_VIEWSTATE ,"' value='" , this.appliedViewState , "' />"].join(""); 212 //now we go to proper dom handling after having to deal with another ie screwup 213 try { 214 theForm.appendChild(element.childNodes[0]); 215 } finally { 216 element.innerHTML = ""; 217 } 218 } 219 }, 220 221 _setVSTInnerForms: function(elem) { 222 elem = this._Dom.byIdOrName(elem); 223 var replacedForms = this._Dom.findByTagName(elem, "form", false); 224 var applyVST = this._Lang.hitch(this, function(elem) { 225 this._setVSTForm(elem); 226 }); 227 228 try { 229 this._Lang.arrForEach(replacedForms, applyVST, 0, this); 230 } finally { 231 delete applyVST; 232 } 233 }, 234 235 236 /** 237 * processes an incoming error from the response 238 * which is hosted under the <error> tag 239 * @param request the current request 240 * @param context the contect object 241 * @param node the node in the xml hosting the error message 242 */ 243 processError : function(request, context, node) { 244 /** 245 * <error> 246 * <error-name>String</error-name> 247 * <error-message><![CDATA[message]]></error-message> 248 * <error> 249 */ 250 var errorName = node.firstChild.textContent || ""; 251 var errorMessage = node.childNodes[1].firstChild.data || ""; 252 253 var _Impl = this._Impl; 254 255 _Impl.sendError(request, context, myfaces._impl.core.Impl.SERVER_ERROR, errorName, errorMessage); 256 }, 257 258 /** 259 * processes an incoming xml redirect directive from the ajax response 260 * @param request the request object 261 * @param context the context 262 * @param node the node hosting the redirect data 263 */ 264 processRedirect : function(request, context, node) { 265 /** 266 * <redirect url="url to redirect" /> 267 */ 268 var redirectUrl = node.getAttribute("url"); 269 if (!redirectUrl) { 270 var _Impl = this._Impl; 271 272 _Impl.sendError(request, context, myfaces._impl.core.Impl.MALFORMEDXML, myfaces._impl.core.Impl.MALFORMEDXML,this._Lang.getMessage("ERR_RED_URL", null, "_AjaxResponse.processRedirect")); 273 return false; 274 } 275 redirectUrl = this._Lang.trim(redirectUrl); 276 if (redirectUrl == "") { 277 return false; 278 } 279 window.location = redirectUrl; 280 return true; 281 }, 282 283 /** 284 * main entry point for processing the changes 285 * it deals with the <changes> node of the 286 * response 287 * 288 * @param request the xhr request object 289 * @param context the context map 290 * @param node the changes node to be processed 291 */ 292 processChanges : function(request, context, node) { 293 var changes = node.childNodes; 294 295 //note we need to trace the changes which could affect our insert update or delete 296 //se that we can realign our ViewStates afterwards 297 //the realignment must happen post change processing 298 299 for (var i = 0; i < changes.length; i++) { 300 301 switch (changes[i].tagName) { 302 303 case this.CMD_UPDATE: 304 if (!this.processUpdate(request, context, changes[i])) { 305 return false; 306 } 307 break; 308 case this.CMD_EVAL: 309 this._Lang.globalEval(changes[i].firstChild.data); 310 break; 311 case this.CMD_INSERT: 312 if (!this.processInsert(request, context, changes[i])) return false; 313 break; 314 case this.CMD_DELETE: 315 if (!this.processDelete(request, context, changes[i])) return false; 316 break; 317 case this.CMD_ATTRIBUTES: 318 if (!this.processAttributes(request, context, changes[i])) return false; 319 break; 320 case this.CMD_EXTENSION: 321 break; 322 default: 323 var _Impl = this._Impl; 324 _Impl.sendError(request, context, myfaces._impl.core.Impl.MALFORMEDXML); 325 return false; 326 } 327 } 328 329 return true; 330 }, 331 332 /** 333 * First substep process a pending update tag 334 * 335 * @param request the xhr request object 336 * @param context the context map 337 * @param node the changes node to be processed 338 */ 339 processUpdate : function(request, context, node) { 340 if (node.getAttribute('id') == this.P_VIEWSTATE) { 341 //update the submitting forms viewstate to the new value 342 // The source form has to be pulled out of the CURRENT document first because the context object 343 // may refer to an invalid document if an update of the entire body has occurred before this point. 344 var viewStateValue = node.firstChild.nodeValue; 345 346 var elementId = (context._mfInternal)? context._mfInternal["_mfSourceControlId"] : context.source.id; 347 var sourceForm = (context._mfInternal)? (document.forms[context._mfInternal["_mfSourceFormId"]] || this._Dom.fuzzyFormDetection(elementId)) : this._Dom.fuzzyFormDetection(elementId); 348 this.appliedViewState = viewStateValue; 349 //source form could not be determined either over the form identifer or the element 350 //we now skip this phase and just add everything we need for the fixup code 351 352 if (!sourceForm) { 353 //no source form found is not an error because 354 //we might be able to recover one way or the other 355 return true; 356 } 357 358 this._updateForms.push(sourceForm.id) 359 //this._setVSTForm(sourceForm); 360 } 361 else { 362 // response may contain several blocks 363 var cDataBlock = this._Dom.concatCDATABlocks(node); 364 365 switch (node.getAttribute('id')) { 366 case this.P_VIEWROOT: 367 368 369 cDataBlock = cDataBlock.substring(cDataBlock.indexOf("<html")); 370 371 var parsedData = this._replaceHead(request, context, cDataBlock); 372 373 var resultNode = ('undefined' != typeof parsedData && null != parsedData) ? this._replaceBody(request, context, cDataBlock, parsedData) : this._replaceBody(request, context, cDataBlock); 374 if (resultNode) { 375 this._pushOperationResult(resultNode); 376 } 377 break; 378 case this.P_VIEWHEAD: 379 //we cannot replace the head, almost no browser allows this, some of them throw errors 380 //others simply ignore it or replace it and destroy the dom that way! 381 this._replaceHead(request, context, cDataBlock); 382 383 break; 384 case this.P_VIEWBODY: 385 //we assume the cdata block is our body including the tag 386 var resultNode = this._replaceBody(request, context, cDataBlock); 387 if (resultNode) { 388 this._pushOperationResult(resultNode); 389 } 390 break; 391 392 default: 393 var resultNode = this.replaceHtmlItem(request, context, node.getAttribute('id'), cDataBlock); 394 if (resultNode) { 395 this._pushOperationResult(resultNode); 396 } 397 break; 398 } 399 } 400 return true; 401 }, 402 403 _pushOperationResult: function(resultNode) { 404 var pushSubnode = this._Lang.hitch(this, function(currNode) { 405 var parentForm = this._Dom.getParent(currNode, "form"); 406 //if possible we work over the ids 407 //so that elements later replaced are referenced 408 //at the latest possibility 409 if (null != parentForm) { 410 this._updateForms.push(parentForm.id || parentForm); 411 } 412 else { 413 this._updateElems.push(currNode.id || currNode); 414 } 415 }); 416 var isArr = 'undefined' != typeof resultNode.length && 'undefined' == typeof resultNode.nodeType; 417 if (isArr && resultNode.length) { 418 for (var cnt = 0; cnt < resultNode.length; cnt++) { 419 pushSubnode(resultNode[cnt]); 420 } 421 } else if (!isArr) { 422 pushSubnode(resultNode); 423 } 424 425 }, 426 427 /** 428 * replaces a current head theoretically, 429 * pratically only the scripts are evaled anew since nothing else 430 * can be changed. 431 * 432 * @param request the current request 433 * @param context the ajax context 434 * @param newData the data to be processed 435 * 436 * @return an xml representation of the page for further processing if possible 437 */ 438 _replaceHead: function(request, context, newData) { 439 440 var _Impl = this._Impl; 441 442 var isWebkit = this._RT.browser.isWebKit; 443 444 //we have to work around an xml parsing bug in Webkit 445 //see https://issues.apache.org/jira/browse/MYFACES-3061 446 var doc = (!isWebkit)? this._Lang.parseXML(newData) : null; 447 448 var newHead = null; 449 if (!isWebkit && this._Lang.isXMLParseError(doc)) { 450 doc = this._Lang.parseXML(newData.replace(/<!\-\-[\s\n]*<!\-\-/g, "<!--").replace(/\/\/-->[\s\n]*\/\/-->/g, "//-->")); 451 } 452 453 if (isWebkit || this._Lang.isXMLParseError(doc) ) { 454 //the standard xml parser failed we retry with the stripper 455 var parser = new (this._RT.getGlobalConfig("updateParser", myfaces._impl._util._HtmlStripper))(); 456 var headData = parser.parse(newData, "head"); 457 //We cannot avoid it here, but we have reduced the parsing now down to the bare minimum 458 //for further processing 459 newHead = this._Lang.parseXML("<head>" + headData + "</head>"); 460 //last and slowest option create a new head element and let the browser 461 //do its slow job 462 if (this._Lang.isXMLParseError(newHead)) { 463 try { 464 newHead = document.createElement("head"); 465 newHead.innerHTML = headData; 466 } catch (e) { 467 //we give up no further fallbacks 468 _Impl.sendError(request, context, _Impl.MALFORMEDXML, _Impl.MALFORMEDXML, "Error head replacement failed reason:"+e.toString()); 469 return null; 470 } 471 } 472 } else { 473 //parser worked we go on 474 newHead = doc.getElementsByTagName("head")[0]; 475 } 476 477 this._Dom.runScripts(newHead, true); 478 479 return doc; 480 }, 481 482 483 /** 484 * special method to handle the body dom manipulation, 485 * replacing the entire body does not work fully by simply adding a second body 486 * and by creating a range instead we have to work around that by dom creating a second 487 * body and then filling it properly! 488 * 489 * @param {Object} request our request object 490 * @param {Object} context (Map) the response context 491 * @param {String} newData the markup which replaces the old dom node! 492 * @param {Node} parsedData (optional) preparsed XML representation data of the current document 493 */ 494 _replaceBody : function(request, context, newData /*varargs*/) { 495 496 var oldBody = document.getElementsByTagName("body")[0]; 497 var placeHolder = document.createElement("div"); 498 var isWebkit = this._RT.browser.isWebKit; 499 500 placeHolder.id = "myfaces_bodyplaceholder"; 501 502 var bodyParent = oldBody.parentNode; 503 this._Dom._removeChildNodes(oldBody); 504 oldBody.innerHTML = ""; 505 var newBody = oldBody; 506 507 newBody.appendChild(placeHolder); 508 509 var bodyData = null; 510 511 var doc = null; 512 513 //we have to work around an xml parsing bug in Webkit 514 //see https://issues.apache.org/jira/browse/MYFACES-3061 515 if(!isWebkit) { 516 doc = (arguments.length > 3) ? arguments[3] : this._Lang.parseXML(newData); 517 } 518 519 if (!isWebkit && this._Lang.isXMLParseError(doc)) { 520 doc = this._Lang.parseXML(newData.replace(/<!\-\-[\s\n]*<!\-\-/g, "<!--").replace(/\/\/-->[\s\n]*\/\/-->/g, "//-->")); 521 } 522 523 if (isWebkit || this._Lang.isXMLParseError(doc)) { 524 //the standard xml parser failed we retry with the stripper 525 526 var parser = new (this._RT.getGlobalConfig("updateParser", myfaces._impl._util._HtmlStripper))(); 527 528 529 bodyData = parser.parse(newData, "body"); 530 } else { 531 //parser worked we go on 532 var newBodyData = doc.getElementsByTagName("body")[0]; 533 534 //speedwise we serialize back into the code 535 //for code reduction, speedwise we will take a small hit 536 //there which we will clean up in the future, but for now 537 //this is ok, I guess, since replace body only is a small subcase 538 bodyData = this._Lang.serializeChilds(newBodyData); 539 540 if (!this._RT.browser.isIEMobile || this._RT.browser.isIEMobile >= 7) { 541 //TODO check what is failing there 542 for (var cnt = 0; cnt < newBodyData.attributes.length; cnt++) { 543 var value = newBodyData.attributes[cnt].value; 544 if (value) 545 this._Dom.setAttribute(newBody, newBodyData.attributes[cnt].name, value); 546 } 547 } 548 } 549 550 //TODO eliminate the serialisation in case of already having a parsed tree 551 var returnedElement = this.replaceHtmlItem(request, context, placeHolder, bodyData); 552 553 if (returnedElement) { 554 this._pushOperationResult(returnedElement); 555 } 556 return returnedElement; 557 }, 558 559 /** 560 * Replaces HTML elements through others and handle errors if the occur in the replacement part 561 * 562 * @param {Object} request (xhrRequest) 563 * @param {Object} context (Map) 564 * @param {Object} itemIdToReplace (String|Node) - ID of the element to replace 565 * @param {String} markup - the new tag 566 */ 567 replaceHtmlItem : function(request, context, itemIdToReplace, markup) { 568 try { 569 //TODO make a detachement fixup which tries to replace the item 570 //with the correct name upon its parent form if given 571 572 573 var origIdentifier = itemIdToReplace; 574 var item = (!this._Lang.isString(itemIdToReplace)) ? itemIdToReplace : 575 this._Dom.byIdOrName(itemIdToReplace); 576 577 if (!item) { 578 throw Error(this._Lang.getMessage("ERR_ITEM_ID_NOTFOUND", null,"_AjaxResponse.replaceHtmlItem",(itemIdToReplace)? itemIdToReplace.toString():"undefined")); 579 } 580 return this._Dom.outerHTML(item, markup); 581 582 } catch (e) { 583 this._onException(request, context, "myfaces._impl.xhrCore._AjaxResponse", "replaceHTMLItem", e); 584 } 585 return null; 586 } 587 , 588 589 /*insert, three attributes can be present 590 * id = insert id 591 * before = before id 592 * after = after id 593 * 594 * the insert id is the id of the node to be inserted 595 * the before is the id if set which the component has to be inserted before 596 * the after is the id if set which the component has to be inserted after 597 **/ 598 processInsert : function(request, context, node) { 599 /*remapping global namespaces for speed and readability reasons*/ 600 var _Impl = this._Impl; 601 var _Dom = this._Dom; 602 var _Lang = this._Lang; 603 604 var insertId = node.getAttribute('id'); 605 var beforeId = node.getAttribute('before'); 606 var afterId = node.getAttribute('after'); 607 608 var isInsert = insertId && this._Lang.trim(insertId) != ""; 609 var isBefore = beforeId && this._Lang.trim(beforeId) != ""; 610 var isAfter = afterId && this._Lang.trim(afterId) != ""; 611 612 if (!isInsert) { 613 _Impl.sendError(request, context, _Impl.MALFORMEDXML, _Impl.MALFORMEDXML,this._Lang.getMessage("ERR_PPR_IDREQ")); 614 return false; 615 } 616 if (!(isBefore || isAfter)) { 617 _Impl.sendError(request, context, _Impl.MALFORMEDXML, _Impl.MALFORMEDXML,this._Lang.getMessage("ERR_PPR_INSERTBEFID")); 618 return false; 619 } 620 //either before or after but not two at the same time 621 var nodeHolder = null; 622 var parentNode = null; 623 624 625 var cDataBlock = this._Dom.concatCDATABlocks(node); 626 627 var replacementFragment; 628 if (isBefore) { 629 beforeId = this._Lang.trim(beforeId); 630 var beforeNode = this._Dom.byIdOrName(beforeId); 631 if (!beforeNode) { 632 _Impl.sendError(request, context, _Impl.MALFORMEDXML, _Impl.MALFORMEDXML,this._Lang.getMessage("ERR_PPR_INSERTBEFID_1", null,"_AjaxResponse.processInsert",beforeId)); 633 return false; 634 } 635 /** 636 *we generate a temp holder 637 *so that we can use innerHTML for 638 *generating the content upfront 639 *before inserting it" 640 **/ 641 nodeHolder = document.createElement("div"); 642 parentNode = beforeNode.parentNode; 643 parentNode.insertBefore(nodeHolder, beforeNode); 644 replacementFragment = this.replaceHtmlItem(request, context, 645 nodeHolder, cDataBlock); 646 if (replacementFragment) { 647 this._pushOperationResult(replacementFragment); 648 } 649 650 } else { 651 afterId = this._Lang.trim(afterId); 652 var afterNode = this._Dom.byIdOrName(afterId); 653 if (!afterNode) { 654 _Impl.sendError(request, context, _Impl.MALFORMEDXML, _Impl.MALFORMEDXML, this._Lang.getMessage("ERR_PPR_INSERTBEFID_2", null,"_AjaxResponse.processInsert", afterId)); 655 return false; 656 } 657 658 nodeHolder = document.createElement("div"); 659 parentNode = afterNode.parentNode; 660 661 //TODO nextsibling not working in ieMobile 6.1 we have to change the method 662 //of accessing it to something else 663 parentNode.insertBefore(nodeHolder, afterNode.nextSibling); 664 665 replacementFragment = this.replaceHtmlItem(request, context, 666 nodeHolder, cDataBlock); 667 668 if (replacementFragment) { 669 this._pushOperationResult(replacementFragment); 670 } 671 672 } 673 return true; 674 } 675 , 676 677 processDelete : function(request, context, node) { 678 var _Impl = this._Impl; 679 680 var deleteId = node.getAttribute('id'); 681 if (!deleteId) { 682 _Impl.sendError(request, context, _Impl.MALFORMEDXML, 683 _Impl.MALFORMEDXML,this._Lang.getMessage("ERR_PPR_DELID", null,"_AjaxResponse.processDelete")); 684 return false; 685 } 686 687 var item = this._Dom.byIdOrName(deleteId); 688 if (!item) { 689 throw Error(this._Lang.getMessage("ERR_PPR_UNKNOWNCID", null,"_AjaxResponse.processDelete",deleteId)); 690 } 691 692 var parentForm = this._Dom.getParent(item, "form"); 693 if (null != parentForm) { 694 this._updateForms.push(parentForm); 695 } 696 this._Dom.deleteItem(item); 697 698 return true; 699 } 700 , 701 702 processAttributes : function(request, context, node) { 703 //we now route into our attributes function to bypass 704 //IE quirks mode incompatibilities to the biggest possible extent 705 //most browsers just have to do a setAttributes but IE 706 //behaves as usual not like the official standard 707 //myfaces._impl._util.this._Dom.setAttribute(domNode, attribute, value; 708 709 var _Impl = this._Impl; 710 711 //<attributes id="id of element"> <attribute name="attribute name" value="attribute value" />* </attributes> 712 var elemId = node.getAttribute('id'); 713 if (!elemId) { 714 _Impl.sendError(request, context, _Impl.MALFORMEDXML 715 , _Impl.MALFORMEDXML, "Error in attributes, id not in xml markup"); 716 return false; 717 } 718 var childNodes = node.childNodes; 719 720 if (!childNodes) { 721 return false; 722 } 723 for (var loop2 = 0; loop2 < childNodes.length; loop2++) { 724 var attributesNode = childNodes[loop2]; 725 726 var attrName = attributesNode.getAttribute("name"); 727 var attrValue = attributesNode.getAttribute("value"); 728 729 if (!attrName) { 730 continue; 731 } 732 733 attrName = this._Lang.trim(attrName); 734 /*no value means reset*/ 735 //value can be of boolean value hence full check 736 if ('undefined' == typeof attrValue || null == attrValue) { 737 attrValue = ""; 738 } 739 740 switch (elemId) { 741 case this.P_VIEWROOT: 742 throw new Error(this._Lang.getMessage("ERR_NO_VIEWROOTATTR", null,"_AjaxResponse.processAttributes")); 743 break; 744 745 case this.P_VIEWHEAD: 746 throw new Error(this._Lang.getMessage("ERR_NO_HEADATTR", null,"_AjaxResponse.processAttributes")); 747 break; 748 749 case this.P_VIEWBODY: 750 var element = document.getElementsByTagName("body")[0]; 751 this._Dom.setAttribute(element, attrName, attrValue); 752 break; 753 754 default: 755 this._Dom.setAttribute(document.getElementById(elemId), attrName, attrValue); 756 break; 757 } 758 759 } 760 return true; 761 }, 762 _finalize: function() { 763 delete this._onException; 764 delete this._onWarning; 765 delete this._updateElems; 766 // List of forms to be updated if any inner block is updated 767 delete this._updateForms; 768 delete this.appliedViewState; 769 } 770 771 }); 772