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(); }
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; }
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; }
bool HTMLSelectElement::hasPlaceholderLabelOption() const { // The select element has no placeholder label option if it has an attribute "multiple" specified or a display size of non-1. // // The condition "size() > 1" is actually not compliant with the HTML5 spec as of Dec 3, 2010. "size() != 1" is correct. // Using "size() > 1" here because size() may be 0 in WebKit. // See the discussion at https://bugs.webkit.org/show_bug.cgi?id=43887 // // "0 size()" happens when an attribute "size" is absent or an invalid size attribute is specified. // In this case, the display size should be assumed as the default. // The default display size is 1 for non-multiple select elements, and 4 for multiple select elements. // // Finally, if size() == 0 and non-multiple, the display size can be assumed as 1. if (multiple() || size() > 1) return false; int listIndex = optionToListIndex(0); ASSERT(listIndex >= 0); if (listIndex < 0) return false; HTMLOptionElement* option = static_cast<HTMLOptionElement*>(listItems()[listIndex]); return !option->disabled() && !listIndex && option->value().isEmpty(); }
Element* HTMLCollection::itemAfter(Element* previous) const { bool deep = true; switch (m_type) { case DocAll: case DocAnchors: case DocApplets: case DocEmbeds: case DocForms: case DocImages: case DocLinks: case DocObjects: case DocScripts: case DocumentNamedItems: case MapAreas: case OtherCollection: case SelectOptions: case DataListOptions: case WindowNamedItems: break; case NodeChildren: case TRCells: case TSectionRows: case TableTBodies: deep = false; break; } Node* current; if (!previous) current = m_base->firstChild(); else current = nextNodeOrSibling(m_base.get(), previous, deep); for (; current; current = nextNodeOrSibling(m_base.get(), current, deep)) { if (!current->isElementNode()) continue; Element* e = static_cast<Element*>(current); switch (m_type) { case DocImages: if (e->hasLocalName(imgTag)) return e; break; case DocScripts: if (e->hasLocalName(scriptTag)) return e; break; case DocForms: if (e->hasLocalName(formTag)) return e; break; case TableTBodies: if (e->hasLocalName(tbodyTag)) return e; break; case TRCells: if (e->hasLocalName(tdTag) || e->hasLocalName(thTag)) return e; break; case TSectionRows: if (e->hasLocalName(trTag)) return e; break; case SelectOptions: if (e->hasLocalName(optionTag)) return e; break; case DataListOptions: if (e->hasLocalName(optionTag)) { HTMLOptionElement* option = static_cast<HTMLOptionElement*>(e); if (!option->disabled() && !option->value().isEmpty()) return e; } break; case MapAreas: if (e->hasLocalName(areaTag)) return e; break; case DocApplets: // all <applet> elements and <object> elements that contain Java Applets // weolar __asm int 3; // if (e->hasLocalName(appletTag)) // return e; // if (e->hasLocalName(objectTag) && static_cast<HTMLObjectElement*>(e)->containsJavaApplet()) // return e; break; case DocEmbeds: if (e->hasLocalName(embedTag)) return e; break; case DocObjects: if (e->hasLocalName(objectTag)) return e; break; case DocLinks: // all <a> and <area> elements with a value for href if ((e->hasLocalName(aTag) || e->hasLocalName(areaTag)) && e->fastHasAttribute(hrefAttr)) return e; break; case DocAnchors: // all <a> elements with a value for name if (e->hasLocalName(aTag) && e->fastHasAttribute(nameAttr)) return e; break; case DocAll: case NodeChildren: return e; case DocumentNamedItems: case OtherCollection: case WindowNamedItems: ASSERT_NOT_REACHED(); break; } } return 0; }
static v8::Handle<v8::Value> disabledAttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) { INC_STATS("DOM.HTMLOptionElement.disabled._get"); HTMLOptionElement* imp = V8HTMLOptionElement::toNative(info.Holder()); return v8Boolean(imp->disabled()); }
void HTMLSelectElement::listBoxDefaultEventHandler(Event* evt) { if (evt->type() == eventNames().mousedownEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton) { focus(); MouseEvent* mEvt = static_cast<MouseEvent*>(evt); int listIndex = static_cast<RenderListBox*>(renderer())->listIndexAtOffset(mEvt->offsetX(), mEvt->offsetY()); if (listIndex >= 0) { // Save the selection so it can be compared to the new selection when we call onChange during mouseup, or after autoscroll finishes. saveLastSelection(); m_activeSelectionState = true; bool multiSelectKeyPressed = false; #if PLATFORM(MAC) multiSelectKeyPressed = mEvt->metaKey(); #else multiSelectKeyPressed = mEvt->ctrlKey(); #endif bool shiftSelect = multiple() && mEvt->shiftKey(); bool multiSelect = multiple() && multiSelectKeyPressed && !mEvt->shiftKey(); HTMLElement* clickedElement = listItems()[listIndex]; HTMLOptionElement* option = 0; if (clickedElement->hasLocalName(optionTag)) { option = static_cast<HTMLOptionElement*>(clickedElement); // Keep track of whether an active selection (like during drag selection), should select or deselect if (option->selected() && multiSelectKeyPressed) m_activeSelectionState = false; if (!m_activeSelectionState) option->setSelectedState(false); } // If we're not in any special multiple selection mode, then deselect all other items, excluding the clicked option. // If no option was clicked, then this will deselect all items in the list. if (!shiftSelect && !multiSelect) deselectItems(option); // If the anchor hasn't been set, and we're doing a single selection or a shift selection, then initialize the anchor to the first selected index. if (m_activeSelectionAnchorIndex < 0 && !multiSelect) setActiveSelectionAnchorIndex(selectedIndex()); // Set the selection state of the clicked option if (option && !option->disabled()) option->setSelectedState(true); // If there was no selectedIndex() for the previous initialization, or // If we're doing a single selection, or a multiple selection (using cmd or ctrl), then initialize the anchor index to the listIndex that just got clicked. if (listIndex >= 0 && (m_activeSelectionAnchorIndex < 0 || !shiftSelect)) setActiveSelectionAnchorIndex(listIndex); setActiveSelectionEndIndex(listIndex); updateListBoxSelection(!multiSelect); if (Frame* frame = document()->frame()) frame->eventHandler()->setMouseDownMayStartAutoscroll(); evt->setDefaultHandled(); } } else if (evt->type() == eventNames().mouseupEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton && document()->frame()->eventHandler()->autoscrollRenderer() != renderer()) // This makes sure we fire onChange for a single click. For drag selection, onChange will fire when the autoscroll timer stops. listBoxOnChange(); else if (evt->type() == eventNames().keydownEvent) { if (!evt->isKeyboardEvent()) return; String keyIdentifier = static_cast<KeyboardEvent*>(evt)->keyIdentifier(); int endIndex = 0; if (m_activeSelectionEndIndex < 0) { // Initialize the end index if (keyIdentifier == "Down") endIndex = nextSelectableListIndex(lastSelectedListIndex()); else if (keyIdentifier == "Up") endIndex = previousSelectableListIndex(optionToListIndex(selectedIndex())); } else { // Set the end index based on the current end index if (keyIdentifier == "Down") endIndex = nextSelectableListIndex(m_activeSelectionEndIndex); else if (keyIdentifier == "Up") endIndex = previousSelectableListIndex(m_activeSelectionEndIndex); } if (keyIdentifier == "Down" || keyIdentifier == "Up") { // Save the selection so it can be compared to the new selection when we call onChange immediately after making the new selection. saveLastSelection(); ASSERT(endIndex >= 0 && (unsigned)endIndex < listItems().size()); setActiveSelectionEndIndex(endIndex); // If the anchor is unitialized, or if we're going to deselect all other options, then set the anchor index equal to the end index. bool deselectOthers = !multiple() || !static_cast<KeyboardEvent*>(evt)->shiftKey(); if (m_activeSelectionAnchorIndex < 0 || deselectOthers) { m_activeSelectionState = true; if (deselectOthers) deselectItems(); setActiveSelectionAnchorIndex(m_activeSelectionEndIndex); } static_cast<RenderListBox*>(renderer())->scrollToRevealElementAtListIndex(endIndex); updateListBoxSelection(deselectOthers); listBoxOnChange(); evt->setDefaultHandled(); } } else if (evt->type() == eventNames().keypressEvent) { if (!evt->isKeyboardEvent()) return; int keyCode = static_cast<KeyboardEvent*>(evt)->keyCode(); if (keyCode == '\r') { if (form()) form()->submitClick(evt); evt->setDefaultHandled(); return; } } }