HTMLSelectElement.cpp 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "mozilla/dom/HTMLSelectElement.h"
  6. #include "mozAutoDocUpdate.h"
  7. #include "mozilla/Attributes.h"
  8. #include "mozilla/BasicEvents.h"
  9. #include "mozilla/EventDispatcher.h"
  10. #include "mozilla/EventStates.h"
  11. #include "mozilla/dom/Element.h"
  12. #include "mozilla/dom/HTMLFormSubmission.h"
  13. #include "mozilla/dom/HTMLOptGroupElement.h"
  14. #include "mozilla/dom/HTMLOptionElement.h"
  15. #include "mozilla/dom/HTMLSelectElementBinding.h"
  16. #include "mozilla/dom/UnionTypes.h"
  17. #include "nsContentCreatorFunctions.h"
  18. #include "nsContentList.h"
  19. #include "nsError.h"
  20. #include "nsGkAtoms.h"
  21. #include "nsIComboboxControlFrame.h"
  22. #include "nsIDocument.h"
  23. #include "nsIFormControlFrame.h"
  24. #include "nsIForm.h"
  25. #include "nsIFormProcessor.h"
  26. #include "nsIFrame.h"
  27. #include "nsIListControlFrame.h"
  28. #include "nsISelectControlFrame.h"
  29. #include "nsLayoutUtils.h"
  30. #include "nsMappedAttributes.h"
  31. #include "nsPresState.h"
  32. #include "nsRuleData.h"
  33. #include "nsServiceManagerUtils.h"
  34. #include "nsStyleConsts.h"
  35. #include "nsTextNode.h"
  36. NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Select)
  37. namespace mozilla {
  38. namespace dom {
  39. NS_IMPL_ISUPPORTS(SelectState, SelectState)
  40. //----------------------------------------------------------------------
  41. //
  42. // SafeOptionListMutation
  43. //
  44. SafeOptionListMutation::SafeOptionListMutation(nsIContent* aSelect,
  45. nsIContent* aParent,
  46. nsIContent* aKid,
  47. uint32_t aIndex,
  48. bool aNotify)
  49. : mSelect(HTMLSelectElement::FromContentOrNull(aSelect))
  50. , mTopLevelMutation(false)
  51. , mNeedsRebuild(false)
  52. {
  53. if (mSelect) {
  54. mTopLevelMutation = !mSelect->mMutating;
  55. if (mTopLevelMutation) {
  56. mSelect->mMutating = true;
  57. } else {
  58. // This is very unfortunate, but to handle mutation events properly,
  59. // option list must be up-to-date before inserting or removing options.
  60. // Fortunately this is called only if mutation event listener
  61. // adds or removes options.
  62. mSelect->RebuildOptionsArray(aNotify);
  63. }
  64. nsresult rv;
  65. if (aKid) {
  66. rv = mSelect->WillAddOptions(aKid, aParent, aIndex, aNotify);
  67. } else {
  68. rv = mSelect->WillRemoveOptions(aParent, aIndex, aNotify);
  69. }
  70. mNeedsRebuild = NS_FAILED(rv);
  71. }
  72. }
  73. SafeOptionListMutation::~SafeOptionListMutation()
  74. {
  75. if (mSelect) {
  76. if (mNeedsRebuild || (mTopLevelMutation && mGuard.Mutated(1))) {
  77. mSelect->RebuildOptionsArray(true);
  78. }
  79. if (mTopLevelMutation) {
  80. mSelect->mMutating = false;
  81. }
  82. #ifdef DEBUG
  83. mSelect->VerifyOptionsArray();
  84. #endif
  85. }
  86. }
  87. //----------------------------------------------------------------------
  88. //
  89. // HTMLSelectElement
  90. //
  91. // construction, destruction
  92. HTMLSelectElement::HTMLSelectElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
  93. FromParser aFromParser)
  94. : nsGenericHTMLFormElementWithState(aNodeInfo),
  95. mOptions(new HTMLOptionsCollection(this)),
  96. mAutocompleteAttrState(nsContentUtils::eAutocompleteAttrState_Unknown),
  97. mIsDoneAddingChildren(!aFromParser),
  98. mDisabledChanged(false),
  99. mMutating(false),
  100. mInhibitStateRestoration(!!(aFromParser & FROM_PARSER_FRAGMENT)),
  101. mSelectionHasChanged(false),
  102. mDefaultSelectionSet(false),
  103. mCanShowInvalidUI(true),
  104. mCanShowValidUI(true),
  105. mNonOptionChildren(0),
  106. mOptGroupCount(0),
  107. mSelectedIndex(-1)
  108. {
  109. SetHasWeirdParserInsertionMode();
  110. // DoneAddingChildren() will be called later if it's from the parser,
  111. // otherwise it is
  112. // Set up our default state: enabled, optional, and valid.
  113. AddStatesSilently(NS_EVENT_STATE_ENABLED |
  114. NS_EVENT_STATE_OPTIONAL |
  115. NS_EVENT_STATE_VALID);
  116. }
  117. // ISupports
  118. NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLSelectElement)
  119. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLSelectElement,
  120. nsGenericHTMLFormElementWithState)
  121. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mValidity)
  122. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOptions)
  123. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectedOptions)
  124. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  125. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLSelectElement,
  126. nsGenericHTMLFormElementWithState)
  127. NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)
  128. NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelectedOptions)
  129. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  130. NS_IMPL_ADDREF_INHERITED(HTMLSelectElement, Element)
  131. NS_IMPL_RELEASE_INHERITED(HTMLSelectElement, Element)
  132. // QueryInterface implementation for HTMLSelectElement
  133. NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLSelectElement)
  134. NS_INTERFACE_TABLE_INHERITED(HTMLSelectElement,
  135. nsIDOMHTMLSelectElement,
  136. nsIConstraintValidation)
  137. NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLFormElementWithState)
  138. // nsIDOMHTMLSelectElement
  139. NS_IMPL_ELEMENT_CLONE(HTMLSelectElement)
  140. // nsIConstraintValidation
  141. NS_IMPL_NSICONSTRAINTVALIDATION_EXCEPT_SETCUSTOMVALIDITY(HTMLSelectElement)
  142. NS_IMETHODIMP
  143. HTMLSelectElement::SetCustomValidity(const nsAString& aError)
  144. {
  145. nsIConstraintValidation::SetCustomValidity(aError);
  146. UpdateState(true);
  147. return NS_OK;
  148. }
  149. void
  150. HTMLSelectElement::GetAutocomplete(DOMString& aValue)
  151. {
  152. const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
  153. mAutocompleteAttrState =
  154. nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aValue,
  155. mAutocompleteAttrState);
  156. }
  157. NS_IMETHODIMP
  158. HTMLSelectElement::GetForm(nsIDOMHTMLFormElement** aForm)
  159. {
  160. return nsGenericHTMLFormElementWithState::GetForm(aForm);
  161. }
  162. nsresult
  163. HTMLSelectElement::InsertChildAt(nsIContent* aKid,
  164. uint32_t aIndex,
  165. bool aNotify)
  166. {
  167. SafeOptionListMutation safeMutation(this, this, aKid, aIndex, aNotify);
  168. nsresult rv = nsGenericHTMLFormElementWithState::InsertChildAt(aKid, aIndex,
  169. aNotify);
  170. if (NS_FAILED(rv)) {
  171. safeMutation.MutationFailed();
  172. }
  173. return rv;
  174. }
  175. void
  176. HTMLSelectElement::RemoveChildAt(uint32_t aIndex, bool aNotify)
  177. {
  178. SafeOptionListMutation safeMutation(this, this, nullptr, aIndex, aNotify);
  179. nsGenericHTMLFormElementWithState::RemoveChildAt(aIndex, aNotify);
  180. }
  181. void
  182. HTMLSelectElement::InsertOptionsIntoList(nsIContent* aOptions,
  183. int32_t aListIndex,
  184. int32_t aDepth,
  185. bool aNotify)
  186. {
  187. MOZ_ASSERT(aDepth == 0 || aDepth == 1);
  188. int32_t insertIndex = aListIndex;
  189. HTMLOptionElement* optElement = HTMLOptionElement::FromContent(aOptions);
  190. if (optElement) {
  191. mOptions->InsertOptionAt(optElement, insertIndex);
  192. insertIndex++;
  193. } else if (aDepth == 0) {
  194. // If it's at the top level, then we just found out there are non-options
  195. // at the top level, which will throw off the insert count
  196. mNonOptionChildren++;
  197. // Deal with optgroups
  198. if (aOptions->IsHTMLElement(nsGkAtoms::optgroup)) {
  199. mOptGroupCount++;
  200. for (nsIContent* child = aOptions->GetFirstChild();
  201. child;
  202. child = child->GetNextSibling()) {
  203. optElement = HTMLOptionElement::FromContent(child);
  204. if (optElement) {
  205. mOptions->InsertOptionAt(optElement, insertIndex);
  206. insertIndex++;
  207. }
  208. }
  209. }
  210. } // else ignore even if optgroup; we want to ignore nested optgroups.
  211. // Deal with the selected list
  212. if (insertIndex - aListIndex) {
  213. // Fix the currently selected index
  214. if (aListIndex <= mSelectedIndex) {
  215. mSelectedIndex += (insertIndex - aListIndex);
  216. SetSelectionChanged(true, aNotify);
  217. }
  218. // Get the frame stuff for notification. No need to flush here
  219. // since if there's no frame for the select yet the select will
  220. // get into the right state once it's created.
  221. nsISelectControlFrame* selectFrame = nullptr;
  222. nsWeakFrame weakSelectFrame;
  223. bool didGetFrame = false;
  224. // Actually select the options if the added options warrant it
  225. for (int32_t i = aListIndex; i < insertIndex; i++) {
  226. // Notify the frame that the option is added
  227. if (!didGetFrame || (selectFrame && !weakSelectFrame.IsAlive())) {
  228. selectFrame = GetSelectFrame();
  229. weakSelectFrame = do_QueryFrame(selectFrame);
  230. didGetFrame = true;
  231. }
  232. if (selectFrame) {
  233. selectFrame->AddOption(i);
  234. }
  235. RefPtr<HTMLOptionElement> option = Item(i);
  236. if (option && option->Selected()) {
  237. // Clear all other options
  238. if (!HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) {
  239. uint32_t mask = IS_SELECTED | CLEAR_ALL | SET_DISABLED | NOTIFY;
  240. SetOptionsSelectedByIndex(i, i, mask);
  241. }
  242. // This is sort of a hack ... we need to notify that the option was
  243. // set and change selectedIndex even though we didn't really change
  244. // its value.
  245. OnOptionSelected(selectFrame, i, true, false, false);
  246. }
  247. }
  248. CheckSelectSomething(aNotify);
  249. }
  250. }
  251. nsresult
  252. HTMLSelectElement::RemoveOptionsFromList(nsIContent* aOptions,
  253. int32_t aListIndex,
  254. int32_t aDepth,
  255. bool aNotify)
  256. {
  257. MOZ_ASSERT(aDepth == 0 || aDepth == 1);
  258. int32_t numRemoved = 0;
  259. HTMLOptionElement* optElement = HTMLOptionElement::FromContent(aOptions);
  260. if (optElement) {
  261. if (mOptions->ItemAsOption(aListIndex) != optElement) {
  262. NS_ERROR("wrong option at index");
  263. return NS_ERROR_UNEXPECTED;
  264. }
  265. mOptions->RemoveOptionAt(aListIndex);
  266. numRemoved++;
  267. } else if (aDepth == 0) {
  268. // Yay, one less artifact at the top level.
  269. mNonOptionChildren--;
  270. // Recurse down deeper for options
  271. if (mOptGroupCount && aOptions->IsHTMLElement(nsGkAtoms::optgroup)) {
  272. mOptGroupCount--;
  273. for (nsIContent* child = aOptions->GetFirstChild();
  274. child;
  275. child = child->GetNextSibling()) {
  276. optElement = HTMLOptionElement::FromContent(child);
  277. if (optElement) {
  278. if (mOptions->ItemAsOption(aListIndex) != optElement) {
  279. NS_ERROR("wrong option at index");
  280. return NS_ERROR_UNEXPECTED;
  281. }
  282. mOptions->RemoveOptionAt(aListIndex);
  283. numRemoved++;
  284. }
  285. }
  286. }
  287. } // else don't check for an optgroup; we want to ignore nested optgroups
  288. if (numRemoved) {
  289. // Tell the widget we removed the options
  290. nsISelectControlFrame* selectFrame = GetSelectFrame();
  291. if (selectFrame) {
  292. nsAutoScriptBlocker scriptBlocker;
  293. for (int32_t i = aListIndex; i < aListIndex + numRemoved; ++i) {
  294. selectFrame->RemoveOption(i);
  295. }
  296. }
  297. // Fix the selected index
  298. if (aListIndex <= mSelectedIndex) {
  299. if (mSelectedIndex < (aListIndex+numRemoved)) {
  300. // aListIndex <= mSelectedIndex < aListIndex+numRemoved
  301. // Find a new selected index if it was one of the ones removed.
  302. FindSelectedIndex(aListIndex, aNotify);
  303. } else {
  304. // Shift the selected index if something in front of it was removed
  305. // aListIndex+numRemoved <= mSelectedIndex
  306. mSelectedIndex -= numRemoved;
  307. SetSelectionChanged(true, aNotify);
  308. }
  309. }
  310. // Select something in case we removed the selected option on a
  311. // single select
  312. if (!CheckSelectSomething(aNotify) && mSelectedIndex == -1) {
  313. // Update the validity state in case of we've just removed the last
  314. // option.
  315. UpdateValueMissingValidityState();
  316. UpdateState(aNotify);
  317. }
  318. }
  319. return NS_OK;
  320. }
  321. // XXXldb Doing the processing before the content nodes have been added
  322. // to the document (as the name of this function seems to require, and
  323. // as the callers do), is highly unusual. Passing around unparented
  324. // content to other parts of the app can make those things think the
  325. // options are the root content node.
  326. NS_IMETHODIMP
  327. HTMLSelectElement::WillAddOptions(nsIContent* aOptions,
  328. nsIContent* aParent,
  329. int32_t aContentIndex,
  330. bool aNotify)
  331. {
  332. if (this != aParent && this != aParent->GetParent()) {
  333. return NS_OK;
  334. }
  335. int32_t level = aParent == this ? 0 : 1;
  336. // Get the index where the options will be inserted
  337. int32_t ind = -1;
  338. if (!mNonOptionChildren) {
  339. // If there are no artifacts, aContentIndex == ind
  340. ind = aContentIndex;
  341. } else {
  342. // If there are artifacts, we have to get the index of the option the
  343. // hard way
  344. int32_t children = aParent->GetChildCount();
  345. if (aContentIndex >= children) {
  346. // If the content insert is after the end of the parent, then we want to get
  347. // the next index *after* the parent and insert there.
  348. ind = GetOptionIndexAfter(aParent);
  349. } else {
  350. // If the content insert is somewhere in the middle of the container, then
  351. // we want to get the option currently at the index and insert in front of
  352. // that.
  353. nsIContent* currentKid = aParent->GetChildAt(aContentIndex);
  354. NS_ASSERTION(currentKid, "Child not found!");
  355. if (currentKid) {
  356. ind = GetOptionIndexAt(currentKid);
  357. } else {
  358. ind = -1;
  359. }
  360. }
  361. }
  362. InsertOptionsIntoList(aOptions, ind, level, aNotify);
  363. return NS_OK;
  364. }
  365. NS_IMETHODIMP
  366. HTMLSelectElement::WillRemoveOptions(nsIContent* aParent,
  367. int32_t aContentIndex,
  368. bool aNotify)
  369. {
  370. if (this != aParent && this != aParent->GetParent()) {
  371. return NS_OK;
  372. }
  373. int32_t level = this == aParent ? 0 : 1;
  374. // Get the index where the options will be removed
  375. nsIContent* currentKid = aParent->GetChildAt(aContentIndex);
  376. if (currentKid) {
  377. int32_t ind;
  378. if (!mNonOptionChildren) {
  379. // If there are no artifacts, aContentIndex == ind
  380. ind = aContentIndex;
  381. } else {
  382. // If there are artifacts, we have to get the index of the option the
  383. // hard way
  384. ind = GetFirstOptionIndex(currentKid);
  385. }
  386. if (ind != -1) {
  387. nsresult rv = RemoveOptionsFromList(currentKid, ind, level, aNotify);
  388. NS_ENSURE_SUCCESS(rv, rv);
  389. }
  390. }
  391. return NS_OK;
  392. }
  393. int32_t
  394. HTMLSelectElement::GetOptionIndexAt(nsIContent* aOptions)
  395. {
  396. // Search this node and below.
  397. // If not found, find the first one *after* this node.
  398. int32_t retval = GetFirstOptionIndex(aOptions);
  399. if (retval == -1) {
  400. retval = GetOptionIndexAfter(aOptions);
  401. }
  402. return retval;
  403. }
  404. int32_t
  405. HTMLSelectElement::GetOptionIndexAfter(nsIContent* aOptions)
  406. {
  407. // - If this is the select, the next option is the last.
  408. // - If not, search all the options after aOptions and up to the last option
  409. // in the parent.
  410. // - If it's not there, search for the first option after the parent.
  411. if (aOptions == this) {
  412. return Length();
  413. }
  414. int32_t retval = -1;
  415. nsCOMPtr<nsIContent> parent = aOptions->GetParent();
  416. if (parent) {
  417. int32_t index = parent->IndexOf(aOptions);
  418. int32_t count = parent->GetChildCount();
  419. retval = GetFirstChildOptionIndex(parent, index+1, count);
  420. if (retval == -1) {
  421. retval = GetOptionIndexAfter(parent);
  422. }
  423. }
  424. return retval;
  425. }
  426. int32_t
  427. HTMLSelectElement::GetFirstOptionIndex(nsIContent* aOptions)
  428. {
  429. int32_t listIndex = -1;
  430. HTMLOptionElement* optElement = HTMLOptionElement::FromContent(aOptions);
  431. if (optElement) {
  432. GetOptionIndex(optElement, 0, true, &listIndex);
  433. return listIndex;
  434. }
  435. listIndex = GetFirstChildOptionIndex(aOptions, 0, aOptions->GetChildCount());
  436. return listIndex;
  437. }
  438. int32_t
  439. HTMLSelectElement::GetFirstChildOptionIndex(nsIContent* aOptions,
  440. int32_t aStartIndex,
  441. int32_t aEndIndex)
  442. {
  443. int32_t retval = -1;
  444. for (int32_t i = aStartIndex; i < aEndIndex; ++i) {
  445. retval = GetFirstOptionIndex(aOptions->GetChildAt(i));
  446. if (retval != -1) {
  447. break;
  448. }
  449. }
  450. return retval;
  451. }
  452. nsISelectControlFrame*
  453. HTMLSelectElement::GetSelectFrame()
  454. {
  455. nsIFormControlFrame* form_control_frame = GetFormControlFrame(false);
  456. nsISelectControlFrame* select_frame = nullptr;
  457. if (form_control_frame) {
  458. select_frame = do_QueryFrame(form_control_frame);
  459. }
  460. return select_frame;
  461. }
  462. void
  463. HTMLSelectElement::Add(const HTMLOptionElementOrHTMLOptGroupElement& aElement,
  464. const Nullable<HTMLElementOrLong>& aBefore,
  465. ErrorResult& aRv)
  466. {
  467. nsGenericHTMLElement& element =
  468. aElement.IsHTMLOptionElement() ?
  469. static_cast<nsGenericHTMLElement&>(aElement.GetAsHTMLOptionElement()) :
  470. static_cast<nsGenericHTMLElement&>(aElement.GetAsHTMLOptGroupElement());
  471. if (aBefore.IsNull()) {
  472. Add(element, static_cast<nsGenericHTMLElement*>(nullptr), aRv);
  473. } else if (aBefore.Value().IsHTMLElement()) {
  474. Add(element, &aBefore.Value().GetAsHTMLElement(), aRv);
  475. } else {
  476. Add(element, aBefore.Value().GetAsLong(), aRv);
  477. }
  478. }
  479. void
  480. HTMLSelectElement::Add(nsGenericHTMLElement& aElement,
  481. nsGenericHTMLElement* aBefore,
  482. ErrorResult& aError)
  483. {
  484. if (!aBefore) {
  485. Element::AppendChild(aElement, aError);
  486. return;
  487. }
  488. // Just in case we're not the parent, get the parent of the reference
  489. // element
  490. nsCOMPtr<nsINode> parent = aBefore->Element::GetParentNode();
  491. if (!parent || !nsContentUtils::ContentIsDescendantOf(parent, this)) {
  492. // NOT_FOUND_ERR: Raised if before is not a descendant of the SELECT
  493. // element.
  494. aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
  495. return;
  496. }
  497. // If the before parameter is not null, we are equivalent to the
  498. // insertBefore method on the parent of before.
  499. nsCOMPtr<nsINode> refNode = aBefore;
  500. parent->InsertBefore(aElement, refNode, aError);
  501. }
  502. NS_IMETHODIMP
  503. HTMLSelectElement::Add(nsIDOMHTMLElement* aElement,
  504. nsIVariant* aBefore)
  505. {
  506. uint16_t dataType;
  507. nsresult rv = aBefore->GetDataType(&dataType);
  508. NS_ENSURE_SUCCESS(rv, rv);
  509. nsCOMPtr<nsIContent> element = do_QueryInterface(aElement);
  510. nsGenericHTMLElement* htmlElement =
  511. nsGenericHTMLElement::FromContentOrNull(element);
  512. if (!htmlElement) {
  513. return NS_ERROR_NULL_POINTER;
  514. }
  515. // aBefore is omitted, undefined or null
  516. if (dataType == nsIDataType::VTYPE_EMPTY ||
  517. dataType == nsIDataType::VTYPE_VOID) {
  518. ErrorResult error;
  519. Add(*htmlElement, (nsGenericHTMLElement*)nullptr, error);
  520. return error.StealNSResult();
  521. }
  522. nsCOMPtr<nsISupports> supports;
  523. // whether aBefore is nsIDOMHTMLElement...
  524. if (NS_SUCCEEDED(aBefore->GetAsISupports(getter_AddRefs(supports)))) {
  525. nsCOMPtr<nsIContent> beforeElement = do_QueryInterface(supports);
  526. nsGenericHTMLElement* beforeHTMLElement =
  527. nsGenericHTMLElement::FromContentOrNull(beforeElement);
  528. NS_ENSURE_TRUE(beforeHTMLElement, NS_ERROR_DOM_SYNTAX_ERR);
  529. ErrorResult error;
  530. Add(*htmlElement, beforeHTMLElement, error);
  531. return error.StealNSResult();
  532. }
  533. // otherwise, whether aBefore is long
  534. int32_t index;
  535. NS_ENSURE_SUCCESS(aBefore->GetAsInt32(&index), NS_ERROR_DOM_SYNTAX_ERR);
  536. ErrorResult error;
  537. Add(*htmlElement, index, error);
  538. return error.StealNSResult();
  539. }
  540. NS_IMETHODIMP
  541. HTMLSelectElement::Remove(int32_t aIndex)
  542. {
  543. nsCOMPtr<nsINode> option = Item(static_cast<uint32_t>(aIndex));
  544. if (!option) {
  545. return NS_OK;
  546. }
  547. option->Remove();
  548. return NS_OK;
  549. }
  550. NS_IMETHODIMP
  551. HTMLSelectElement::GetOptions(nsIDOMHTMLOptionsCollection** aValue)
  552. {
  553. NS_IF_ADDREF(*aValue = GetOptions());
  554. return NS_OK;
  555. }
  556. NS_IMETHODIMP
  557. HTMLSelectElement::GetType(nsAString& aType)
  558. {
  559. if (HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) {
  560. aType.AssignLiteral("select-multiple");
  561. }
  562. else {
  563. aType.AssignLiteral("select-one");
  564. }
  565. return NS_OK;
  566. }
  567. NS_IMETHODIMP
  568. HTMLSelectElement::GetLength(uint32_t* aLength)
  569. {
  570. return mOptions->GetLength(aLength);
  571. }
  572. #define MAX_DYNAMIC_SELECT_LENGTH 10000
  573. NS_IMETHODIMP
  574. HTMLSelectElement::SetLength(uint32_t aLength)
  575. {
  576. ErrorResult rv;
  577. SetLength(aLength, rv);
  578. return rv.StealNSResult();
  579. }
  580. void
  581. HTMLSelectElement::SetLength(uint32_t aLength, ErrorResult& aRv)
  582. {
  583. uint32_t curlen = Length();
  584. if (curlen > aLength) { // Remove extra options
  585. for (uint32_t i = curlen; i > aLength; --i) {
  586. MOZ_ALWAYS_SUCCEEDS(Remove(i - 1));
  587. }
  588. } else if (aLength > curlen) {
  589. if (aLength > MAX_DYNAMIC_SELECT_LENGTH) {
  590. aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
  591. return;
  592. }
  593. RefPtr<mozilla::dom::NodeInfo> nodeInfo;
  594. nsContentUtils::NameChanged(mNodeInfo, nsGkAtoms::option,
  595. getter_AddRefs(nodeInfo));
  596. nsCOMPtr<nsINode> node = NS_NewHTMLOptionElement(nodeInfo.forget());
  597. RefPtr<nsTextNode> text = new nsTextNode(mNodeInfo->NodeInfoManager());
  598. aRv = node->AppendChildTo(text, false);
  599. if (aRv.Failed()) {
  600. return;
  601. }
  602. for (uint32_t i = curlen; i < aLength; i++) {
  603. nsINode::AppendChild(*node, aRv);
  604. if (aRv.Failed()) {
  605. return;
  606. }
  607. if (i + 1 < aLength) {
  608. node = node->CloneNode(true, aRv);
  609. if (aRv.Failed()) {
  610. return;
  611. }
  612. MOZ_ASSERT(node);
  613. }
  614. }
  615. }
  616. }
  617. /* static */
  618. bool
  619. HTMLSelectElement::MatchSelectedOptions(Element* aElement,
  620. int32_t /* unused */,
  621. nsIAtom* /* unused */,
  622. void* /* unused*/)
  623. {
  624. HTMLOptionElement* option = HTMLOptionElement::FromContent(aElement);
  625. return option && option->Selected();
  626. }
  627. nsIHTMLCollection*
  628. HTMLSelectElement::SelectedOptions()
  629. {
  630. if (!mSelectedOptions) {
  631. mSelectedOptions = new nsContentList(this, MatchSelectedOptions, nullptr,
  632. nullptr, /* deep */ true);
  633. }
  634. return mSelectedOptions;
  635. }
  636. NS_IMETHODIMP
  637. HTMLSelectElement::GetSelectedOptions(nsIDOMHTMLCollection** aSelectedOptions)
  638. {
  639. NS_ADDREF(*aSelectedOptions = SelectedOptions());
  640. return NS_OK;
  641. }
  642. //NS_IMPL_INT_ATTR(HTMLSelectElement, SelectedIndex, selectedindex)
  643. NS_IMETHODIMP
  644. HTMLSelectElement::GetSelectedIndex(int32_t* aValue)
  645. {
  646. *aValue = SelectedIndex();
  647. return NS_OK;
  648. }
  649. nsresult
  650. HTMLSelectElement::SetSelectedIndexInternal(int32_t aIndex, bool aNotify)
  651. {
  652. int32_t oldSelectedIndex = mSelectedIndex;
  653. uint32_t mask = IS_SELECTED | CLEAR_ALL | SET_DISABLED;
  654. if (aNotify) {
  655. mask |= NOTIFY;
  656. }
  657. SetOptionsSelectedByIndex(aIndex, aIndex, mask);
  658. nsresult rv = NS_OK;
  659. nsISelectControlFrame* selectFrame = GetSelectFrame();
  660. if (selectFrame) {
  661. rv = selectFrame->OnSetSelectedIndex(oldSelectedIndex, mSelectedIndex);
  662. }
  663. SetSelectionChanged(true, aNotify);
  664. return rv;
  665. }
  666. NS_IMETHODIMP
  667. HTMLSelectElement::SetSelectedIndex(int32_t aIndex)
  668. {
  669. return SetSelectedIndexInternal(aIndex, true);
  670. }
  671. NS_IMETHODIMP
  672. HTMLSelectElement::GetOptionIndex(nsIDOMHTMLOptionElement* aOption,
  673. int32_t aStartIndex, bool aForward,
  674. int32_t* aIndex)
  675. {
  676. nsCOMPtr<nsINode> option = do_QueryInterface(aOption);
  677. return mOptions->GetOptionIndex(option->AsElement(), aStartIndex, aForward, aIndex);
  678. }
  679. bool
  680. HTMLSelectElement::IsOptionSelectedByIndex(int32_t aIndex)
  681. {
  682. HTMLOptionElement* option = Item(static_cast<uint32_t>(aIndex));
  683. return option && option->Selected();
  684. }
  685. void
  686. HTMLSelectElement::OnOptionSelected(nsISelectControlFrame* aSelectFrame,
  687. int32_t aIndex,
  688. bool aSelected,
  689. bool aChangeOptionState,
  690. bool aNotify)
  691. {
  692. // Set the selected index
  693. if (aSelected && (aIndex < mSelectedIndex || mSelectedIndex < 0)) {
  694. mSelectedIndex = aIndex;
  695. SetSelectionChanged(true, aNotify);
  696. } else if (!aSelected && aIndex == mSelectedIndex) {
  697. FindSelectedIndex(aIndex + 1, aNotify);
  698. }
  699. if (aChangeOptionState) {
  700. // Tell the option to get its bad self selected
  701. RefPtr<HTMLOptionElement> option = Item(static_cast<uint32_t>(aIndex));
  702. if (option) {
  703. option->SetSelectedInternal(aSelected, aNotify);
  704. }
  705. }
  706. // Let the frame know too
  707. if (aSelectFrame) {
  708. aSelectFrame->OnOptionSelected(aIndex, aSelected);
  709. }
  710. UpdateSelectedOptions();
  711. UpdateValueMissingValidityState();
  712. UpdateState(aNotify);
  713. }
  714. void
  715. HTMLSelectElement::FindSelectedIndex(int32_t aStartIndex, bool aNotify)
  716. {
  717. mSelectedIndex = -1;
  718. SetSelectionChanged(true, aNotify);
  719. uint32_t len = Length();
  720. for (int32_t i = aStartIndex; i < int32_t(len); i++) {
  721. if (IsOptionSelectedByIndex(i)) {
  722. mSelectedIndex = i;
  723. SetSelectionChanged(true, aNotify);
  724. break;
  725. }
  726. }
  727. }
  728. // XXX Consider splitting this into two functions for ease of reading:
  729. // SelectOptionsByIndex(startIndex, endIndex, clearAll, checkDisabled)
  730. // startIndex, endIndex - the range of options to turn on
  731. // (-1, -1) will clear all indices no matter what.
  732. // clearAll - will clear all other options unless checkDisabled is on
  733. // and all the options attempted to be set are disabled
  734. // (note that if it is not multiple, and an option is selected,
  735. // everything else will be cleared regardless).
  736. // checkDisabled - if this is TRUE, and an option is disabled, it will not be
  737. // changed regardless of whether it is selected or not.
  738. // Generally the UI passes TRUE and JS passes FALSE.
  739. // (setDisabled currently is the opposite)
  740. // DeselectOptionsByIndex(startIndex, endIndex, checkDisabled)
  741. // startIndex, endIndex - the range of options to turn on
  742. // (-1, -1) will clear all indices no matter what.
  743. // checkDisabled - if this is TRUE, and an option is disabled, it will not be
  744. // changed regardless of whether it is selected or not.
  745. // Generally the UI passes TRUE and JS passes FALSE.
  746. // (setDisabled currently is the opposite)
  747. //
  748. // XXXbz the above comment is pretty confusing. Maybe we should actually
  749. // document the args to this function too, in addition to documenting what
  750. // things might end up looking like? In particular, pay attention to the
  751. // setDisabled vs checkDisabled business.
  752. bool
  753. HTMLSelectElement::SetOptionsSelectedByIndex(int32_t aStartIndex,
  754. int32_t aEndIndex,
  755. uint32_t aOptionsMask)
  756. {
  757. #if 0
  758. printf("SetOption(%d-%d, %c, ClearAll=%c)\n", aStartIndex, aEndIndex,
  759. (aOptionsMask & IS_SELECTED ? 'Y' : 'N'),
  760. (aOptionsMask & CLEAR_ALL ? 'Y' : 'N'));
  761. #endif
  762. // Don't bother if the select is disabled
  763. if (!(aOptionsMask & SET_DISABLED) && IsDisabled()) {
  764. return false;
  765. }
  766. // Don't bother if there are no options
  767. uint32_t numItems = Length();
  768. if (numItems == 0) {
  769. return false;
  770. }
  771. // First, find out whether multiple items can be selected
  772. bool isMultiple = Multiple();
  773. // These variables tell us whether any options were selected
  774. // or deselected.
  775. bool optionsSelected = false;
  776. bool optionsDeselected = false;
  777. nsISelectControlFrame* selectFrame = nullptr;
  778. bool didGetFrame = false;
  779. nsWeakFrame weakSelectFrame;
  780. if (aOptionsMask & IS_SELECTED) {
  781. // Setting selectedIndex to an out-of-bounds index means -1. (HTML5)
  782. if (aStartIndex < 0 || AssertedCast<uint32_t>(aStartIndex) >= numItems ||
  783. aEndIndex < 0 || AssertedCast<uint32_t>(aEndIndex) >= numItems) {
  784. aStartIndex = -1;
  785. aEndIndex = -1;
  786. }
  787. // Only select the first value if it's not multiple
  788. if (!isMultiple) {
  789. aEndIndex = aStartIndex;
  790. }
  791. // This variable tells whether or not all of the options we attempted to
  792. // select are disabled. If ClearAll is passed in as true, and we do not
  793. // select anything because the options are disabled, we will not clear the
  794. // other options. (This is to make the UI work the way one might expect.)
  795. bool allDisabled = !(aOptionsMask & SET_DISABLED);
  796. //
  797. // Save a little time when clearing other options
  798. //
  799. int32_t previousSelectedIndex = mSelectedIndex;
  800. //
  801. // Select the requested indices
  802. //
  803. // If index is -1, everything will be deselected (bug 28143)
  804. if (aStartIndex != -1) {
  805. MOZ_ASSERT(aStartIndex >= 0);
  806. MOZ_ASSERT(aEndIndex >= 0);
  807. // Loop through the options and select them (if they are not disabled and
  808. // if they are not already selected).
  809. for (uint32_t optIndex = AssertedCast<uint32_t>(aStartIndex);
  810. optIndex <= AssertedCast<uint32_t>(aEndIndex);
  811. optIndex++) {
  812. RefPtr<HTMLOptionElement> option = Item(optIndex);
  813. // Ignore disabled options.
  814. if (!(aOptionsMask & SET_DISABLED)) {
  815. if (option && IsOptionDisabled(option)) {
  816. continue;
  817. }
  818. allDisabled = false;
  819. }
  820. // If the index is already selected, ignore it.
  821. if (option && !option->Selected()) {
  822. // To notify the frame if anything gets changed. No need
  823. // to flush here, if there's no frame yet we don't need to
  824. // force it to be created just to notify it about a change
  825. // in the select.
  826. selectFrame = GetSelectFrame();
  827. weakSelectFrame = do_QueryFrame(selectFrame);
  828. didGetFrame = true;
  829. OnOptionSelected(selectFrame, optIndex, true, true,
  830. aOptionsMask & NOTIFY);
  831. optionsSelected = true;
  832. }
  833. }
  834. }
  835. // Next remove all other options if single select or all is clear
  836. // If index is -1, everything will be deselected (bug 28143)
  837. if (((!isMultiple && optionsSelected)
  838. || ((aOptionsMask & CLEAR_ALL) && !allDisabled)
  839. || aStartIndex == -1)
  840. && previousSelectedIndex != -1) {
  841. for (uint32_t optIndex = AssertedCast<uint32_t>(previousSelectedIndex);
  842. optIndex < numItems;
  843. optIndex++) {
  844. if (static_cast<int32_t>(optIndex) < aStartIndex ||
  845. static_cast<int32_t>(optIndex) > aEndIndex) {
  846. HTMLOptionElement* option = Item(optIndex);
  847. // If the index is already selected, ignore it.
  848. if (option && option->Selected()) {
  849. if (!didGetFrame || (selectFrame && !weakSelectFrame.IsAlive())) {
  850. // To notify the frame if anything gets changed, don't
  851. // flush, if the frame doesn't exist we don't need to
  852. // create it just to tell it about this change.
  853. selectFrame = GetSelectFrame();
  854. weakSelectFrame = do_QueryFrame(selectFrame);
  855. didGetFrame = true;
  856. }
  857. OnOptionSelected(selectFrame, optIndex, false, true,
  858. aOptionsMask & NOTIFY);
  859. optionsDeselected = true;
  860. // Only need to deselect one option if not multiple
  861. if (!isMultiple) {
  862. break;
  863. }
  864. }
  865. }
  866. }
  867. }
  868. } else {
  869. // If we're deselecting, loop through all selected items and deselect
  870. // any that are in the specified range.
  871. for (int32_t optIndex = aStartIndex; optIndex <= aEndIndex; optIndex++) {
  872. HTMLOptionElement* option = Item(optIndex);
  873. if (!(aOptionsMask & SET_DISABLED) && IsOptionDisabled(option)) {
  874. continue;
  875. }
  876. // If the index is already selected, ignore it.
  877. if (option && option->Selected()) {
  878. if (!didGetFrame || (selectFrame && !weakSelectFrame.IsAlive())) {
  879. // To notify the frame if anything gets changed, don't
  880. // flush, if the frame doesn't exist we don't need to
  881. // create it just to tell it about this change.
  882. selectFrame = GetSelectFrame();
  883. weakSelectFrame = do_QueryFrame(selectFrame);
  884. didGetFrame = true;
  885. }
  886. OnOptionSelected(selectFrame, optIndex, false, true,
  887. aOptionsMask & NOTIFY);
  888. optionsDeselected = true;
  889. }
  890. }
  891. }
  892. // Make sure something is selected unless we were set to -1 (none)
  893. if (optionsDeselected && aStartIndex != -1) {
  894. optionsSelected =
  895. CheckSelectSomething(aOptionsMask & NOTIFY) || optionsSelected;
  896. }
  897. // Let the caller know whether anything was changed
  898. return optionsSelected || optionsDeselected;
  899. }
  900. NS_IMETHODIMP
  901. HTMLSelectElement::IsOptionDisabled(int32_t aIndex, bool* aIsDisabled)
  902. {
  903. *aIsDisabled = false;
  904. RefPtr<HTMLOptionElement> option = Item(aIndex);
  905. NS_ENSURE_TRUE(option, NS_ERROR_FAILURE);
  906. *aIsDisabled = IsOptionDisabled(option);
  907. return NS_OK;
  908. }
  909. bool
  910. HTMLSelectElement::IsOptionDisabled(HTMLOptionElement* aOption)
  911. {
  912. MOZ_ASSERT(aOption);
  913. if (aOption->Disabled()) {
  914. return true;
  915. }
  916. // Check for disabled optgroups
  917. // If there are no artifacts, there are no optgroups
  918. if (mNonOptionChildren) {
  919. for (nsCOMPtr<Element> node = static_cast<nsINode*>(aOption)->GetParentElement();
  920. node;
  921. node = node->GetParentElement()) {
  922. // If we reached the select element, we're done
  923. if (node->IsHTMLElement(nsGkAtoms::select)) {
  924. return false;
  925. }
  926. RefPtr<HTMLOptGroupElement> optGroupElement =
  927. HTMLOptGroupElement::FromContent(node);
  928. if (!optGroupElement) {
  929. // If you put something else between you and the optgroup, you're a
  930. // moron and you deserve not to have optgroup disabling work.
  931. return false;
  932. }
  933. if (optGroupElement->Disabled()) {
  934. return true;
  935. }
  936. }
  937. }
  938. return false;
  939. }
  940. NS_IMETHODIMP
  941. HTMLSelectElement::GetValue(nsAString& aValue)
  942. {
  943. DOMString value;
  944. GetValue(value);
  945. value.ToString(aValue);
  946. return NS_OK;
  947. }
  948. void
  949. HTMLSelectElement::GetValue(DOMString& aValue)
  950. {
  951. int32_t selectedIndex = SelectedIndex();
  952. if (selectedIndex < 0) {
  953. return;
  954. }
  955. RefPtr<HTMLOptionElement> option =
  956. Item(static_cast<uint32_t>(selectedIndex));
  957. if (!option) {
  958. return;
  959. }
  960. DebugOnly<nsresult> rv = option->GetValue(aValue);
  961. MOZ_ASSERT(NS_SUCCEEDED(rv));
  962. }
  963. NS_IMETHODIMP
  964. HTMLSelectElement::SetValue(const nsAString& aValue)
  965. {
  966. uint32_t length = Length();
  967. for (uint32_t i = 0; i < length; i++) {
  968. RefPtr<HTMLOptionElement> option = Item(i);
  969. if (!option) {
  970. continue;
  971. }
  972. nsAutoString optionVal;
  973. option->GetValue(optionVal);
  974. if (optionVal.Equals(aValue)) {
  975. SetSelectedIndexInternal(int32_t(i), true);
  976. return NS_OK;
  977. }
  978. }
  979. // No matching option was found.
  980. SetSelectedIndexInternal(-1, true);
  981. return NS_OK;
  982. }
  983. NS_IMPL_BOOL_ATTR(HTMLSelectElement, Autofocus, autofocus)
  984. NS_IMPL_BOOL_ATTR(HTMLSelectElement, Disabled, disabled)
  985. NS_IMPL_BOOL_ATTR(HTMLSelectElement, Multiple, multiple)
  986. NS_IMPL_STRING_ATTR(HTMLSelectElement, Name, name)
  987. NS_IMPL_BOOL_ATTR(HTMLSelectElement, Required, required)
  988. NS_IMPL_UINT_ATTR(HTMLSelectElement, Size, size)
  989. int32_t
  990. HTMLSelectElement::TabIndexDefault()
  991. {
  992. return 0;
  993. }
  994. bool
  995. HTMLSelectElement::IsHTMLFocusable(bool aWithMouse,
  996. bool* aIsFocusable, int32_t* aTabIndex)
  997. {
  998. if (nsGenericHTMLFormElementWithState::IsHTMLFocusable(aWithMouse, aIsFocusable,
  999. aTabIndex))
  1000. {
  1001. return true;
  1002. }
  1003. *aIsFocusable = !IsDisabled();
  1004. return false;
  1005. }
  1006. NS_IMETHODIMP
  1007. HTMLSelectElement::Item(uint32_t aIndex, nsIDOMNode** aReturn)
  1008. {
  1009. return mOptions->Item(aIndex, aReturn);
  1010. }
  1011. NS_IMETHODIMP
  1012. HTMLSelectElement::NamedItem(const nsAString& aName, nsIDOMNode** aReturn)
  1013. {
  1014. return mOptions->NamedItem(aName, aReturn);
  1015. }
  1016. bool
  1017. HTMLSelectElement::CheckSelectSomething(bool aNotify)
  1018. {
  1019. if (mIsDoneAddingChildren) {
  1020. if (mSelectedIndex < 0 && IsCombobox()) {
  1021. return SelectSomething(aNotify);
  1022. }
  1023. }
  1024. return false;
  1025. }
  1026. bool
  1027. HTMLSelectElement::SelectSomething(bool aNotify)
  1028. {
  1029. // If we're not done building the select, don't play with this yet.
  1030. if (!mIsDoneAddingChildren) {
  1031. return false;
  1032. }
  1033. uint32_t count;
  1034. GetLength(&count);
  1035. for (uint32_t i = 0; i < count; i++) {
  1036. bool disabled;
  1037. nsresult rv = IsOptionDisabled(i, &disabled);
  1038. if (NS_FAILED(rv) || !disabled) {
  1039. rv = SetSelectedIndexInternal(i, aNotify);
  1040. NS_ENSURE_SUCCESS(rv, false);
  1041. UpdateValueMissingValidityState();
  1042. UpdateState(aNotify);
  1043. return true;
  1044. }
  1045. }
  1046. return false;
  1047. }
  1048. nsresult
  1049. HTMLSelectElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
  1050. nsIContent* aBindingParent,
  1051. bool aCompileEventHandlers)
  1052. {
  1053. nsresult rv = nsGenericHTMLFormElementWithState::BindToTree(aDocument, aParent,
  1054. aBindingParent,
  1055. aCompileEventHandlers);
  1056. NS_ENSURE_SUCCESS(rv, rv);
  1057. // If there is a disabled fieldset in the parent chain, the element is now
  1058. // barred from constraint validation.
  1059. // XXXbz is this still needed now that fieldset changes always call
  1060. // FieldSetDisabledChanged?
  1061. UpdateBarredFromConstraintValidation();
  1062. // And now make sure our state is up to date
  1063. UpdateState(false);
  1064. return rv;
  1065. }
  1066. void
  1067. HTMLSelectElement::UnbindFromTree(bool aDeep, bool aNullParent)
  1068. {
  1069. nsGenericHTMLFormElementWithState::UnbindFromTree(aDeep, aNullParent);
  1070. // We might be no longer disabled because our parent chain changed.
  1071. // XXXbz is this still needed now that fieldset changes always call
  1072. // FieldSetDisabledChanged?
  1073. UpdateBarredFromConstraintValidation();
  1074. // And now make sure our state is up to date
  1075. UpdateState(false);
  1076. }
  1077. nsresult
  1078. HTMLSelectElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
  1079. const nsAttrValueOrString* aValue,
  1080. bool aNotify)
  1081. {
  1082. if (aNameSpaceID == kNameSpaceID_None) {
  1083. if (aName == nsGkAtoms::disabled) {
  1084. if (aNotify) {
  1085. mDisabledChanged = true;
  1086. }
  1087. } else if (aName == nsGkAtoms::multiple) {
  1088. if (!aValue && aNotify && mSelectedIndex >= 0) {
  1089. // We're changing from being a multi-select to a single-select.
  1090. // Make sure we only have one option selected before we do that.
  1091. // Note that this needs to come before we really unset the attr,
  1092. // since SetOptionsSelectedByIndex does some bail-out type
  1093. // optimization for cases when the select is not multiple that
  1094. // would lead to only a single option getting deselected.
  1095. SetSelectedIndexInternal(mSelectedIndex, aNotify);
  1096. }
  1097. }
  1098. }
  1099. return nsGenericHTMLFormElementWithState::BeforeSetAttr(aNameSpaceID, aName,
  1100. aValue, aNotify);
  1101. }
  1102. nsresult
  1103. HTMLSelectElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
  1104. const nsAttrValue* aValue,
  1105. const nsAttrValue* aOldValue, bool aNotify)
  1106. {
  1107. if (aNameSpaceID == kNameSpaceID_None) {
  1108. if (aName == nsGkAtoms::disabled) {
  1109. UpdateBarredFromConstraintValidation();
  1110. } else if (aName == nsGkAtoms::required) {
  1111. UpdateValueMissingValidityState();
  1112. } else if (aName == nsGkAtoms::autocomplete) {
  1113. // Clear the cached @autocomplete attribute state
  1114. mAutocompleteAttrState = nsContentUtils::eAutocompleteAttrState_Unknown;
  1115. } else if (aName == nsGkAtoms::multiple) {
  1116. if (!aValue && aNotify) {
  1117. // We might have become a combobox; make sure _something_ gets
  1118. // selected in that case
  1119. CheckSelectSomething(aNotify);
  1120. }
  1121. }
  1122. }
  1123. return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName,
  1124. aValue, aOldValue,
  1125. aNotify);
  1126. }
  1127. void
  1128. HTMLSelectElement::DoneAddingChildren(bool aHaveNotified)
  1129. {
  1130. mIsDoneAddingChildren = true;
  1131. nsISelectControlFrame* selectFrame = GetSelectFrame();
  1132. // If we foolishly tried to restore before we were done adding
  1133. // content, restore the rest of the options proper-like
  1134. if (mRestoreState) {
  1135. RestoreStateTo(mRestoreState);
  1136. mRestoreState = nullptr;
  1137. }
  1138. // Notify the frame
  1139. if (selectFrame) {
  1140. selectFrame->DoneAddingChildren(true);
  1141. }
  1142. if (!mInhibitStateRestoration) {
  1143. nsresult rv = GenerateStateKey();
  1144. if (NS_SUCCEEDED(rv)) {
  1145. RestoreFormControlState();
  1146. }
  1147. }
  1148. // Now that we're done, select something (if it's a single select something
  1149. // must be selected)
  1150. if (!CheckSelectSomething(false)) {
  1151. // If an option has @selected set, it will be selected during parsing but
  1152. // with an empty value. We have to make sure the select element updates it's
  1153. // validity state to take this into account.
  1154. UpdateValueMissingValidityState();
  1155. // And now make sure we update our content state too
  1156. UpdateState(aHaveNotified);
  1157. }
  1158. mDefaultSelectionSet = true;
  1159. }
  1160. bool
  1161. HTMLSelectElement::ParseAttribute(int32_t aNamespaceID,
  1162. nsIAtom* aAttribute,
  1163. const nsAString& aValue,
  1164. nsAttrValue& aResult)
  1165. {
  1166. if (kNameSpaceID_None == aNamespaceID) {
  1167. if (aAttribute == nsGkAtoms::size) {
  1168. return aResult.ParsePositiveIntValue(aValue);
  1169. } else if (aAttribute == nsGkAtoms::autocomplete) {
  1170. aResult.ParseAtomArray(aValue);
  1171. return true;
  1172. }
  1173. }
  1174. return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
  1175. aResult);
  1176. }
  1177. void
  1178. HTMLSelectElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
  1179. nsRuleData* aData)
  1180. {
  1181. nsGenericHTMLFormElementWithState::MapImageAlignAttributeInto(aAttributes, aData);
  1182. nsGenericHTMLFormElementWithState::MapCommonAttributesInto(aAttributes, aData);
  1183. }
  1184. nsChangeHint
  1185. HTMLSelectElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
  1186. int32_t aModType) const
  1187. {
  1188. nsChangeHint retval =
  1189. nsGenericHTMLFormElementWithState::GetAttributeChangeHint(aAttribute, aModType);
  1190. if (aAttribute == nsGkAtoms::multiple ||
  1191. aAttribute == nsGkAtoms::size) {
  1192. retval |= nsChangeHint_ReconstructFrame;
  1193. }
  1194. return retval;
  1195. }
  1196. NS_IMETHODIMP_(bool)
  1197. HTMLSelectElement::IsAttributeMapped(const nsIAtom* aAttribute) const
  1198. {
  1199. static const MappedAttributeEntry* const map[] = {
  1200. sCommonAttributeMap,
  1201. sImageAlignAttributeMap
  1202. };
  1203. return FindAttributeDependence(aAttribute, map);
  1204. }
  1205. nsMapRuleToAttributesFunc
  1206. HTMLSelectElement::GetAttributeMappingFunction() const
  1207. {
  1208. return &MapAttributesIntoRule;
  1209. }
  1210. bool
  1211. HTMLSelectElement::IsDisabledForEvents(WidgetEvent* aEvent)
  1212. {
  1213. nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
  1214. nsIFrame* formFrame = nullptr;
  1215. if (formControlFrame) {
  1216. formFrame = do_QueryFrame(formControlFrame);
  1217. }
  1218. return IsElementDisabledForEvents(aEvent, formFrame);
  1219. }
  1220. nsresult
  1221. HTMLSelectElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
  1222. {
  1223. aVisitor.mCanHandle = false;
  1224. if (IsDisabledForEvents(aVisitor.mEvent)) {
  1225. return NS_OK;
  1226. }
  1227. return nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);
  1228. }
  1229. nsresult
  1230. HTMLSelectElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
  1231. {
  1232. if (aVisitor.mEvent->mMessage == eFocus) {
  1233. // If the invalid UI is shown, we should show it while focused and
  1234. // update the invalid/valid UI.
  1235. mCanShowInvalidUI = !IsValid() && ShouldShowValidityUI();
  1236. // If neither invalid UI nor valid UI is shown, we shouldn't show the valid
  1237. // UI while focused.
  1238. mCanShowValidUI = ShouldShowValidityUI();
  1239. // We don't have to update NS_EVENT_STATE_MOZ_UI_INVALID nor
  1240. // NS_EVENT_STATE_MOZ_UI_VALID given that the states should not change.
  1241. } else if (aVisitor.mEvent->mMessage == eBlur) {
  1242. mCanShowInvalidUI = true;
  1243. mCanShowValidUI = true;
  1244. UpdateState(true);
  1245. }
  1246. return nsGenericHTMLFormElementWithState::PostHandleEvent(aVisitor);
  1247. }
  1248. EventStates
  1249. HTMLSelectElement::IntrinsicState() const
  1250. {
  1251. EventStates state = nsGenericHTMLFormElementWithState::IntrinsicState();
  1252. if (IsCandidateForConstraintValidation()) {
  1253. if (IsValid()) {
  1254. state |= NS_EVENT_STATE_VALID;
  1255. } else {
  1256. state |= NS_EVENT_STATE_INVALID;
  1257. if ((!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) &&
  1258. (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) ||
  1259. (mCanShowInvalidUI && ShouldShowValidityUI()))) {
  1260. state |= NS_EVENT_STATE_MOZ_UI_INVALID;
  1261. }
  1262. }
  1263. // :-moz-ui-valid applies if all the following are true:
  1264. // 1. The element is not focused, or had either :-moz-ui-valid or
  1265. // :-moz-ui-invalid applying before it was focused ;
  1266. // 2. The element is either valid or isn't allowed to have
  1267. // :-moz-ui-invalid applying ;
  1268. // 3. The element has no form owner or its form owner doesn't have the
  1269. // novalidate attribute set ;
  1270. // 4. The element has already been modified or the user tried to submit the
  1271. // form owner while invalid.
  1272. if ((!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) &&
  1273. (mCanShowValidUI && ShouldShowValidityUI() &&
  1274. (IsValid() || (state.HasState(NS_EVENT_STATE_MOZ_UI_INVALID) &&
  1275. !mCanShowInvalidUI)))) {
  1276. state |= NS_EVENT_STATE_MOZ_UI_VALID;
  1277. }
  1278. }
  1279. if (HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
  1280. state |= NS_EVENT_STATE_REQUIRED;
  1281. } else {
  1282. state |= NS_EVENT_STATE_OPTIONAL;
  1283. }
  1284. return state;
  1285. }
  1286. // nsIFormControl
  1287. NS_IMETHODIMP
  1288. HTMLSelectElement::SaveState()
  1289. {
  1290. RefPtr<SelectState> state = new SelectState();
  1291. uint32_t len = Length();
  1292. for (uint32_t optIndex = 0; optIndex < len; optIndex++) {
  1293. HTMLOptionElement* option = Item(optIndex);
  1294. if (option && option->Selected()) {
  1295. nsAutoString value;
  1296. option->GetValue(value);
  1297. state->PutOption(optIndex, value);
  1298. }
  1299. }
  1300. nsPresState* presState = GetPrimaryPresState();
  1301. if (presState) {
  1302. presState->SetStateProperty(state);
  1303. if (mDisabledChanged) {
  1304. // We do not want to save the real disabled state but the disabled
  1305. // attribute.
  1306. presState->SetDisabled(HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
  1307. }
  1308. }
  1309. return NS_OK;
  1310. }
  1311. bool
  1312. HTMLSelectElement::RestoreState(nsPresState* aState)
  1313. {
  1314. // Get the presentation state object to retrieve our stuff out of.
  1315. nsCOMPtr<SelectState> state(
  1316. do_QueryInterface(aState->GetStateProperty()));
  1317. if (state) {
  1318. RestoreStateTo(state);
  1319. // Don't flush, if the frame doesn't exist yet it doesn't care if
  1320. // we're reset or not.
  1321. DispatchContentReset();
  1322. }
  1323. if (aState->IsDisabledSet()) {
  1324. SetDisabled(aState->GetDisabled());
  1325. }
  1326. return false;
  1327. }
  1328. void
  1329. HTMLSelectElement::RestoreStateTo(SelectState* aNewSelected)
  1330. {
  1331. if (!mIsDoneAddingChildren) {
  1332. mRestoreState = aNewSelected;
  1333. return;
  1334. }
  1335. uint32_t len = Length();
  1336. uint32_t mask = IS_SELECTED | CLEAR_ALL | SET_DISABLED | NOTIFY;
  1337. // First clear all
  1338. SetOptionsSelectedByIndex(-1, -1, mask);
  1339. // Next set the proper ones
  1340. for (uint32_t i = 0; i < len; i++) {
  1341. HTMLOptionElement* option = Item(i);
  1342. if (option) {
  1343. nsAutoString value;
  1344. nsresult rv = option->GetValue(value);
  1345. if (NS_SUCCEEDED(rv) && aNewSelected->ContainsOption(i, value)) {
  1346. SetOptionsSelectedByIndex(i, i, IS_SELECTED | SET_DISABLED | NOTIFY);
  1347. }
  1348. }
  1349. }
  1350. }
  1351. NS_IMETHODIMP
  1352. HTMLSelectElement::Reset()
  1353. {
  1354. uint32_t numSelected = 0;
  1355. //
  1356. // Cycle through the options array and reset the options
  1357. //
  1358. uint32_t numOptions = Length();
  1359. for (uint32_t i = 0; i < numOptions; i++) {
  1360. RefPtr<HTMLOptionElement> option = Item(i);
  1361. if (option) {
  1362. //
  1363. // Reset the option to its default value
  1364. //
  1365. uint32_t mask = SET_DISABLED | NOTIFY;
  1366. if (option->DefaultSelected()) {
  1367. mask |= IS_SELECTED;
  1368. numSelected++;
  1369. }
  1370. SetOptionsSelectedByIndex(i, i, mask);
  1371. }
  1372. }
  1373. //
  1374. // If nothing was selected and it's not multiple, select something
  1375. //
  1376. if (numSelected == 0 && IsCombobox()) {
  1377. SelectSomething(true);
  1378. }
  1379. SetSelectionChanged(false, true);
  1380. //
  1381. // Let the frame know we were reset
  1382. //
  1383. // Don't flush, if there's no frame yet it won't care about us being
  1384. // reset even if we forced it to be created now.
  1385. //
  1386. DispatchContentReset();
  1387. return NS_OK;
  1388. }
  1389. static NS_DEFINE_CID(kFormProcessorCID, NS_FORMPROCESSOR_CID);
  1390. NS_IMETHODIMP
  1391. HTMLSelectElement::SubmitNamesValues(HTMLFormSubmission* aFormSubmission)
  1392. {
  1393. // Disabled elements don't submit
  1394. if (IsDisabled()) {
  1395. return NS_OK;
  1396. }
  1397. //
  1398. // Get the name (if no name, no submit)
  1399. //
  1400. nsAutoString name;
  1401. GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
  1402. if (name.IsEmpty()) {
  1403. return NS_OK;
  1404. }
  1405. //
  1406. // Submit
  1407. //
  1408. uint32_t len = Length();
  1409. nsAutoString mozType;
  1410. nsCOMPtr<nsIFormProcessor> keyGenProcessor;
  1411. if (GetAttr(kNameSpaceID_None, nsGkAtoms::moztype, mozType) &&
  1412. mozType.EqualsLiteral("-mozilla-keygen")) {
  1413. keyGenProcessor = do_GetService(kFormProcessorCID);
  1414. }
  1415. for (uint32_t optIndex = 0; optIndex < len; optIndex++) {
  1416. HTMLOptionElement* option = Item(optIndex);
  1417. // Don't send disabled options
  1418. if (!option || IsOptionDisabled(option)) {
  1419. continue;
  1420. }
  1421. if (!option->Selected()) {
  1422. continue;
  1423. }
  1424. nsString value;
  1425. MOZ_ALWAYS_SUCCEEDS(option->GetValue(value));
  1426. if (keyGenProcessor) {
  1427. nsString tmp(value);
  1428. if (NS_SUCCEEDED(keyGenProcessor->ProcessValue(this, name, tmp))) {
  1429. value = tmp;
  1430. }
  1431. }
  1432. aFormSubmission->AddNameValuePair(name, value);
  1433. }
  1434. return NS_OK;
  1435. }
  1436. void
  1437. HTMLSelectElement::DispatchContentReset()
  1438. {
  1439. nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
  1440. if (formControlFrame) {
  1441. // Only dispatch content reset notification if this is a list control
  1442. // frame or combo box control frame.
  1443. if (IsCombobox()) {
  1444. nsIComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
  1445. if (comboFrame) {
  1446. comboFrame->OnContentReset();
  1447. }
  1448. } else {
  1449. nsIListControlFrame* listFrame = do_QueryFrame(formControlFrame);
  1450. if (listFrame) {
  1451. listFrame->OnContentReset();
  1452. }
  1453. }
  1454. }
  1455. }
  1456. static void
  1457. AddOptions(nsIContent* aRoot, HTMLOptionsCollection* aArray)
  1458. {
  1459. for (nsIContent* child = aRoot->GetFirstChild();
  1460. child;
  1461. child = child->GetNextSibling()) {
  1462. HTMLOptionElement* opt = HTMLOptionElement::FromContent(child);
  1463. if (opt) {
  1464. aArray->AppendOption(opt);
  1465. } else if (child->IsHTMLElement(nsGkAtoms::optgroup)) {
  1466. for (nsIContent* grandchild = child->GetFirstChild();
  1467. grandchild;
  1468. grandchild = grandchild->GetNextSibling()) {
  1469. opt = HTMLOptionElement::FromContent(grandchild);
  1470. if (opt) {
  1471. aArray->AppendOption(opt);
  1472. }
  1473. }
  1474. }
  1475. }
  1476. }
  1477. void
  1478. HTMLSelectElement::RebuildOptionsArray(bool aNotify)
  1479. {
  1480. mOptions->Clear();
  1481. AddOptions(this, mOptions);
  1482. FindSelectedIndex(0, aNotify);
  1483. }
  1484. bool
  1485. HTMLSelectElement::IsValueMissing()
  1486. {
  1487. if (!Required()) {
  1488. return false;
  1489. }
  1490. uint32_t length = Length();
  1491. for (uint32_t i = 0; i < length; ++i) {
  1492. RefPtr<HTMLOptionElement> option = Item(i);
  1493. if (!option->Selected()) {
  1494. continue;
  1495. }
  1496. if (IsOptionDisabled(option)) {
  1497. continue;
  1498. }
  1499. nsAutoString value;
  1500. MOZ_ALWAYS_SUCCEEDS(option->GetValue(value));
  1501. if (!value.IsEmpty()) {
  1502. return false;
  1503. }
  1504. }
  1505. return true;
  1506. }
  1507. void
  1508. HTMLSelectElement::UpdateValueMissingValidityState()
  1509. {
  1510. SetValidityState(VALIDITY_STATE_VALUE_MISSING, IsValueMissing());
  1511. }
  1512. nsresult
  1513. HTMLSelectElement::GetValidationMessage(nsAString& aValidationMessage,
  1514. ValidityStateType aType)
  1515. {
  1516. switch (aType) {
  1517. case VALIDITY_STATE_VALUE_MISSING: {
  1518. nsXPIDLString message;
  1519. nsresult rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
  1520. "FormValidationSelectMissing",
  1521. message);
  1522. aValidationMessage = message;
  1523. return rv;
  1524. }
  1525. default: {
  1526. return nsIConstraintValidation::GetValidationMessage(aValidationMessage, aType);
  1527. }
  1528. }
  1529. }
  1530. #ifdef DEBUG
  1531. void
  1532. HTMLSelectElement::VerifyOptionsArray()
  1533. {
  1534. int32_t index = 0;
  1535. for (nsIContent* child = nsINode::GetFirstChild();
  1536. child;
  1537. child = child->GetNextSibling()) {
  1538. HTMLOptionElement* opt = HTMLOptionElement::FromContent(child);
  1539. if (opt) {
  1540. NS_ASSERTION(opt == mOptions->ItemAsOption(index++),
  1541. "Options collection broken");
  1542. } else if (child->IsHTMLElement(nsGkAtoms::optgroup)) {
  1543. for (nsIContent* grandchild = child->GetFirstChild();
  1544. grandchild;
  1545. grandchild = grandchild->GetNextSibling()) {
  1546. opt = HTMLOptionElement::FromContent(grandchild);
  1547. if (opt) {
  1548. NS_ASSERTION(opt == mOptions->ItemAsOption(index++),
  1549. "Options collection broken");
  1550. }
  1551. }
  1552. }
  1553. }
  1554. }
  1555. #endif
  1556. void
  1557. HTMLSelectElement::UpdateBarredFromConstraintValidation()
  1558. {
  1559. SetBarredFromConstraintValidation(IsDisabled());
  1560. }
  1561. void
  1562. HTMLSelectElement::FieldSetDisabledChanged(bool aNotify)
  1563. {
  1564. UpdateBarredFromConstraintValidation();
  1565. nsGenericHTMLFormElementWithState::FieldSetDisabledChanged(aNotify);
  1566. }
  1567. void
  1568. HTMLSelectElement::SetSelectionChanged(bool aValue, bool aNotify)
  1569. {
  1570. if (!mDefaultSelectionSet) {
  1571. return;
  1572. }
  1573. UpdateSelectedOptions();
  1574. bool previousSelectionChangedValue = mSelectionHasChanged;
  1575. mSelectionHasChanged = aValue;
  1576. if (mSelectionHasChanged != previousSelectionChangedValue) {
  1577. UpdateState(aNotify);
  1578. }
  1579. }
  1580. void
  1581. HTMLSelectElement::UpdateSelectedOptions()
  1582. {
  1583. if (mSelectedOptions) {
  1584. mSelectedOptions->SetDirty();
  1585. }
  1586. }
  1587. bool
  1588. HTMLSelectElement::OpenInParentProcess()
  1589. {
  1590. nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
  1591. nsIComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
  1592. if (comboFrame) {
  1593. return comboFrame->IsOpenInParentProcess();
  1594. }
  1595. return false;
  1596. }
  1597. void
  1598. HTMLSelectElement::SetOpenInParentProcess(bool aVal)
  1599. {
  1600. nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
  1601. nsIComboboxControlFrame* comboFrame = do_QueryFrame(formControlFrame);
  1602. if (comboFrame) {
  1603. comboFrame->SetOpenInParentProcess(aVal);
  1604. }
  1605. }
  1606. JSObject*
  1607. HTMLSelectElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
  1608. {
  1609. return HTMLSelectElementBinding::Wrap(aCx, this, aGivenProto);
  1610. }
  1611. } // namespace dom
  1612. } // namespace mozilla