template <> inline bool isMatchingElement(const HTMLCollection* htmlCollection, Element* element) { CollectionType type = htmlCollection->type(); if (!element->isHTMLElement() && !(type == DocAll || type == NodeChildren || type == WindowNamedItems)) return false; switch (type) { case DocImages: return element->hasLocalName(imgTag); case DocScripts: return element->hasLocalName(scriptTag); case DocForms: return element->hasLocalName(formTag); case TableTBodies: return element->hasLocalName(tbodyTag); case TRCells: return element->hasLocalName(tdTag) || element->hasLocalName(thTag); case TSectionRows: return element->hasLocalName(trTag); case SelectOptions: return element->hasLocalName(optionTag); case SelectedOptions: return element->hasLocalName(optionTag) && toHTMLOptionElement(element)->selected(); case DataListOptions: if (element->hasLocalName(optionTag)) { HTMLOptionElement* option = toHTMLOptionElement(element); if (!option->isDisabledFormControl() && !option->value().isEmpty()) return true; } return false; case MapAreas: return element->hasLocalName(areaTag); case DocApplets: return element->hasLocalName(appletTag) || (element->hasLocalName(objectTag) && static_cast<HTMLObjectElement*>(element)->containsJavaApplet()); case DocEmbeds: return element->hasLocalName(embedTag); case DocLinks: return (element->hasLocalName(aTag) || element->hasLocalName(areaTag)) && element->fastHasAttribute(hrefAttr); case DocAnchors: return element->hasLocalName(aTag) && element->fastHasAttribute(nameAttr); case DocAll: case NodeChildren: return true; case DocumentNamedItems: return static_cast<const DocumentNameCollection*>(htmlCollection)->nodeMatches(element); case WindowNamedItems: return static_cast<const WindowNameCollection*>(htmlCollection)->nodeMatches(element); case FormControls: case TableRows: case ChildNodeListType: case ClassNodeListType: case NameNodeListType: case TagNodeListType: case HTMLTagNodeListType: case RadioNodeListType: case LabelsNodeListType: ASSERT_NOT_REACHED(); } return false; }
void SelectPopupClient::setValueAndClosePopup(int, const String& stringValue) { ASSERT(m_size == stringValue.length()); if (m_size > 0) { bool selecteds[m_size]; for (unsigned i = 0; i < m_size; i++) selecteds[i] = stringValue[i] - '0'; const WTF::Vector<HTMLElement*>& items = m_element->listItems(); if (items.size() != static_cast<unsigned int>(m_size)) return; HTMLOptionElement* option; for (unsigned i = 0; i < m_size; i++) { if (items[i]->hasTagName(HTMLNames::optionTag)) { option = static_cast<HTMLOptionElement*>(items[i]); option->setSelectedState(selecteds[i]); } } } // Force repaint because we do not send mouse events to the select element // and the element doesn't automatically repaint itself. m_element->dispatchFormControlChangeEvent(); m_element->renderer()->repaint(); closePopup(); }
static void valueAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) { INC_STATS("DOM.HTMLOptionElement.value._set"); HTMLOptionElement* imp = V8HTMLOptionElement::toNative(info.Holder()); V8Parameter<WithNullCheck> v = value; imp->setValue(v); return; }
void HTMLSelectElement::updateListBoxSelection(bool deselectOtherOptions) { ASSERT(renderer() && renderer()->isListBox()); unsigned start; unsigned end; ASSERT(m_activeSelectionAnchorIndex >= 0); start = min(m_activeSelectionAnchorIndex, m_activeSelectionEndIndex); end = max(m_activeSelectionAnchorIndex, m_activeSelectionEndIndex); const Vector<HTMLElement*>& items = listItems(); for (unsigned i = 0; i < items.size(); i++) { if (items[i]->hasLocalName(optionTag)) { HTMLOptionElement* option = static_cast<HTMLOptionElement*>(items[i]); if (!option->disabled()) { if (i >= start && i <= end) option->setSelectedState(m_activeSelectionState); else if (deselectOtherOptions || i >= m_cachedStateForActiveSelection.size()) option->setSelectedState(false); else option->setSelectedState(m_cachedStateForActiveSelection[i]); } } } scrollToSelection(); }
void HTMLSelectElement::recalcListItems(bool updateSelectedStates) const { m_listItems.clear(); HTMLOptionElement* foundSelected = 0; for (Node* current = firstChild(); current; current = current->traverseNextSibling(this)) { if (current->hasTagName(optgroupTag) && current->firstChild()) { // FIXME: It doesn't make sense to add an optgroup to the list items, // when it has children, but not to add it if it happens to have, // children (say some comment nodes or text nodes), yet that's what // this code does! m_listItems.append(static_cast<HTMLElement*>(current)); current = current->firstChild(); // FIXME: It doesn't make sense to handle an <optgroup> inside another <optgroup> // if it's not the first child, but not handle it if it happens to be the first // child, yet that's what this code does! } if (current->hasTagName(optionTag)) { m_listItems.append(static_cast<HTMLElement*>(current)); if (updateSelectedStates) { if (!foundSelected && (usesMenuList() || (!m_multiple && static_cast<HTMLOptionElement*>(current)->selected()))) { foundSelected = static_cast<HTMLOptionElement*>(current); foundSelected->setSelectedState(true); } else if (foundSelected && !m_multiple && static_cast<HTMLOptionElement*>(current)->selected()) { foundSelected->setSelectedState(false); foundSelected = static_cast<HTMLOptionElement*>(current); } } } if (current->hasTagName(hrTag)) m_listItems.append(static_cast<HTMLElement*>(current)); } m_recalcListItems = false; }
void HTMLSelectElement::setSelectedIndex(int optionIndex, bool deselect, bool fireOnChange) { const Vector<HTMLElement*>& items = listItems(); int listIndex = optionToListIndex(optionIndex); HTMLOptionElement* element = 0; if (!multiple()) deselect = true; if (listIndex >= 0) { if (m_activeSelectionAnchorIndex < 0 || deselect) setActiveSelectionAnchorIndex(listIndex); if (m_activeSelectionEndIndex < 0 || deselect) setActiveSelectionEndIndex(listIndex); element = static_cast<HTMLOptionElement*>(items[listIndex]); element->setSelectedState(true); } if (deselect) deselectItems(element); scrollToSelection(); // This only gets called with fireOnChange for menu lists. if (fireOnChange && usesMenuList()) menuListOnChange(); Frame* frame = document()->frame(); if (frame) frame->page()->chrome()->client()->formStateDidChange(this); }
static void disabledAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) { INC_STATS("DOM.HTMLOptionElement.disabled._set"); HTMLOptionElement* imp = V8HTMLOptionElement::toNative(info.Holder()); bool v = value->BooleanValue(); imp->setDisabled(v); return; }
void SelectPopupClient::setValueAndClosePopup(int, const String& stringValue) { ASSERT(m_element); static const char* cancelValue = "-1"; if (stringValue == cancelValue) { closePopup(); return; } if (m_size > 0) { bool selecteds[m_size]; for (unsigned i = 0; i < m_size; i++) selecteds[i] = stringValue[i] - '0'; const Vector<HTMLElement*>& items = m_element->listItems(); if (items.size() != static_cast<unsigned int>(m_size)) return; HTMLOptionElement* option; for (unsigned i = 0; i < m_size; i++) { if (items[i]->hasTagName(HTMLNames::optionTag)) { option = static_cast<HTMLOptionElement*>(items[i]); option->setSelectedState(selecteds[i]); } } } // Force repaint because we do not send mouse events to the select element // and the element doesn't automatically repaint itself. if (m_element->renderer()) m_element->renderer()->repaint(); m_notifyChangeTimer.startOneShot(0); }
static void selectedAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) { HTMLOptionElement* imp = V8HTMLOptionElement::toNative(info.Holder()); bool v = value->BooleanValue(); imp->setSelected(v); return; }
void HTMLSelectOptionAccessible::SetSelected(bool aSelect) { HTMLOptionElement* option = HTMLOptionElement::FromContent(mContent); if (option) option->SetSelected(aSelect); }
void HTMLOptionsCollection::GetSupportedNames(nsTArray<nsString>& aNames) { AutoTArray<nsIAtom*, 8> atoms; for (uint32_t i = 0; i < mElements.Length(); ++i) { HTMLOptionElement* content = mElements.ElementAt(i); if (content) { // Note: HasName means the names is exposed on the document, // which is false for options, so we don't check it here. const nsAttrValue* val = content->GetParsedAttr(nsGkAtoms::name); if (val && val->Type() == nsAttrValue::eAtom) { nsIAtom* name = val->GetAtomValue(); if (!atoms.Contains(name)) { atoms.AppendElement(name); } } if (content->HasID()) { nsIAtom* id = content->GetID(); if (!atoms.Contains(id)) { atoms.AppendElement(id); } } } } uint32_t atomsLen = atoms.Length(); nsString* names = aNames.AppendElements(atomsLen); for (uint32_t i = 0; i < atomsLen; ++i) { atoms[i]->ToString(names[i]); } }
void HTMLOptionsCollection::GetSupportedNames(unsigned aFlags, nsTArray<nsString>& aNames) { if (!(aFlags & JSITER_HIDDEN)) { return; } nsAutoTArray<nsIAtom*, 8> atoms; for (uint32_t i = 0; i < mElements.Length(); ++i) { HTMLOptionElement* content = mElements.ElementAt(i); if (content) { // Note: HasName means the names is exposed on the document, // which is false for options, so we don't check it here. const nsAttrValue* val = content->GetParsedAttr(nsGkAtoms::name); if (val && val->Type() == nsAttrValue::eAtom) { nsIAtom* name = val->GetAtomValue(); if (!atoms.Contains(name)) { atoms.AppendElement(name); } } if (content->HasID()) { nsIAtom* id = content->GetID(); if (!atoms.Contains(id)) { atoms.AppendElement(id); } } } } aNames.SetCapacity(atoms.Length()); for (uint32_t i = 0; i < atoms.Length(); ++i) { aNames.AppendElement(nsDependentAtomString(atoms[i])); } }
static void defaultSelectedAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) { HTMLOptionElement* imp = V8HTMLOptionElement::toNative(info.Holder()); bool v = value->BooleanValue(); imp->setBooleanAttribute(WebCore::HTMLNames::selectedAttr, v); return; }
static void labelAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) { HTMLOptionElement* imp = V8HTMLOptionElement::toNative(info.Holder()); V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(V8StringResource<>, v, value); imp->setLabel(v); return; }
JSValue jsHTMLOptionElementValue(ExecState* exec, JSValue slotBase, const Identifier&) { JSHTMLOptionElement* castedThis = static_cast<JSHTMLOptionElement*>(asObject(slotBase)); UNUSED_PARAM(exec); HTMLOptionElement* imp = static_cast<HTMLOptionElement*>(castedThis->impl()); JSValue result = jsString(exec, imp->value()); return result; }
void setJSHTMLOptionElementText(ExecState* exec, JSObject* thisObject, JSValue value) { JSHTMLOptionElement* castedThisObj = static_cast<JSHTMLOptionElement*>(thisObject); HTMLOptionElement* imp = static_cast<HTMLOptionElement*>(castedThisObj->impl()); ExceptionCode ec = 0; imp->setText(valueToStringWithNullCheck(exec, value), ec); setDOMException(exec, ec); }
JSValue jsHTMLOptionElementDisabled(ExecState* exec, JSValue slotBase, const Identifier&) { JSHTMLOptionElement* castedThis = static_cast<JSHTMLOptionElement*>(asObject(slotBase)); UNUSED_PARAM(exec); HTMLOptionElement* imp = static_cast<HTMLOptionElement*>(castedThis->impl()); JSValue result = jsBoolean(imp->disabled()); return result; }
uint64_t HTMLSelectOptionAccessible::NativeState() const { // As a HTMLSelectOptionAccessible we can have the following states: // SELECTABLE, SELECTED, FOCUSED, FOCUSABLE, OFFSCREEN // Upcall to Accessible, but skip HyperTextAccessible impl // because we don't want EDITABLE or SELECTABLE_TEXT uint64_t state = Accessible::NativeState(); Accessible* select = GetSelect(); if (!select) return state; uint64_t selectState = select->State(); if (selectState & states::INVISIBLE) return state; // Are we selected? HTMLOptionElement* option = HTMLOptionElement::FromNode(mContent); bool selected = option && option->Selected(); if (selected) state |= states::SELECTED; if (selectState & states::OFFSCREEN) { state |= states::OFFSCREEN; } else if (selectState & states::COLLAPSED) { // <select> is COLLAPSED: add OFFSCREEN, if not the currently // visible option if (!selected) { state |= states::OFFSCREEN; // Ensure the invisible state is removed. Otherwise, group info will skip // this option. Furthermore, this gets cached and this doesn't get // invalidated even once the select is expanded. state &= ~states::INVISIBLE; } else { // Clear offscreen and invisible for currently showing option state &= ~(states::OFFSCREEN | states::INVISIBLE); state |= selectState & states::OPAQUE1; } } else { // XXX list frames are weird, don't rely on Accessible's general // visibility implementation unless they get reimplemented in layout state &= ~states::OFFSCREEN; // <select> is not collapsed: compare bounds to calculate OFFSCREEN Accessible* listAcc = Parent(); if (listAcc) { nsIntRect optionRect = Bounds(); nsIntRect listRect = listAcc->Bounds(); if (optionRect.Y() < listRect.Y() || optionRect.YMost() > listRect.YMost()) { state |= states::OFFSCREEN; } } } return state; }
static inline bool isAcceptableElement(CollectionType type, Element* element) { if (!element->isHTMLElement() && !(type == DocAll || type == NodeChildren)) return false; switch (type) { case DocImages: return element->hasLocalName(imgTag); case DocScripts: return element->hasLocalName(scriptTag); case DocForms: return element->hasLocalName(formTag); case TableTBodies: return element->hasLocalName(tbodyTag); case TRCells: return element->hasLocalName(tdTag) || element->hasLocalName(thTag); case TSectionRows: return element->hasLocalName(trTag); case SelectOptions: return element->hasLocalName(optionTag); case SelectedOptions: return element->hasLocalName(optionTag) && toHTMLOptionElement(element)->selected(); case DataListOptions: if (element->hasLocalName(optionTag)) { HTMLOptionElement* option = static_cast<HTMLOptionElement*>(element); if (!option->disabled() && !option->value().isEmpty()) return true; } return false; case MapAreas: return element->hasLocalName(areaTag); case DocApplets: return element->hasLocalName(appletTag) || (element->hasLocalName(objectTag) && static_cast<HTMLObjectElement*>(element)->containsJavaApplet()); case DocEmbeds: return element->hasLocalName(embedTag); case DocObjects: return element->hasLocalName(objectTag); case DocLinks: return (element->hasLocalName(aTag) || element->hasLocalName(areaTag)) && element->fastHasAttribute(hrefAttr); case DocAnchors: return element->hasLocalName(aTag) && element->fastHasAttribute(nameAttr); case DocAll: case NodeChildren: return true; #if ENABLE(MICRODATA) case ItemProperties: return element->fastHasAttribute(itempropAttr); #endif case FormControls: case DocumentNamedItems: case TableRows: case WindowNamedItems: case NodeListCollectionType: ASSERT_NOT_REACHED(); } return false; }
NS_IMETHODIMP HTMLSelectOptionAccessible::SetSelected(bool aSelect) { if (IsDefunct()) return NS_ERROR_FAILURE; HTMLOptionElement* option = HTMLOptionElement::FromContent(mContent); return option ? option->SetSelected(aSelect) : NS_ERROR_FAILURE; }
static void textAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) { INC_STATS("DOM.HTMLOptionElement.text._set"); HTMLOptionElement* imp = V8HTMLOptionElement::toNative(info.Holder()); V8Parameter<WithNullCheck> v = value; ExceptionCode ec = 0; imp->setText(v, ec); if (UNLIKELY(ec)) V8Proxy::setDOMException(ec); return; }
static void textAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) { HTMLOptionElement* imp = V8HTMLOptionElement::toNative(info.Holder()); V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(V8StringResource<>, v, value); ExceptionCode ec = 0; imp->setText(v, ec); if (UNLIKELY(ec)) setDOMException(ec, info.GetIsolate()); return; }
uint64_t HTMLSelectOptionAccessible::NativeState() { // As a HTMLSelectOptionAccessible we can have the following states: // SELECTABLE, SELECTED, FOCUSED, FOCUSABLE, OFFSCREEN // Upcall to Accessible, but skip HyperTextAccessible impl // because we don't want EDITABLE or SELECTABLE_TEXT uint64_t state = Accessible::NativeState(); Accessible* select = GetSelect(); if (!select) return state; uint64_t selectState = select->State(); if (selectState & states::INVISIBLE) return state; // Are we selected? HTMLOptionElement* option = HTMLOptionElement::FromContent(mContent); bool selected = option && option->Selected(); if (selected) state |= states::SELECTED; if (selectState & states::OFFSCREEN) { state |= states::OFFSCREEN; } else if (selectState & states::COLLAPSED) { // <select> is COLLAPSED: add OFFSCREEN, if not the currently // visible option if (!selected) { state |= states::OFFSCREEN; state ^= states::INVISIBLE; } else { // Clear offscreen and invisible for currently showing option state &= ~(states::OFFSCREEN | states::INVISIBLE); state |= selectState & states::OPAQUE1; } } else { // XXX list frames are weird, don't rely on Accessible's general // visibility implementation unless they get reimplemented in layout state &= ~states::OFFSCREEN; // <select> is not collapsed: compare bounds to calculate OFFSCREEN Accessible* listAcc = Parent(); if (listAcc) { nsIntRect optionRect = Bounds(); nsIntRect listRect = listAcc->Bounds(); if (optionRect.y < listRect.y || optionRect.y + optionRect.height > listRect.y + listRect.height) { state |= states::OFFSCREEN; } } } return state; }
void HTMLSelectElement::deselectItems(HTMLOptionElement* excludeElement) { const Vector<HTMLElement*>& items = listItems(); unsigned i; for (i = 0; i < items.size(); i++) { if (items[i]->hasLocalName(optionTag) && (items[i] != excludeElement)) { HTMLOptionElement* element = static_cast<HTMLOptionElement*>(items[i]); element->setSelectedState(false); } } }
v8::Handle<v8::Value> removeElement(HTMLSelectElement* imp, const v8::Arguments& args) { if (V8HTMLOptionElement::HasInstance(args[0])) { HTMLOptionElement* element = V8HTMLOptionElement::toNative(v8::Handle<v8::Object>::Cast(args[0])); imp->remove(element->index()); return v8::Undefined(); } imp->remove(toInt32(args[0])); return v8::Undefined(); }
bool RenderThemeAndroid::paintTextArea(RenderObject* obj, const RenderObject::PaintInfo& info, const IntRect& rect) { if (!obj->isListBox()) return true; paintCombo(obj, info, rect); RenderStyle* style = obj->style(); if (style) style->setColor(Color::transparent); Node* node = obj->node(); if (!node || !node->hasTagName(HTMLNames::selectTag)) return true; HTMLSelectElement* select = static_cast<HTMLSelectElement*>(node); // The first item may be visible. Make sure it does not draw. // If it has a style, it overrides the RenderListBox's style, so we // need to make sure both are set to transparent. node = select->item(0); if (node) { RenderObject* renderer = node->renderer(); if (renderer) { RenderStyle* renderStyle = renderer->style(); if (renderStyle) renderStyle->setColor(Color::transparent); } } // Find the first selected option, and draw its text. // FIXME: In a later change, if there is more than one item selected, // draw a string that says "X items" like iPhone Safari does int index = select->selectedIndex(); node = select->item(index); if (!node || !node->hasTagName(HTMLNames::optionTag)) return true; HTMLOptionElement* option = static_cast<HTMLOptionElement*>(node); String label = option->textIndentedToRespectGroupLabel(); SkRect r(rect); SkPaint paint; paint.setAntiAlias(true); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); // Values for text size and positioning determined by trial and error paint.setTextSize(r.height() - SkIntToScalar(6)); SkCanvas* canvas = getCanvasFromInfo(info); int saveCount = canvas->save(); r.fRight -= SkIntToScalar(RenderSkinCombo::extraWidth()); canvas->clipRect(r); canvas->drawText(label.characters(), label.length() << 1, r.fLeft + SkIntToScalar(5), r.fBottom - SkIntToScalar(5), paint); canvas->restoreToCount(saveCount); return true; }
void PopupMenuImpl::addOption(HTMLOptionElement& element, bool enableExtraStyling, SharedBuffer* data) { PagePopupClient::addString("{\n", data); PagePopupClient::addString("type: \"option\",\n", data); addProperty("label", element.text(), data); addProperty("title", element.title(), data); addProperty("value", element.listIndex(), data); addProperty("ariaLabel", element.fastGetAttribute(HTMLNames::aria_labelAttr), data); addProperty("disabled", element.isDisabledFormControl(), data); addElementStyle(element, enableExtraStyling, data); PagePopupClient::addString("},\n", data); }
HTMLKeygenElement::HTMLKeygenElement(Document* doc, HTMLFormElement* f) : HTMLSelectElement(keygenTag, doc, f) { Vector<String> keys = supportedKeySizes(); Vector<String>::const_iterator end = keys.end(); for (Vector<String>::const_iterator it = keys.begin(); it != end; ++it) { HTMLOptionElement* o = new HTMLOptionElement(doc, form()); addChild(o); o->addChild(new Text(doc, *it)); } }
void LayoutMenuList::setTextFromOption(int optionIndex) { HTMLSelectElement* select = selectElement(); const HeapVector<Member<HTMLElement>>& listItems = select->listItems(); const int size = listItems.size(); String text = emptyString(); m_optionStyle.clear(); if (selectElement()->multiple()) { unsigned selectedCount = 0; int firstSelectedIndex = -1; for (int i = 0; i < size; ++i) { Element* element = listItems[i]; if (!isHTMLOptionElement(*element)) continue; if (toHTMLOptionElement(element)->selected()) { if (++selectedCount == 1) firstSelectedIndex = i; } } if (selectedCount == 1) { ASSERT(0 <= firstSelectedIndex); ASSERT(firstSelectedIndex < size); HTMLOptionElement* selectedOptionElement = toHTMLOptionElement(listItems[firstSelectedIndex]); ASSERT(selectedOptionElement->selected()); text = selectedOptionElement->textIndentedToRespectGroupLabel(); m_optionStyle = selectedOptionElement->mutableComputedStyle(); } else { Locale& locale = select->locale(); String localizedNumberString = locale.convertToLocalizedNumber(String::number(selectedCount)); text = locale.queryString(WebLocalizedString::SelectMenuListText, localizedNumberString); ASSERT(!m_optionStyle); } } else { const int i = select->optionToListIndex(optionIndex); if (i >= 0 && i < size) { Element* element = listItems[i]; if (isHTMLOptionElement(*element)) { text = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel(); m_optionStyle = element->mutableComputedStyle(); } } } setText(text.stripWhiteSpace()); didUpdateActiveOption(optionIndex); }
HRESULT STDMETHODCALLTYPE DOMHTMLOptionElement::label( /* [retval][out] */ BSTR* result) { if (!result) return E_POINTER; *result = 0; ASSERT(m_element); ASSERT(m_element->hasTagName(optionTag)); HTMLOptionElement* optionElement = static_cast<HTMLOptionElement*>(m_element); *result = BString(optionElement->label()).release(); return S_OK; }