Bug 1494333 - index crons just like artifacts r=Callek
[gecko.git] / dom / html / HTMLSelectElement.h
blobf3c656816eb9b936b36abf60e97c72ab0984742f
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef mozilla_dom_HTMLSelectElement_h
7 #define mozilla_dom_HTMLSelectElement_h
9 #include "mozilla/Attributes.h"
10 #include "nsGenericHTMLElement.h"
11 #include "nsIConstraintValidation.h"
13 #include "mozilla/dom/BindingDeclarations.h"
14 #include "mozilla/dom/UnionTypes.h"
15 #include "mozilla/dom/HTMLOptionsCollection.h"
16 #include "mozilla/ErrorResult.h"
17 #include "nsCheapSets.h"
18 #include "nsCOMPtr.h"
19 #include "nsError.h"
20 #include "mozilla/dom/HTMLFormElement.h"
21 #include "nsContentUtils.h"
23 class nsContentList;
24 class nsIDOMHTMLOptionElement;
25 class nsIHTMLCollection;
26 class nsISelectControlFrame;
28 namespace mozilla {
30 class EventChainPostVisitor;
31 class EventChainPreVisitor;
32 class SelectContentData;
33 class PresState;
35 namespace dom {
37 class HTMLFormSubmission;
38 class HTMLSelectElement;
40 class MOZ_STACK_CLASS SafeOptionListMutation
42 public:
43 /**
44 * @param aSelect The select element which option list is being mutated.
45 * Can be null.
46 * @param aParent The content object which is being mutated.
47 * @param aKid If not null, a new child element is being inserted to
48 * aParent. Otherwise a child element will be removed.
49 * @param aIndex The index of the content object in the parent.
51 SafeOptionListMutation(nsIContent* aSelect, nsIContent* aParent,
52 nsIContent* aKid, uint32_t aIndex, bool aNotify);
53 ~SafeOptionListMutation();
54 void MutationFailed() { mNeedsRebuild = true; }
55 private:
56 static void* operator new(size_t) CPP_THROW_NEW { return 0; }
57 static void operator delete(void*, size_t) {}
58 /** The select element which option list is being mutated. */
59 RefPtr<HTMLSelectElement> mSelect;
60 /** true if the current mutation is the first one in the stack. */
61 bool mTopLevelMutation;
62 /** true if it is known that the option list must be recreated. */
63 bool mNeedsRebuild;
64 /** Whether we should be notifying when we make various method calls on
65 mSelect */
66 const bool mNotify;
67 /** The selected index at mutation start. */
68 int32_t mInitialSelectedIndex;
69 /** Option list must be recreated if more than one mutation is detected. */
70 nsMutationGuard mGuard;
74 /**
75 * Implementation of &lt;select&gt;
77 class HTMLSelectElement final : public nsGenericHTMLFormElementWithState,
78 public nsIConstraintValidation
80 public:
81 /**
82 * IS_SELECTED whether to set the option(s) to true or false
84 * CLEAR_ALL whether to clear all other options (for example, if you
85 * are normal-clicking on the current option)
87 * SET_DISABLED whether it is permissible to set disabled options
88 * (for JavaScript)
90 * NOTIFY whether to notify frames and such
92 * NO_RESELECT no need to select something after an option is deselected
93 * (for reset)
95 enum OptionType {
96 IS_SELECTED = 1 << 0,
97 CLEAR_ALL = 1 << 1,
98 SET_DISABLED = 1 << 2,
99 NOTIFY = 1 << 3,
100 NO_RESELECT = 1 << 4
103 using nsIConstraintValidation::GetValidationMessage;
105 explicit HTMLSelectElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
106 FromParser aFromParser = NOT_FROM_PARSER);
108 NS_IMPL_FROMNODE_HTML_WITH_TAG(HTMLSelectElement, select)
110 // nsISupports
111 NS_DECL_ISUPPORTS_INHERITED
113 virtual int32_t TabIndexDefault() override;
115 // Element
116 virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override
118 return true;
121 // WebIdl HTMLSelectElement
122 bool Autofocus() const
124 return GetBoolAttr(nsGkAtoms::autofocus);
126 void SetAutofocus(bool aVal, ErrorResult& aRv)
128 SetHTMLBoolAttr(nsGkAtoms::autofocus, aVal, aRv);
130 void GetAutocomplete(DOMString& aValue);
131 void SetAutocomplete(const nsAString& aValue, ErrorResult& aRv)
133 SetHTMLAttr(nsGkAtoms::autocomplete, aValue, aRv);
136 void GetAutocompleteInfo(AutocompleteInfo& aInfo);
138 bool Disabled() const
140 return GetBoolAttr(nsGkAtoms::disabled);
142 void SetDisabled(bool aVal, ErrorResult& aRv)
144 SetHTMLBoolAttr(nsGkAtoms::disabled, aVal, aRv);
146 HTMLFormElement* GetForm() const
148 return nsGenericHTMLFormElementWithState::GetForm();
150 bool Multiple() const
152 return GetBoolAttr(nsGkAtoms::multiple);
154 void SetMultiple(bool aVal, ErrorResult& aRv)
156 SetHTMLBoolAttr(nsGkAtoms::multiple, aVal, aRv);
159 void GetName(DOMString& aValue)
161 GetHTMLAttr(nsGkAtoms::name, aValue);
163 void SetName(const nsAString& aName, ErrorResult& aRv)
165 SetHTMLAttr(nsGkAtoms::name, aName, aRv);
167 bool Required() const
169 return State().HasState(NS_EVENT_STATE_REQUIRED);
171 void SetRequired(bool aVal, ErrorResult& aRv)
173 SetHTMLBoolAttr(nsGkAtoms::required, aVal, aRv);
175 uint32_t Size() const
177 return GetUnsignedIntAttr(nsGkAtoms::size, 0);
179 void SetSize(uint32_t aSize, ErrorResult& aRv)
181 SetUnsignedIntAttr(nsGkAtoms::size, aSize, 0, aRv);
184 void GetType(nsAString& aValue);
186 HTMLOptionsCollection* Options() const
188 return mOptions;
190 uint32_t Length() const
192 return mOptions->Length();
194 void SetLength(uint32_t aLength, ErrorResult& aRv);
195 Element* IndexedGetter(uint32_t aIdx, bool& aFound) const
197 return mOptions->IndexedGetter(aIdx, aFound);
199 HTMLOptionElement* Item(uint32_t aIdx) const
201 return mOptions->ItemAsOption(aIdx);
203 HTMLOptionElement* NamedItem(const nsAString& aName) const
205 return mOptions->GetNamedItem(aName);
207 void Add(const HTMLOptionElementOrHTMLOptGroupElement& aElement,
208 const Nullable<HTMLElementOrLong>& aBefore,
209 ErrorResult& aRv);
210 void Remove(int32_t aIndex);
211 void IndexedSetter(uint32_t aIndex, HTMLOptionElement* aOption,
212 ErrorResult& aRv)
214 mOptions->IndexedSetter(aIndex, aOption, aRv);
217 static bool MatchSelectedOptions(Element* aElement, int32_t, nsAtom*,
218 void*);
220 nsIHTMLCollection* SelectedOptions();
222 int32_t SelectedIndex() const
224 return mSelectedIndex;
226 void SetSelectedIndex(int32_t aIdx, ErrorResult& aRv)
228 aRv = SetSelectedIndexInternal(aIdx, true);
230 void GetValue(DOMString& aValue);
231 void SetValue(const nsAString& aValue);
233 // Override SetCustomValidity so we update our state properly when it's called
234 // via bindings.
235 void SetCustomValidity(const nsAString& aError);
237 using nsINode::Remove;
239 // nsINode
240 virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
242 // nsIContent
243 void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
244 virtual nsresult PostHandleEvent(
245 EventChainPostVisitor& aVisitor) override;
247 virtual bool IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable, int32_t* aTabIndex) override;
248 virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
249 bool aNotify) override;
250 virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
252 // Overriden nsIFormControl methods
253 NS_IMETHOD Reset() override;
254 NS_IMETHOD SubmitNamesValues(HTMLFormSubmission* aFormSubmission) override;
255 NS_IMETHOD SaveState() override;
256 virtual bool RestoreState(PresState* aState) override;
257 virtual bool IsDisabledForEvents(EventMessage aMessage) override;
259 virtual void FieldSetDisabledChanged(bool aNotify) override;
261 EventStates IntrinsicState() const override;
264 * To be called when stuff is added under a child of the select--but *before*
265 * they are actually added.
267 * @param aOptions the content that was added (usually just an option, but
268 * could be an optgroup node with many child options)
269 * @param aParent the parent the options were added to (could be an optgroup)
270 * @param aContentIndex the index where the options are being added within the
271 * parent (if the parent is an optgroup, the index within the optgroup)
273 NS_IMETHOD WillAddOptions(nsIContent* aOptions,
274 nsIContent* aParent,
275 int32_t aContentIndex,
276 bool aNotify);
279 * To be called when stuff is removed under a child of the select--but
280 * *before* they are actually removed.
282 * @param aParent the parent the option(s) are being removed from
283 * @param aContentIndex the index of the option(s) within the parent (if the
284 * parent is an optgroup, the index within the optgroup)
286 NS_IMETHOD WillRemoveOptions(nsIContent* aParent,
287 int32_t aContentIndex,
288 bool aNotify);
291 * Checks whether an option is disabled (even if it's part of an optgroup)
293 * @param aIndex the index of the option to check
294 * @return whether the option is disabled
296 NS_IMETHOD IsOptionDisabled(int32_t aIndex,
297 bool* aIsDisabled);
298 bool IsOptionDisabled(HTMLOptionElement* aOption) const;
301 * Sets multiple options (or just sets startIndex if select is single)
302 * and handles notifications and cleanup and everything under the sun.
303 * When this method exits, the select will be in a consistent state. i.e.
304 * if you set the last option to false, it will select an option anyway.
306 * @param aStartIndex the first index to set
307 * @param aEndIndex the last index to set (set same as first index for one
308 * option)
309 * @param aOptionsMask determines whether to set, clear all or disable
310 * options and whether frames are to be notified of such.
311 * @return whether any options were actually changed
313 bool SetOptionsSelectedByIndex(int32_t aStartIndex,
314 int32_t aEndIndex,
315 uint32_t aOptionsMask);
318 * Called when an attribute is about to be changed
320 virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
321 nsIContent* aBindingParent) override;
322 virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
323 virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsAtom* aName,
324 const nsAttrValueOrString* aValue,
325 bool aNotify) override;
326 virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
327 const nsAttrValue* aValue,
328 const nsAttrValue* aOldValue,
329 nsIPrincipal* aSubjectPrincipal,
330 bool aNotify) override;
332 virtual void DoneAddingChildren(bool aHaveNotified) override;
333 virtual bool IsDoneAddingChildren() override {
334 return mIsDoneAddingChildren;
337 virtual bool ParseAttribute(int32_t aNamespaceID,
338 nsAtom* aAttribute,
339 const nsAString& aValue,
340 nsIPrincipal* aMaybeScriptedPrincipal,
341 nsAttrValue& aResult) override;
342 virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
343 virtual nsChangeHint GetAttributeChangeHint(const nsAtom* aAttribute,
344 int32_t aModType) const override;
345 NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
347 virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
349 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLSelectElement,
350 nsGenericHTMLFormElementWithState)
352 HTMLOptionsCollection* GetOptions()
354 return mOptions;
357 // nsIConstraintValidation
358 nsresult GetValidationMessage(nsAString& aValidationMessage,
359 ValidityStateType aType) override;
361 void UpdateValueMissingValidityState();
363 * Insert aElement before the node given by aBefore
365 void Add(nsGenericHTMLElement& aElement, nsGenericHTMLElement* aBefore,
366 ErrorResult& aError);
367 void Add(nsGenericHTMLElement& aElement, int32_t aIndex, ErrorResult& aError)
369 // If item index is out of range, insert to last.
370 // (since beforeElement becomes null, it is inserted to last)
371 nsIContent* beforeContent = mOptions->GetElementAt(aIndex);
372 return Add(aElement, nsGenericHTMLElement::FromNodeOrNull(beforeContent),
373 aError);
377 * Is this a combobox?
379 bool IsCombobox() const
381 return !Multiple() && Size() <= 1;
384 bool OpenInParentProcess();
385 void SetOpenInParentProcess(bool aVal);
387 void GetPreviewValue(nsAString& aValue)
389 aValue = mPreviewValue;
391 void SetPreviewValue(const nsAString& aValue);
393 protected:
394 virtual ~HTMLSelectElement();
396 friend class SafeOptionListMutation;
398 // Helper Methods
400 * Check whether the option specified by the index is selected
401 * @param aIndex the index
402 * @return whether the option at the index is selected
404 bool IsOptionSelectedByIndex(int32_t aIndex);
406 * Starting with (and including) aStartIndex, find the first selected index
407 * and set mSelectedIndex to it.
408 * @param aStartIndex the index to start with
410 void FindSelectedIndex(int32_t aStartIndex, bool aNotify);
412 * Select some option if possible (generally the first non-disabled option).
413 * @return true if something was selected, false otherwise
415 bool SelectSomething(bool aNotify);
417 * Call SelectSomething(), but only if nothing is selected
418 * @see SelectSomething()
419 * @return true if something was selected, false otherwise
421 bool CheckSelectSomething(bool aNotify);
423 * Called to trigger notifications of frames and fixing selected index
425 * @param aSelectFrame the frame for this content (could be null)
426 * @param aIndex the index that was selected or deselected
427 * @param aSelected whether the index was selected or deselected
428 * @param aChangeOptionState if false, don't do anything to the
429 * HTMLOptionElement at aIndex. If true, change
430 * its selected state to aSelected.
431 * @param aNotify whether to notify the style system and such
433 void OnOptionSelected(nsISelectControlFrame* aSelectFrame,
434 int32_t aIndex,
435 bool aSelected,
436 bool aChangeOptionState,
437 bool aNotify);
439 * Restore state to a particular state string (representing the options)
440 * @param aNewSelected the state string to restore to
442 void RestoreStateTo(const SelectContentData& aNewSelected);
444 // Adding options
446 * Insert option(s) into the options[] array and perform notifications
447 * @param aOptions the option or optgroup being added
448 * @param aListIndex the index to start adding options into the list at
449 * @param aDepth the depth of aOptions (1=direct child of select ...)
451 void InsertOptionsIntoList(nsIContent* aOptions,
452 int32_t aListIndex,
453 int32_t aDepth,
454 bool aNotify);
456 * Remove option(s) from the options[] array
457 * @param aOptions the option or optgroup being added
458 * @param aListIndex the index to start removing options from the list at
459 * @param aDepth the depth of aOptions (1=direct child of select ...)
461 nsresult RemoveOptionsFromList(nsIContent* aOptions,
462 int32_t aListIndex,
463 int32_t aDepth,
464 bool aNotify);
466 // nsIConstraintValidation
467 void UpdateBarredFromConstraintValidation();
468 bool IsValueMissing() const;
471 * Get the index of the first option at, under or following the content in
472 * the select, or length of options[] if none are found
473 * @param aOptions the content
474 * @return the index of the first option
476 int32_t GetOptionIndexAt(nsIContent* aOptions);
478 * Get the next option following the content in question (not at or under)
479 * (this could include siblings of the current content or siblings of the
480 * parent or children of siblings of the parent).
481 * @param aOptions the content
482 * @return the index of the next option after the content
484 int32_t GetOptionIndexAfter(nsIContent* aOptions);
486 * Get the first option index at or under the content in question.
487 * @param aOptions the content
488 * @return the index of the first option at or under the content
490 int32_t GetFirstOptionIndex(nsIContent* aOptions);
492 * Get the first option index under the content in question, within the
493 * range specified.
494 * @param aOptions the content
495 * @param aStartIndex the first child to look at
496 * @param aEndIndex the child *after* the last child to look at
497 * @return the index of the first option at or under the content
499 int32_t GetFirstChildOptionIndex(nsIContent* aOptions,
500 int32_t aStartIndex,
501 int32_t aEndIndex);
504 * Get the frame as an nsISelectControlFrame (MAY RETURN nullptr)
505 * @return the select frame, or null
507 nsISelectControlFrame* GetSelectFrame();
510 * Helper method for dispatching ContentReset notifications to list
511 * and combo box frames.
513 void DispatchContentReset();
516 * Rebuilds the options array from scratch as a fallback in error cases.
518 void RebuildOptionsArray(bool aNotify);
520 #ifdef DEBUG
521 void VerifyOptionsArray();
522 #endif
524 nsresult SetSelectedIndexInternal(int32_t aIndex, bool aNotify);
526 void SetSelectionChanged(bool aValue, bool aNotify);
529 * Marks the selectedOptions list as dirty, so that it'll populate itself
530 * again.
532 void UpdateSelectedOptions();
535 * Return whether an element should have a validity UI.
536 * (with :-moz-ui-invalid and :-moz-ui-valid pseudo-classes).
538 * @return Whether the element should have a validity UI.
540 bool ShouldShowValidityUI() const {
542 * Always show the validity UI if the form has already tried to be submitted
543 * but was invalid.
545 * Otherwise, show the validity UI if the selection has been changed.
547 if (mForm && mForm->HasEverTriedInvalidSubmit()) {
548 return true;
551 return mSelectionHasChanged;
554 /** The options[] array */
555 RefPtr<HTMLOptionsCollection> mOptions;
556 nsContentUtils::AutocompleteAttrState mAutocompleteAttrState;
557 nsContentUtils::AutocompleteAttrState mAutocompleteInfoState;
558 /** false if the parser is in the middle of adding children. */
559 bool mIsDoneAddingChildren;
560 /** true if our disabled state has changed from the default **/
561 bool mDisabledChanged;
562 /** true if child nodes are being added or removed.
563 * Used by SafeOptionListMutation.
565 bool mMutating;
567 * True if DoneAddingChildren will get called but shouldn't restore state.
569 bool mInhibitStateRestoration;
571 * True if the selection has changed since the element's creation.
573 bool mSelectionHasChanged;
575 * True if the default selected option has been set.
577 bool mDefaultSelectionSet;
579 * True if :-moz-ui-invalid can be shown.
581 bool mCanShowInvalidUI;
583 * True if :-moz-ui-valid can be shown.
585 bool mCanShowValidUI;
587 /** The number of non-options as children of the select */
588 uint32_t mNonOptionChildren;
589 /** The number of optgroups anywhere under the select */
590 uint32_t mOptGroupCount;
592 * The current selected index for selectedIndex (will be the first selected
593 * index if multiple are selected)
595 int32_t mSelectedIndex;
597 * The temporary restore state in case we try to restore before parser is
598 * done adding options
600 UniquePtr<SelectContentData> mRestoreState;
603 * The live list of selected options.
605 RefPtr<nsContentList> mSelectedOptions;
608 * The current displayed preview text.
610 nsString mPreviewValue;
612 private:
613 static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
614 MappedDeclarations&);
617 } // namespace dom
618 } // namespace mozilla
620 #endif // mozilla_dom_HTMLSelectElement_h