PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/htmlunit-2.8/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/html/HTMLFormElement.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 442 lines | 256 code | 48 blank | 138 comment | 44 complexity | b6ebd3e96b7dbd144686adbf8f1807ff MD5 | raw file
  1. /*
  2. * Copyright (c) 2002-2010 Gargoyle Software Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. package com.gargoylesoftware.htmlunit.javascript.host.html;
  16. import java.io.IOException;
  17. import java.net.MalformedURLException;
  18. import java.util.ArrayList;
  19. import java.util.List;
  20. import net.sourceforge.htmlunit.corejs.javascript.Context;
  21. import net.sourceforge.htmlunit.corejs.javascript.Function;
  22. import net.sourceforge.htmlunit.corejs.javascript.Scriptable;
  23. import net.sourceforge.htmlunit.corejs.javascript.ScriptableObject;
  24. import org.apache.commons.lang.StringUtils;
  25. import com.gargoylesoftware.htmlunit.BrowserVersionFeatures;
  26. import com.gargoylesoftware.htmlunit.WebAssert;
  27. import com.gargoylesoftware.htmlunit.WebClient;
  28. import com.gargoylesoftware.htmlunit.WebRequest;
  29. import com.gargoylesoftware.htmlunit.html.DomNode;
  30. import com.gargoylesoftware.htmlunit.html.FormFieldWithNameHistory;
  31. import com.gargoylesoftware.htmlunit.html.HtmlElement;
  32. import com.gargoylesoftware.htmlunit.html.HtmlForm;
  33. import com.gargoylesoftware.htmlunit.html.HtmlImage;
  34. import com.gargoylesoftware.htmlunit.html.HtmlImageInput;
  35. import com.gargoylesoftware.htmlunit.html.HtmlPage;
  36. /**
  37. * A JavaScript object for a Form.
  38. *
  39. * @version $Revision: 5893 $
  40. * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
  41. * @author Daniel Gredler
  42. * @author Kent Tong
  43. * @author Chris Erskine
  44. * @author Marc Guillemot
  45. * @author Ahmed Ashour
  46. * @author Sudhan Moghe
  47. *
  48. * @see <a href="http://msdn.microsoft.com/en-us/library/ms535249.aspx">MSDN documentation</a>
  49. */
  50. public class HTMLFormElement extends HTMLElement implements Function {
  51. private static final long serialVersionUID = -1860993922147246513L;
  52. private HTMLCollection elements_; // has to be a member to have equality (==) working
  53. /**
  54. * Creates an instance. A default constructor is required for all JavaScript objects.
  55. */
  56. public HTMLFormElement() {
  57. // Empty.
  58. }
  59. /**
  60. * {@inheritDoc}
  61. */
  62. @Override
  63. public void setHtmlElement(final HtmlElement htmlElement) {
  64. super.setHtmlElement(htmlElement);
  65. final HtmlForm htmlForm = getHtmlForm();
  66. htmlForm.setScriptObject(this);
  67. }
  68. /**
  69. * Returns the value of the JavaScript attribute "name".
  70. * @return the value of this attribute
  71. */
  72. public String jsxGet_name() {
  73. return getHtmlForm().getNameAttribute();
  74. }
  75. /**
  76. * Sets the value of the JavaScript attribute "name".
  77. * @param name the new value
  78. */
  79. public void jsxSet_name(final String name) {
  80. WebAssert.notNull("name", name);
  81. getHtmlForm().setNameAttribute(name);
  82. }
  83. /**
  84. * Returns the value of the JavaScript attribute "elements".
  85. * @return the value of this attribute
  86. */
  87. public HTMLCollection jsxGet_elements() {
  88. if (elements_ == null) {
  89. final HtmlForm htmlForm = getHtmlForm();
  90. elements_ = new HTMLCollection(this) {
  91. private static final long serialVersionUID = -2554743215194459203L;
  92. @Override
  93. protected List<Object> computeElements() {
  94. final List<Object> response = super.computeElements();
  95. response.addAll(htmlForm.getLostChildren());
  96. return response;
  97. }
  98. @Override
  99. protected Object getWithPreemption(final String name) {
  100. final List<HtmlElement> matchingElements = new ArrayList<HtmlElement>();
  101. for (final Object o : getElements()) {
  102. final HtmlElement elt = (HtmlElement) o;
  103. if (isAccessibleByIdOrName(elt, name)) {
  104. matchingElements.add(elt);
  105. }
  106. }
  107. if (matchingElements.isEmpty()) {
  108. return NOT_FOUND;
  109. }
  110. else if (matchingElements.size() == 1) {
  111. return matchingElements.get(0).getScriptObject();
  112. }
  113. return new HTMLCollection(htmlForm, matchingElements);
  114. }
  115. };
  116. final String xpath = ".//*[(name() = 'input' or name() = 'button'"
  117. + " or name() = 'select' or name() = 'textarea')]";
  118. elements_.init(htmlForm, xpath);
  119. }
  120. return elements_;
  121. }
  122. /**
  123. * Returns the value of the JavaScript attribute "length".
  124. * Does not count input type=image elements as browsers (IE6, Mozilla 1.7) do
  125. * (cf <a href="http://msdn.microsoft.com/en-us/library/ms534101.aspx">MSDN doc</a>)
  126. * @return the value of this attribute
  127. */
  128. public int jsxGet_length() {
  129. final int all = jsxGet_elements().jsxGet_length();
  130. final int images = getHtmlForm().getElementsByAttribute("input", "type", "image").size();
  131. return all - images;
  132. }
  133. /**
  134. * Returns the value of the JavaScript attribute "action".
  135. * @return the value of this attribute
  136. */
  137. public String jsxGet_action() {
  138. String action = getHtmlForm().getActionAttribute();
  139. if (getBrowserVersion().hasFeature(BrowserVersionFeatures.GENERATED_169)) {
  140. try {
  141. action = ((HtmlPage) getHtmlForm().getPage()).getFullyQualifiedUrl(action).toExternalForm();
  142. }
  143. catch (final MalformedURLException e) {
  144. // nothing, return action attribute
  145. }
  146. }
  147. return action;
  148. }
  149. /**
  150. * Sets the value of the JavaScript attribute "action".
  151. * @param action the new value
  152. */
  153. public void jsxSet_action(final String action) {
  154. WebAssert.notNull("action", action);
  155. getHtmlForm().setActionAttribute(action);
  156. }
  157. /**
  158. * Returns the value of the JavaScript attribute "method".
  159. * @return the value of this attribute
  160. */
  161. public String jsxGet_method() {
  162. return getHtmlForm().getMethodAttribute();
  163. }
  164. /**
  165. * Sets the value of the JavaScript attribute "method".
  166. * @param method the new value
  167. */
  168. public void jsxSet_method(final String method) {
  169. WebAssert.notNull("method", method);
  170. getHtmlForm().setMethodAttribute(method);
  171. }
  172. /**
  173. * Returns the value of the JavaScript attribute "target".
  174. * @return the value of this attribute
  175. */
  176. public String jsxGet_target() {
  177. return getHtmlForm().getTargetAttribute();
  178. }
  179. /**
  180. * Returns the <tt>onsubmit</tt> event handler for this element.
  181. * @return the <tt>onsubmit</tt> event handler for this element
  182. */
  183. public Object jsxGet_onsubmit() {
  184. return getEventHandlerProp("onsubmit");
  185. }
  186. /**
  187. * Sets the <tt>onsubmit</tt> event handler for this element.
  188. * @param onsubmit the <tt>onsubmit</tt> event handler for this element
  189. */
  190. public void jsxSet_onsubmit(final Object onsubmit) {
  191. setEventHandlerProp("onsubmit", onsubmit);
  192. }
  193. /**
  194. * Sets the value of the JavaScript attribute "target".
  195. * @param target the new value
  196. */
  197. public void jsxSet_target(final String target) {
  198. WebAssert.notNull("target", target);
  199. getHtmlForm().setTargetAttribute(target);
  200. }
  201. /**
  202. * Returns the value of the JavaScript attribute "encoding".
  203. * @return the value of this attribute
  204. */
  205. public String jsxGet_encoding() {
  206. return getHtmlForm().getEnctypeAttribute();
  207. }
  208. /**
  209. * Sets the value of the JavaScript attribute "encoding".
  210. * @param encoding the new value
  211. */
  212. public void jsxSet_encoding(final String encoding) {
  213. WebAssert.notNull("encoding", encoding);
  214. getHtmlForm().setEnctypeAttribute(encoding);
  215. }
  216. private HtmlForm getHtmlForm() {
  217. return (HtmlForm) getDomNodeOrDie();
  218. }
  219. /**
  220. * Submits the form (at the end of the current script execution).
  221. *
  222. * @throws IOException if an IO error occurs
  223. */
  224. public void jsxFunction_submit()
  225. throws IOException {
  226. final HtmlPage page = (HtmlPage) getDomNodeOrDie().getPage();
  227. final WebClient webClient = page.getWebClient();
  228. final String action = getHtmlForm().getActionAttribute();
  229. if (action.startsWith("javascript:")) {
  230. final String js = StringUtils.substringAfter(action, "javascript:");
  231. webClient.getJavaScriptEngine().execute(page, js, "Form action", 0);
  232. }
  233. else {
  234. // download should be done ASAP, response will be loaded into a window later
  235. final WebRequest request = getHtmlForm().getWebRequest(null);
  236. final String target = page.getResolvedTarget(jsxGet_target());
  237. webClient.download(page.getEnclosingWindow(), target, request, "JS form.submit()");
  238. }
  239. }
  240. /**
  241. * Retrieves a form object or an object from an elements collection.
  242. * @param index Integer or String that specifies the object or collection to retrieve.
  243. * If this parameter is an integer, it is the zero-based index of the object.
  244. * If this parameter is a string, all objects with matching name or id properties are retrieved,
  245. * and a collection is returned if more than one match is made
  246. * @param subIndex Optional. Integer that specifies the zero-based index of the object to retrieve
  247. * when a collection is returned
  248. * @return an object or a collection of objects if successful, or null otherwise
  249. */
  250. public Object jsxFunction_item(final Object index, final Object subIndex) {
  251. if (index instanceof Number) {
  252. return jsxGet_elements().jsxFunction_item(index);
  253. }
  254. final HtmlForm htmlForm = getHtmlForm();
  255. final HTMLCollection elements = new HTMLCollection(this) {
  256. private static final long serialVersionUID = -2554743215194459203L;
  257. @Override
  258. protected List<Object> computeElements() {
  259. final List<Object> response = super.computeElements();
  260. response.addAll(htmlForm.getLostChildren());
  261. return response;
  262. }
  263. };
  264. final String xpath = ".//*[((name() = 'input' or name() = 'button'"
  265. + " or name() = 'select' or name() = 'textarea')) and @name='" + index + "']";
  266. elements.init(htmlForm, xpath);
  267. if (elements.getLength() == 0) {
  268. return null;
  269. }
  270. else if (elements.getLength() == 1) {
  271. return elements.jsxFunction_item(0);
  272. }
  273. if (subIndex instanceof Number) {
  274. return elements.jsxFunction_item(subIndex);
  275. }
  276. return elements;
  277. }
  278. /**
  279. * Resets this form.
  280. */
  281. public void jsxFunction_reset() {
  282. getHtmlForm().reset();
  283. }
  284. /**
  285. * Overridden to allow the retrieval of certain form elements by ID or name.
  286. *
  287. * @param name {@inheritDoc}
  288. * @return {@inheritDoc}
  289. */
  290. @Override
  291. protected Object getWithPreemption(final String name) {
  292. final List<HtmlElement> elements = findElements(name);
  293. if (elements.isEmpty()) {
  294. return NOT_FOUND;
  295. }
  296. if (elements.size() == 1) {
  297. return getScriptableFor(elements.get(0));
  298. }
  299. final HTMLCollection collection = new HTMLCollection(getHtmlForm(), elements) {
  300. protected List<Object> computeElements() {
  301. return new ArrayList<Object>(findElements(name));
  302. };
  303. };
  304. return collection;
  305. }
  306. private List<HtmlElement> findElements(final String name) {
  307. final List<HtmlElement> elements = new ArrayList<HtmlElement>();
  308. addElements(name, getHtmlForm().getHtmlElementDescendants(), elements);
  309. addElements(name, getHtmlForm().getLostChildren(), elements);
  310. // If no form fields are found, IE and Firefox are able to find img elements by ID or name.
  311. if (elements.isEmpty()) {
  312. for (final DomNode node : getHtmlForm().getChildren()) {
  313. if (node instanceof HtmlImage) {
  314. final HtmlImage img = (HtmlImage) node;
  315. if (name.equals(img.getId()) || name.equals(img.getNameAttribute())) {
  316. elements.add(img);
  317. }
  318. }
  319. }
  320. }
  321. return elements;
  322. }
  323. private void addElements(final String name, final Iterable<HtmlElement> nodes,
  324. final List<HtmlElement> addTo) {
  325. for (final HtmlElement node : nodes) {
  326. if (isAccessibleByIdOrName(node, name)) {
  327. addTo.add(node);
  328. }
  329. }
  330. }
  331. /**
  332. * Indicates if the element can be reached by id or name in expressions like "myForm.myField".
  333. * @param element the element to test
  334. * @param name the name used to address the element
  335. * @return <code>true</code> if this element matches the conditions
  336. */
  337. private boolean isAccessibleByIdOrName(final HtmlElement element, final String name) {
  338. if ((element instanceof FormFieldWithNameHistory && !(element instanceof HtmlImageInput))) {
  339. final FormFieldWithNameHistory elementWithNames = (FormFieldWithNameHistory) element;
  340. if (name.equals(elementWithNames.getOriginalName())
  341. || name.equals(element.getId())) {
  342. return true;
  343. }
  344. if (!getBrowserVersion().hasFeature(BrowserVersionFeatures.FORMFIELD_REACHABLE_BY_NEW_NAMES)) {
  345. return false;
  346. }
  347. else if (name.equals(element.getAttribute("name"))
  348. || elementWithNames.getPreviousNames().contains(name)) {
  349. return true;
  350. }
  351. }
  352. return false;
  353. }
  354. /**
  355. * Returns the specified indexed property.
  356. * @param index the index of the property
  357. * @param start the scriptable object that was originally queried for this property
  358. * @return the property
  359. */
  360. @Override
  361. public Object get(final int index, final Scriptable start) {
  362. if (getDomNodeOrNull() == null) {
  363. return NOT_FOUND; // typically for the prototype
  364. }
  365. return jsxGet_elements().get(index, ((HTMLFormElement) start).jsxGet_elements());
  366. }
  367. /**
  368. * {@inheritDoc}
  369. */
  370. public Object call(final Context cx, final Scriptable scope, final Scriptable thisObj, final Object[] args) {
  371. if (!getBrowserVersion().hasFeature(BrowserVersionFeatures.GENERATED_80)) {
  372. throw Context.reportRuntimeError("Not a function.");
  373. }
  374. if (args.length > 0) {
  375. final Object arg = args[0];
  376. if (arg instanceof String) {
  377. return ScriptableObject.getProperty(this, (String) arg);
  378. }
  379. else if (arg instanceof Number) {
  380. return ScriptableObject.getProperty(this, ((Number) arg).intValue());
  381. }
  382. }
  383. return Context.getUndefinedValue();
  384. }
  385. /**
  386. * {@inheritDoc}
  387. */
  388. public Scriptable construct(final Context cx, final Scriptable scope, final Object[] args) {
  389. if (!getBrowserVersion().hasFeature(BrowserVersionFeatures.GENERATED_81)) {
  390. throw Context.reportRuntimeError("Not a function.");
  391. }
  392. return null;
  393. }
  394. }