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 * @class 18 * @name _AjaxUtils 19 * @memberOf myfaces._impl.xhrCore 20 * @extends myfaces._impl.xhrCore._FinalizeableObj 21 * @description 22 * 23 * A set of helper routines which are utilized within our Ajax subsystem and nowhere else 24 */ 25 myfaces._impl.core._Runtime.extendClass("myfaces._impl.xhrCore._AjaxUtils", myfaces._impl.xhrCore._FinalizeableObj, 26 /** @lends myfaces._impl.xhrCore._AjaxUtils.prototype */ 27 { 28 _processedExceptions: {}, 29 30 /** 31 * Constructor 32 * @param {function} onException - exception handler 33 * @param {function} onWarning - warning handler 34 */ 35 constructor_ : function(onException, onWarning) { 36 this._onException = onException; 37 this._onWarning = onWarning; 38 }, 39 40 41 /** 42 * determines fields to submit 43 * @param {Object} request the xhr request object 44 * @param {Object} context (Map) 45 * @param {Node} item - item that triggered the event 46 * @param {Node} parentItem - form element item is nested in 47 * @param {Array} partialIds - ids fo PPS 48 */ 49 encodeSubmittableFields : function(targetBuf, request, context, item, 50 parentItem, partialIds) { 51 52 try { 53 if (!parentItem) { 54 this._onWarning(request, context, "myfaces._impl.xhrCore._AjaxUtils", "encodeSubmittableFields " + "Html-Component is not nested in a Form-Tag"); 55 return null; 56 } 57 58 if (partialIds && partialIds.length > 0) { 59 this.encodePartialSubmit(parentItem, item, false, partialIds, targetBuf); 60 } else { 61 // add all nodes 62 var eLen = parentItem.elements.length; 63 for (var e = 0; e < eLen; e++) { 64 this.encodeElement(parentItem.elements[e], targetBuf); 65 } // end of for (formElements) 66 } 67 68 this.appendIssuingItem(item, targetBuf); 69 } catch (e) { 70 this._onException(request, context, "myfaces._impl.xhrCore._AjaxUtils", "encodeSubmittableFields", e); 71 } 72 }, 73 74 /** 75 * checks recursively if contained in PPS 76 * the algorithm is as follows we have an issuing item 77 * the parent form of the issuing item and a set of child ids which do not 78 * have to be inputs, we scan now for those ids and all inputs which are childs 79 * of those ids 80 * 81 * Now this algorithm is up for discussion because it is relatively complex 82 * but for now we will leave it as it is. 83 * 84 * @param {Node} node - the root node of the partial page submit 85 * @param {boolean} submitAll - if set to true, all elements within this node will 86 * be added to the partial page submit 87 * @param {Array} partialIds - an array of partial ids which should be used for the submit 88 * @param {Array} targetBuf a target string buffer which receives the encoded elements 89 */ 90 encodePartialSubmit : function(node, issuingItem, submitAll, 91 partialIds, targetBuf) { 92 var _Lang = myfaces._impl._util._Lang; 93 var _Impl = myfaces._impl.core.Impl; 94 var _Dom = myfaces._impl._util._Dom; 95 96 var partialIdsFilter = function(curNode) { 97 if (curNode.nodeType != 1) return false; 98 if (submitAll && node != curNode) return true; 99 100 var id = curNode.id || curNode.name; 101 102 return (id && _Lang.contains(partialIds, id)) || id == _Impl.P_VIEWSTATE; 103 }; 104 105 //shallow scan because we have a second scanning step, to find the encodable childs of 106 //the result nodes, that way we can reduce the number of nodes 107 var nodes = _Dom.findAll(node, partialIdsFilter, false); 108 109 var allowedTagNames = {"input":true, "select":true, "textarea":true}; 110 111 if (nodes && nodes.length) { 112 for (var cnt = 0; cnt < nodes.length; cnt++) { 113 //we can shortcut the form any other nodetype 114 //must get a separate investigation 115 var subNodes = (nodes[cnt].tagName.toLowerCase() == "form") ? 116 node.elements : 117 _Dom.findByTagNames(nodes[cnt], allowedTagNames, true); 118 119 if (subNodes && subNodes.length) { 120 for (var cnt2 = 0; cnt2 < subNodes.length; cnt2++) { 121 this.encodeElement(subNodes[cnt2], targetBuf); 122 } 123 } else { 124 this.encodeElement(nodes[cnt], targetBuf); 125 } 126 } 127 } 128 129 this.appendViewState(node, targetBuf); 130 }, 131 132 /** 133 * appends the viewstate element if not given already 134 * 135 * @param parentNode 136 * @param targetBuf 137 * 138 * TODO dom level2 handling here, for dom level2 we can omit the check and readd the viewstate 139 */ 140 appendViewState: function(parentNode, targetBuf) { 141 var _Dom = myfaces._impl._util._Dom; 142 var _Impl = myfaces._impl.core.Impl; 143 144 //viewstate covered, do a preemptive check 145 if (targetBuf.hasKey(_Impl.P_VIEWSTATE)) return; 146 147 var viewStates = _Dom.findByName(parentNode, _Impl.P_VIEWSTATE, true); 148 if (viewStates && viewStates.length) { 149 for (var cnt2 = 0; cnt2 < viewStates.length; cnt2++) { 150 this.encodeElement(viewStates[cnt2], targetBuf); 151 } 152 } 153 }, 154 155 /** 156 * appends the issuing item if not given already 157 * @param item 158 * @param targetBuf 159 */ 160 appendIssuingItem: function (item, targetBuf) { 161 // if triggered by a Button send it along 162 if (item && item.type && item.type.toLowerCase() == "submit") { 163 targetBuf.append(item.name, item.value); 164 } 165 }, 166 167 168 /** 169 * encodes a single input element for submission 170 * 171 * @param {Node} element - to be encoded 172 * @param {} targetBuf - a target array buffer receiving the encoded strings 173 */ 174 encodeElement : function(element, targetBuf) { 175 176 //browser behavior no element name no encoding (normal submit fails in that case) 177 //https://issues.apache.org/jira/browse/MYFACES-2847 178 if (!element.name) { 179 return; 180 } 181 182 var _RT = myfaces._impl.core._Runtime; 183 var name = element.name; 184 var tagName = element.tagName.toLowerCase(); 185 var elemType = element.type; 186 if (elemType != null) { 187 elemType = elemType.toLowerCase(); 188 } 189 190 // routine for all elements 191 // rules: 192 // - process only inputs, textareas and selects 193 // - elements muest have attribute "name" 194 // - elements must not be disabled 195 if (((tagName == "input" || tagName == "textarea" || tagName == "select") && 196 (name != null && name != "")) && !element.disabled) { 197 198 // routine for select elements 199 // rules: 200 // - if select-one and value-Attribute exist => "name=value" 201 // (also if value empty => "name=") 202 // - if select-one and value-Attribute don't exist => 203 // "name=DisplayValue" 204 // - if select multi and multple selected => "name=value1&name=value2" 205 // - if select and selectedIndex=-1 don't submit 206 if (tagName == "select") { 207 // selectedIndex must be >= 0 sein to be submittet 208 if (element.selectedIndex >= 0) { 209 var uLen = element.options.length; 210 for (var u = 0; u < uLen; u++) { 211 // find all selected options 212 //var subBuf = []; 213 if (element.options[u].selected) { 214 var elementOption = element.options[u]; 215 targetBuf.append(name, (elementOption.getAttribute("value") != null) ? 216 elementOption.value : elementOption.text); 217 } 218 } 219 } 220 } 221 222 // routine for remaining elements 223 // rules: 224 // - don't submit no selects (processed above), buttons, reset buttons, submit buttons, 225 // - submit checkboxes and radio inputs only if checked 226 if ((tagName != "select" && elemType != "button" 227 && elemType != "reset" && elemType != "submit" && elemType != "image") 228 && ((elemType != "checkbox" && elemType != "radio") || element.checked)) { 229 if ('undefined' != typeof element.files && element.files != null && _RT.getXHRLvl() >= 2 && element.files.length) { 230 //xhr level2 231 targetBuf.append(name, element.files[0]); 232 } else { 233 targetBuf.append(name, element.value); 234 } 235 } 236 237 } 238 }, 239 240 _finalize: function() { 241 delete this._onException; 242 delete this._onWarning; 243 } 244 245 });