| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). | 2 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
| 3 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 3 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 4 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 4 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 5 * (C) 2001 Dirk Mueller (mueller@kde.org) | 5 * (C) 2001 Dirk Mueller (mueller@kde.org) |
| 6 * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights
reserved. | 6 * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights
reserved. |
| 7 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) | 7 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) |
| 8 * Copyright (C) 2010 Google Inc. All rights reserved. | 8 * Copyright (C) 2010 Google Inc. All rights reserved. |
| 9 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmo
bile.com/) | 9 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmo
bile.com/) |
| 10 * | 10 * |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 #include "bindings/v8/ExceptionState.h" | 32 #include "bindings/v8/ExceptionState.h" |
| 33 #include "bindings/v8/ExceptionStatePlaceholder.h" | 33 #include "bindings/v8/ExceptionStatePlaceholder.h" |
| 34 #include "core/HTMLNames.h" | 34 #include "core/HTMLNames.h" |
| 35 #include "core/accessibility/AXObjectCache.h" | 35 #include "core/accessibility/AXObjectCache.h" |
| 36 #include "core/dom/Attribute.h" | 36 #include "core/dom/Attribute.h" |
| 37 #include "core/dom/ElementTraversal.h" | 37 #include "core/dom/ElementTraversal.h" |
| 38 #include "core/dom/NodeTraversal.h" | 38 #include "core/dom/NodeTraversal.h" |
| 39 #include "core/events/GestureEvent.h" | 39 #include "core/events/GestureEvent.h" |
| 40 #include "core/events/KeyboardEvent.h" | 40 #include "core/events/KeyboardEvent.h" |
| 41 #include "core/events/MouseEvent.h" | 41 #include "core/events/MouseEvent.h" |
| 42 #include "core/frame/FrameView.h" |
| 42 #include "core/frame/LocalFrame.h" | 43 #include "core/frame/LocalFrame.h" |
| 43 #include "core/html/FormDataList.h" | 44 #include "core/html/FormDataList.h" |
| 44 #include "core/html/HTMLFormElement.h" | 45 #include "core/html/HTMLFormElement.h" |
| 46 #include "core/html/HTMLOptGroupElement.h" |
| 45 #include "core/html/HTMLOptionElement.h" | 47 #include "core/html/HTMLOptionElement.h" |
| 46 #include "core/html/forms/FormController.h" | 48 #include "core/html/forms/FormController.h" |
| 49 #include "core/page/AutoscrollController.h" |
| 47 #include "core/page/EventHandler.h" | 50 #include "core/page/EventHandler.h" |
| 51 #include "core/page/Page.h" |
| 48 #include "core/page/SpatialNavigation.h" | 52 #include "core/page/SpatialNavigation.h" |
| 53 #include "core/rendering/HitTestRequest.h" |
| 54 #include "core/rendering/HitTestResult.h" |
| 49 #include "core/rendering/RenderListBox.h" | 55 #include "core/rendering/RenderListBox.h" |
| 50 #include "core/rendering/RenderMenuList.h" | 56 #include "core/rendering/RenderMenuList.h" |
| 51 #include "core/rendering/RenderTheme.h" | 57 #include "core/rendering/RenderTheme.h" |
| 58 #include "core/rendering/RenderView.h" |
| 52 #include "platform/PlatformMouseEvent.h" | 59 #include "platform/PlatformMouseEvent.h" |
| 53 #include "platform/text/PlatformLocale.h" | 60 #include "platform/text/PlatformLocale.h" |
| 54 | 61 |
| 55 using namespace WTF::Unicode; | 62 using namespace WTF::Unicode; |
| 56 | 63 |
| 57 namespace WebCore { | 64 namespace WebCore { |
| 58 | 65 |
| 59 using namespace HTMLNames; | 66 using namespace HTMLNames; |
| 60 | 67 |
| 61 // Upper limit agreed upon with representatives of Opera and Mozilla. | 68 // Upper limit agreed upon with representatives of Opera and Mozilla. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 73 , m_activeSelectionState(false) | 80 , m_activeSelectionState(false) |
| 74 , m_shouldRecalcListItems(false) | 81 , m_shouldRecalcListItems(false) |
| 75 , m_suggestedIndex(-1) | 82 , m_suggestedIndex(-1) |
| 76 { | 83 { |
| 77 ScriptWrappable::init(this); | 84 ScriptWrappable::init(this); |
| 78 setHasCustomStyleCallbacks(); | 85 setHasCustomStyleCallbacks(); |
| 79 } | 86 } |
| 80 | 87 |
| 81 PassRefPtrWillBeRawPtr<HTMLSelectElement> HTMLSelectElement::create(Document& do
cument) | 88 PassRefPtrWillBeRawPtr<HTMLSelectElement> HTMLSelectElement::create(Document& do
cument) |
| 82 { | 89 { |
| 83 return adoptRefWillBeNoop(new HTMLSelectElement(document, 0)); | 90 RefPtrWillBeRawPtr<HTMLSelectElement> select = adoptRefWillBeNoop(new HTMLSe
lectElement(document, 0)); |
| 91 select->ensureUserAgentShadowRoot(); |
| 92 return select.release(); |
| 84 } | 93 } |
| 85 | 94 |
| 86 PassRefPtrWillBeRawPtr<HTMLSelectElement> HTMLSelectElement::create(Document& do
cument, HTMLFormElement* form) | 95 PassRefPtrWillBeRawPtr<HTMLSelectElement> HTMLSelectElement::create(Document& do
cument, HTMLFormElement* form) |
| 87 { | 96 { |
| 88 return adoptRefWillBeNoop(new HTMLSelectElement(document, form)); | 97 RefPtrWillBeRawPtr<HTMLSelectElement> select = adoptRefWillBeNoop(new HTMLSe
lectElement(document, form)); |
| 98 select->ensureUserAgentShadowRoot(); |
| 99 return select.release(); |
| 89 } | 100 } |
| 90 | 101 |
| 91 const AtomicString& HTMLSelectElement::formControlType() const | 102 const AtomicString& HTMLSelectElement::formControlType() const |
| 92 { | 103 { |
| 93 DEFINE_STATIC_LOCAL(const AtomicString, selectMultiple, ("select-multiple",
AtomicString::ConstructFromLiteral)); | 104 DEFINE_STATIC_LOCAL(const AtomicString, selectMultiple, ("select-multiple",
AtomicString::ConstructFromLiteral)); |
| 94 DEFINE_STATIC_LOCAL(const AtomicString, selectOne, ("select-one", AtomicStri
ng::ConstructFromLiteral)); | 105 DEFINE_STATIC_LOCAL(const AtomicString, selectOne, ("select-one", AtomicStri
ng::ConstructFromLiteral)); |
| 95 return m_multiple ? selectMultiple : selectOne; | 106 return m_multiple ? selectMultiple : selectOne; |
| 96 } | 107 } |
| 97 | 108 |
| 98 void HTMLSelectElement::optionSelectedByUser(int optionIndex, bool fireOnChangeN
ow, bool allowMultipleSelection) | 109 void HTMLSelectElement::optionSelectedByUser(int optionIndex, bool fireOnChangeN
ow, bool allowMultipleSelection) |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 sizeAttribute->setValue(attrSize); | 338 sizeAttribute->setValue(attrSize); |
| 328 } | 339 } |
| 329 size = std::max(size, 1); | 340 size = std::max(size, 1); |
| 330 | 341 |
| 331 // Ensure that we've determined selectedness of the items at least once
prior to changing the size. | 342 // Ensure that we've determined selectedness of the items at least once
prior to changing the size. |
| 332 if (oldSize != size) | 343 if (oldSize != size) |
| 333 updateListItemSelectedStates(); | 344 updateListItemSelectedStates(); |
| 334 | 345 |
| 335 m_size = size; | 346 m_size = size; |
| 336 setNeedsValidityCheck(); | 347 setNeedsValidityCheck(); |
| 337 if (m_size != oldSize && inActiveDocument()) { | 348 if (m_size != oldSize && document().isActive() && inDocument()) { |
| 338 lazyReattachIfAttached(); | 349 lazyReattachIfAttached(); |
| 339 setRecalcListItems(); | 350 setRecalcListItems(); |
| 340 } | 351 } |
| 341 } else if (name == multipleAttr) | 352 } else if (name == multipleAttr) |
| 342 parseMultipleAttribute(value); | 353 parseMultipleAttribute(value); |
| 343 else if (name == accesskeyAttr) { | 354 else if (name == accesskeyAttr) { |
| 344 // FIXME: ignore for the moment. | 355 // FIXME: ignore for the moment. |
| 345 // | 356 // |
| 346 } else if (name == disabledAttr) { | 357 } else if (name == disabledAttr) { |
| 347 HTMLFormControlElementWithState::parseAttribute(name, value); | 358 HTMLFormControlElementWithState::parseAttribute(name, value); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 359 bool HTMLSelectElement::shouldShowFocusRingOnMouseFocus() const | 370 bool HTMLSelectElement::shouldShowFocusRingOnMouseFocus() const |
| 360 { | 371 { |
| 361 return true; | 372 return true; |
| 362 } | 373 } |
| 363 | 374 |
| 364 bool HTMLSelectElement::canSelectAll() const | 375 bool HTMLSelectElement::canSelectAll() const |
| 365 { | 376 { |
| 366 return !usesMenuList(); | 377 return !usesMenuList(); |
| 367 } | 378 } |
| 368 | 379 |
| 369 RenderObject* HTMLSelectElement::createRenderer(RenderStyle*) | 380 RenderObject* HTMLSelectElement::createRenderer(RenderStyle* style) |
| 370 { | 381 { |
| 371 if (usesMenuList()) | 382 if (usesMenuList()) |
| 372 return new RenderMenuList(this); | 383 return new RenderMenuList(this); |
| 373 return new RenderListBox(this); | 384 return new RenderListBox(this); |
| 374 } | 385 } |
| 375 | 386 |
| 376 PassRefPtrWillBeRawPtr<HTMLCollection> HTMLSelectElement::selectedOptions() | 387 PassRefPtrWillBeRawPtr<HTMLCollection> HTMLSelectElement::selectedOptions() |
| 377 { | 388 { |
| 378 updateListItemSelectedStates(); | 389 updateListItemSelectedStates(); |
| 379 return ensureCachedHTMLCollection(SelectedOptions); | 390 return ensureCachedHTMLCollection(SelectedOptions); |
| 380 } | 391 } |
| 381 | 392 |
| 382 PassRefPtrWillBeRawPtr<HTMLOptionsCollection> HTMLSelectElement::options() | 393 PassRefPtrWillBeRawPtr<HTMLOptionsCollection> HTMLSelectElement::options() |
| 383 { | 394 { |
| 384 return toHTMLOptionsCollection(ensureCachedHTMLCollection(SelectOptions).get
()); | 395 return toHTMLOptionsCollection(ensureCachedHTMLCollection(SelectOptions).get
()); |
| 385 } | 396 } |
| 386 | 397 |
| 387 void HTMLSelectElement::updateListItemSelectedStates() | 398 void HTMLSelectElement::updateListItemSelectedStates() |
| 388 { | 399 { |
| 389 if (!m_shouldRecalcListItems) | 400 if (!m_shouldRecalcListItems) |
| 390 return; | 401 return; |
| 391 recalcListItems(); | 402 recalcListItems(); |
| 392 setNeedsValidityCheck(); | 403 setNeedsValidityCheck(); |
| 393 } | 404 } |
| 394 | 405 |
| 395 void HTMLSelectElement::childrenChanged(bool changedByParser, Node* beforeChange
, Node* afterChange, int childCountDelta) | 406 void HTMLSelectElement::childrenChanged(bool changedByParser, Node* beforeChange
, Node* afterChange, int childCountDelta) |
| 396 { | 407 { |
| 397 setRecalcListItems(); | 408 setRecalcListItems(); |
| 398 setNeedsValidityCheck(); | 409 setNeedsValidityCheck(); |
| 399 m_lastOnChangeSelection.clear(); | |
| 400 | 410 |
| 401 HTMLFormControlElementWithState::childrenChanged(changedByParser, beforeChan
ge, afterChange, childCountDelta); | 411 HTMLFormControlElementWithState::childrenChanged(changedByParser, beforeChan
ge, afterChange, childCountDelta); |
| 402 } | 412 } |
| 403 | 413 |
| 404 void HTMLSelectElement::optionElementChildrenChanged() | 414 void HTMLSelectElement::optionElementChildrenChanged() |
| 405 { | 415 { |
| 406 setRecalcListItems(); | 416 setRecalcListItems(); |
| 407 setNeedsValidityCheck(); | 417 setNeedsValidityCheck(); |
| 408 | 418 |
| 409 if (renderer()) { | 419 if (renderer()) { |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 516 // Valid means that it is enabled and an option element. | 526 // Valid means that it is enabled and an option element. |
| 517 int HTMLSelectElement::nextValidIndex(int listIndex, SkipDirection direction, in
t skip) const | 527 int HTMLSelectElement::nextValidIndex(int listIndex, SkipDirection direction, in
t skip) const |
| 518 { | 528 { |
| 519 ASSERT(direction == -1 || direction == 1); | 529 ASSERT(direction == -1 || direction == 1); |
| 520 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this->
listItems(); | 530 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this->
listItems(); |
| 521 int lastGoodIndex = listIndex; | 531 int lastGoodIndex = listIndex; |
| 522 int size = listItems.size(); | 532 int size = listItems.size(); |
| 523 for (listIndex += direction; listIndex >= 0 && listIndex < size; listIndex +
= direction) { | 533 for (listIndex += direction; listIndex >= 0 && listIndex < size; listIndex +
= direction) { |
| 524 --skip; | 534 --skip; |
| 525 HTMLElement* element = listItems[listIndex]; | 535 HTMLElement* element = listItems[listIndex]; |
| 526 if (!isHTMLOptionElement(*element) || toHTMLOptionElement(element)->isDi
sabledFormControl() || toHTMLOptionElement(element)->isDisplayNone()) | 536 if (isHTMLOptionElement(*element)) { |
| 537 const HTMLOptionElement& option = toHTMLOptionElement(*element); |
| 538 if (option.isDisabledFormControl()) |
| 539 continue; |
| 540 if (!usesMenuList() && !option.renderer()) |
| 541 continue; |
| 542 } else { |
| 527 continue; | 543 continue; |
| 544 } |
| 528 lastGoodIndex = listIndex; | 545 lastGoodIndex = listIndex; |
| 529 if (skip <= 0) | 546 if (skip <= 0) |
| 530 break; | 547 break; |
| 531 } | 548 } |
| 532 return lastGoodIndex; | 549 return lastGoodIndex; |
| 533 } | 550 } |
| 534 | 551 |
| 535 int HTMLSelectElement::nextSelectableListIndex(int startIndex) const | 552 int HTMLSelectElement::nextSelectableListIndex(int startIndex) const |
| 536 { | 553 { |
| 537 return nextValidIndex(startIndex, SkipForwards, 1); | 554 return nextValidIndex(startIndex, SkipForwards, 1); |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 633 { | 650 { |
| 634 ASSERT(renderer() && (renderer()->isListBox() || m_multiple)); | 651 ASSERT(renderer() && (renderer()->isListBox() || m_multiple)); |
| 635 ASSERT(!listItems().size() || m_activeSelectionAnchorIndex >= 0); | 652 ASSERT(!listItems().size() || m_activeSelectionAnchorIndex >= 0); |
| 636 | 653 |
| 637 unsigned start = std::min(m_activeSelectionAnchorIndex, m_activeSelectionEnd
Index); | 654 unsigned start = std::min(m_activeSelectionAnchorIndex, m_activeSelectionEnd
Index); |
| 638 unsigned end = std::max(m_activeSelectionAnchorIndex, m_activeSelectionEndIn
dex); | 655 unsigned end = std::max(m_activeSelectionAnchorIndex, m_activeSelectionEndIn
dex); |
| 639 | 656 |
| 640 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems(
); | 657 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems(
); |
| 641 for (unsigned i = 0; i < items.size(); ++i) { | 658 for (unsigned i = 0; i < items.size(); ++i) { |
| 642 HTMLElement* element = items[i]; | 659 HTMLElement* element = items[i]; |
| 643 if (!isHTMLOptionElement(*element) || toHTMLOptionElement(element)->isDi
sabledFormControl() || toHTMLOptionElement(element)->isDisplayNone()) | 660 if (!isHTMLOptionElement(*element) || toHTMLOptionElement(element)->isDi
sabledFormControl() || !toHTMLOptionElement(element)->renderer()) |
| 644 continue; | 661 continue; |
| 645 | 662 |
| 646 if (i >= start && i <= end) | 663 if (i >= start && i <= end) |
| 647 toHTMLOptionElement(element)->setSelectedState(m_activeSelectionStat
e); | 664 toHTMLOptionElement(element)->setSelectedState(m_activeSelectionStat
e); |
| 648 else if (deselectOtherOptions || i >= m_cachedStateForActiveSelection.si
ze()) | 665 else if (deselectOtherOptions || i >= m_cachedStateForActiveSelection.si
ze()) |
| 649 toHTMLOptionElement(element)->setSelectedState(false); | 666 toHTMLOptionElement(element)->setSelectedState(false); |
| 650 else | 667 else |
| 651 toHTMLOptionElement(element)->setSelectedState(m_cachedStateForActiv
eSelection[i]); | 668 toHTMLOptionElement(element)->setSelectedState(m_cachedStateForActiv
eSelection[i]); |
| 652 } | 669 } |
| 653 | 670 |
| 654 scrollToSelection(); | 671 scrollToSelection(); |
| 655 setNeedsValidityCheck(); | 672 setNeedsValidityCheck(); |
| 656 notifyFormStateChanged(); | 673 notifyFormStateChanged(); |
| 657 } | 674 } |
| 658 | 675 |
| 659 void HTMLSelectElement::listBoxOnChange() | 676 void HTMLSelectElement::listBoxOnChange() |
| 660 { | 677 { |
| 661 ASSERT(!usesMenuList() || m_multiple); | 678 ASSERT(!usesMenuList() || m_multiple); |
| 662 | 679 |
| 663 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems(
); | 680 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems(
); |
| 664 | 681 |
| 665 // If the cached selection list is empty, or the size has changed, then fire | |
| 666 // dispatchFormControlChangeEvent, and return early. | |
| 667 // FIXME: Why? This looks unreasonable. | |
| 668 if (m_lastOnChangeSelection.isEmpty() || m_lastOnChangeSelection.size() != i
tems.size()) { | |
| 669 dispatchFormControlChangeEvent(); | |
| 670 return; | |
| 671 } | |
| 672 | |
| 673 // Update m_lastOnChangeSelection and fire dispatchFormControlChangeEvent. | 682 // Update m_lastOnChangeSelection and fire dispatchFormControlChangeEvent. |
| 674 bool fireOnChange = false; | 683 bool fireOnChange = false; |
| 675 for (unsigned i = 0; i < items.size(); ++i) { | 684 for (unsigned i = 0; i < items.size(); ++i) { |
| 676 HTMLElement* element = items[i]; | 685 HTMLElement* element = items[i]; |
| 677 bool selected = isHTMLOptionElement(*element) && toHTMLOptionElement(ele
ment)->selected(); | 686 bool selected = isHTMLOptionElement(*element) && toHTMLOptionElement(ele
ment)->selected(); |
| 678 if (selected != m_lastOnChangeSelection[i]) | 687 if (i < m_lastOnChangeSelection.size()) { |
| 688 if (selected != m_lastOnChangeSelection[i]) { |
| 689 fireOnChange = true; |
| 690 break; |
| 691 } |
| 692 } else if (selected) { |
| 679 fireOnChange = true; | 693 fireOnChange = true; |
| 680 m_lastOnChangeSelection[i] = selected; | 694 break; |
| 695 } |
| 681 } | 696 } |
| 682 | 697 |
| 683 if (fireOnChange) { | 698 if (fireOnChange) { |
| 699 saveLastSelection(); |
| 684 RefPtrWillBeRawPtr<HTMLSelectElement> protector(this); | 700 RefPtrWillBeRawPtr<HTMLSelectElement> protector(this); |
| 685 dispatchInputEvent(); | 701 dispatchInputEvent(); |
| 686 dispatchFormControlChangeEvent(); | 702 dispatchFormControlChangeEvent(); |
| 687 } | 703 } |
| 688 } | 704 } |
| 689 | 705 |
| 690 void HTMLSelectElement::dispatchInputAndChangeEventForMenuList(bool requiresUser
Gesture) | 706 void HTMLSelectElement::dispatchInputAndChangeEventForMenuList(bool requiresUser
Gesture) |
| 691 { | 707 { |
| 692 ASSERT(usesMenuList()); | 708 ASSERT(usesMenuList()); |
| 693 | 709 |
| 694 int selected = selectedIndex(); | 710 int selected = selectedIndex(); |
| 695 if (m_lastOnChangeIndex != selected && (!requiresUserGesture || m_isProcessi
ngUserDrivenChange)) { | 711 if (m_lastOnChangeIndex != selected && (!requiresUserGesture || m_isProcessi
ngUserDrivenChange)) { |
| 696 m_lastOnChangeIndex = selected; | 712 m_lastOnChangeIndex = selected; |
| 697 m_isProcessingUserDrivenChange = false; | 713 m_isProcessingUserDrivenChange = false; |
| 698 RefPtrWillBeRawPtr<HTMLSelectElement> protector(this); | 714 RefPtrWillBeRawPtr<HTMLSelectElement> protector(this); |
| 699 dispatchInputEvent(); | 715 dispatchInputEvent(); |
| 700 dispatchFormControlChangeEvent(); | 716 dispatchFormControlChangeEvent(); |
| 701 } | 717 } |
| 702 } | 718 } |
| 703 | 719 |
| 704 void HTMLSelectElement::scrollToSelection() | 720 void HTMLSelectElement::scrollToSelection() |
| 705 { | 721 { |
| 722 if (!isFinishedParsingChildren()) |
| 723 return; |
| 706 if (usesMenuList()) | 724 if (usesMenuList()) |
| 707 return; | 725 return; |
| 708 | 726 scrollTo(activeSelectionEndListIndex()); |
| 709 if (RenderObject* renderer = this->renderer()) | 727 if (AXObjectCache* cache = document().existingAXObjectCache()) |
| 710 toRenderListBox(renderer)->selectionChanged(); | 728 cache->selectedChildrenChanged(this); |
| 711 } | 729 } |
| 712 | 730 |
| 713 void HTMLSelectElement::setOptionsChangedOnRenderer() | 731 void HTMLSelectElement::setOptionsChangedOnRenderer() |
| 714 { | 732 { |
| 715 if (RenderObject* renderer = this->renderer()) { | 733 if (RenderObject* renderer = this->renderer()) { |
| 716 if (usesMenuList()) | 734 if (usesMenuList()) |
| 717 toRenderMenuList(renderer)->setOptionsChanged(true); | 735 toRenderMenuList(renderer)->setOptionsChanged(true); |
| 718 else | |
| 719 toRenderListBox(renderer)->setOptionsChanged(true); | |
| 720 } | 736 } |
| 721 } | 737 } |
| 722 | 738 |
| 723 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& HTMLSelectElement::lis
tItems() const | 739 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& HTMLSelectElement::lis
tItems() const |
| 724 { | 740 { |
| 725 if (m_shouldRecalcListItems) | 741 if (m_shouldRecalcListItems) |
| 726 recalcListItems(); | 742 recalcListItems(); |
| 727 else { | 743 else { |
| 728 #if ASSERT_ENABLED | 744 #if ASSERT_ENABLED |
| 729 WillBeHeapVector<RawPtrWillBeMember<HTMLElement> > items = m_listItems; | 745 WillBeHeapVector<RawPtrWillBeMember<HTMLElement> > items = m_listItems; |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 851 { | 867 { |
| 852 return m_suggestedIndex; | 868 return m_suggestedIndex; |
| 853 } | 869 } |
| 854 | 870 |
| 855 void HTMLSelectElement::setSuggestedIndex(int suggestedIndex) | 871 void HTMLSelectElement::setSuggestedIndex(int suggestedIndex) |
| 856 { | 872 { |
| 857 m_suggestedIndex = suggestedIndex; | 873 m_suggestedIndex = suggestedIndex; |
| 858 | 874 |
| 859 if (RenderObject* renderer = this->renderer()) { | 875 if (RenderObject* renderer = this->renderer()) { |
| 860 renderer->updateFromElement(); | 876 renderer->updateFromElement(); |
| 861 if (renderer->isListBox()) | 877 scrollTo(suggestedIndex); |
| 862 toRenderListBox(renderer)->scrollToRevealElementAtListIndex(suggeste
dIndex); | |
| 863 } | 878 } |
| 864 } | 879 } |
| 865 | 880 |
| 881 void HTMLSelectElement::scrollTo(int listIndex) |
| 882 { |
| 883 if (listIndex < 0) |
| 884 return; |
| 885 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems(
); |
| 886 int listSize = static_cast<int>(items.size()); |
| 887 if (listIndex >= listSize) |
| 888 return; |
| 889 items[listIndex]->scrollIntoViewIfNeeded(false); |
| 890 } |
| 891 |
| 866 void HTMLSelectElement::optionSelectionStateChanged(HTMLOptionElement* option, b
ool optionIsSelected) | 892 void HTMLSelectElement::optionSelectionStateChanged(HTMLOptionElement* option, b
ool optionIsSelected) |
| 867 { | 893 { |
| 868 ASSERT(option->ownerSelectElement() == this); | 894 ASSERT(option->ownerSelectElement() == this); |
| 869 if (optionIsSelected) | 895 if (optionIsSelected) |
| 870 selectOption(option->index()); | 896 selectOption(option->index()); |
| 871 else if (!usesMenuList() || multiple()) | 897 else if (!usesMenuList() || multiple()) |
| 872 selectOption(-1); | 898 selectOption(-1); |
| 873 else | 899 else |
| 874 selectOption(nextSelectableListIndex(-1)); | 900 selectOption(nextSelectableListIndex(-1)); |
| 875 } | 901 } |
| 876 | 902 |
| 903 void HTMLSelectElement::optionRemoved(HTMLOptionElement* option) |
| 904 { |
| 905 if (m_activeSelectionAnchorIndex < 0 && m_activeSelectionEndIndex < 0) |
| 906 return; |
| 907 int listIndex = optionToListIndex(option->index()); |
| 908 if (listIndex <= m_activeSelectionAnchorIndex) |
| 909 m_activeSelectionAnchorIndex--; |
| 910 if (listIndex <= m_activeSelectionEndIndex) |
| 911 m_activeSelectionEndIndex--; |
| 912 } |
| 913 |
| 877 void HTMLSelectElement::selectOption(int optionIndex, SelectOptionFlags flags) | 914 void HTMLSelectElement::selectOption(int optionIndex, SelectOptionFlags flags) |
| 878 { | 915 { |
| 879 bool shouldDeselect = !m_multiple || (flags & DeselectOtherOptions); | 916 bool shouldDeselect = !m_multiple || (flags & DeselectOtherOptions); |
| 880 | 917 |
| 881 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems(
); | 918 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems(
); |
| 882 int listIndex = optionToListIndex(optionIndex); | 919 int listIndex = optionToListIndex(optionIndex); |
| 883 | 920 |
| 884 HTMLElement* element = 0; | 921 HTMLElement* element = 0; |
| 885 if (listIndex >= 0) { | 922 if (listIndex >= 0) { |
| 886 element = items[listIndex]; | 923 element = items[listIndex]; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 902 | 939 |
| 903 scrollToSelection(); | 940 scrollToSelection(); |
| 904 | 941 |
| 905 setNeedsValidityCheck(); | 942 setNeedsValidityCheck(); |
| 906 | 943 |
| 907 if (usesMenuList()) { | 944 if (usesMenuList()) { |
| 908 m_isProcessingUserDrivenChange = flags & UserDriven; | 945 m_isProcessingUserDrivenChange = flags & UserDriven; |
| 909 if (flags & DispatchInputAndChangeEvent) | 946 if (flags & DispatchInputAndChangeEvent) |
| 910 dispatchInputAndChangeEventForMenuList(); | 947 dispatchInputAndChangeEventForMenuList(); |
| 911 if (RenderObject* renderer = this->renderer()) { | 948 if (RenderObject* renderer = this->renderer()) { |
| 912 if (usesMenuList()) | 949 if (usesMenuList()) { |
| 913 toRenderMenuList(renderer)->didSetSelectedIndex(listIndex); | 950 toRenderMenuList(renderer)->didSetSelectedIndex(listIndex); |
| 914 else if (renderer->isListBox()) | 951 } else if (renderer->isListBox()) { |
| 915 toRenderListBox(renderer)->selectionChanged(); | 952 if (AXObjectCache* cache = document().existingAXObjectCache()) |
| 953 cache->selectedChildrenChanged(this); |
| 954 } |
| 916 } | 955 } |
| 917 } | 956 } |
| 918 | 957 |
| 919 notifyFormStateChanged(); | 958 notifyFormStateChanged(); |
| 920 } | 959 } |
| 921 | 960 |
| 922 int HTMLSelectElement::optionToListIndex(int optionIndex) const | 961 int HTMLSelectElement::optionToListIndex(int optionIndex) const |
| 923 { | 962 { |
| 924 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems(
); | 963 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems(
); |
| 925 int listSize = static_cast<int>(items.size()); | 964 int listSize = static_cast<int>(items.size()); |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1046 startIndex = foundIndex + 1; | 1085 startIndex = foundIndex + 1; |
| 1047 } | 1086 } |
| 1048 } | 1087 } |
| 1049 | 1088 |
| 1050 setOptionsChangedOnRenderer(); | 1089 setOptionsChangedOnRenderer(); |
| 1051 setNeedsValidityCheck(); | 1090 setNeedsValidityCheck(); |
| 1052 } | 1091 } |
| 1053 | 1092 |
| 1054 void HTMLSelectElement::parseMultipleAttribute(const AtomicString& value) | 1093 void HTMLSelectElement::parseMultipleAttribute(const AtomicString& value) |
| 1055 { | 1094 { |
| 1056 bool oldUsesMenuList = usesMenuList(); | |
| 1057 m_multiple = !value.isNull(); | 1095 m_multiple = !value.isNull(); |
| 1058 setNeedsValidityCheck(); | 1096 setNeedsValidityCheck(); |
| 1059 if (oldUsesMenuList != usesMenuList()) | 1097 |
| 1060 lazyReattachIfAttached(); | 1098 lazyReattachIfAttached(); |
| 1061 } | 1099 } |
| 1062 | 1100 |
| 1063 bool HTMLSelectElement::appendFormData(FormDataList& list, bool) | 1101 bool HTMLSelectElement::appendFormData(FormDataList& list, bool) |
| 1064 { | 1102 { |
| 1065 const AtomicString& name = this->name(); | 1103 const AtomicString& name = this->name(); |
| 1066 if (name.isEmpty()) | 1104 if (name.isEmpty()) |
| 1067 return false; | 1105 return false; |
| 1068 | 1106 |
| 1069 bool successful = false; | 1107 bool successful = false; |
| 1070 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems(
); | 1108 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems(
); |
| (...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1328 // we're doing a single selection, or a multiple selection (using cmd or | 1366 // we're doing a single selection, or a multiple selection (using cmd or |
| 1329 // ctrl), then initialize the anchor index to the listIndex that just got | 1367 // ctrl), then initialize the anchor index to the listIndex that just got |
| 1330 // clicked. | 1368 // clicked. |
| 1331 if (m_activeSelectionAnchorIndex < 0 || !shiftSelect) | 1369 if (m_activeSelectionAnchorIndex < 0 || !shiftSelect) |
| 1332 setActiveSelectionAnchorIndex(listIndex); | 1370 setActiveSelectionAnchorIndex(listIndex); |
| 1333 | 1371 |
| 1334 setActiveSelectionEndIndex(listIndex); | 1372 setActiveSelectionEndIndex(listIndex); |
| 1335 updateListBoxSelection(!multiSelect); | 1373 updateListBoxSelection(!multiSelect); |
| 1336 } | 1374 } |
| 1337 | 1375 |
| 1376 int HTMLSelectElement::listIndexForEventTargetOption(const Event& event) |
| 1377 { |
| 1378 Node* targetNode = event.target()->toNode(); |
| 1379 if (!targetNode || !isHTMLOptionElement(*targetNode)) |
| 1380 return -1; |
| 1381 return listIndexForOption(toHTMLOptionElement(*targetNode)); |
| 1382 } |
| 1383 |
| 1384 int HTMLSelectElement::listIndexForOption(const HTMLOptionElement& option) |
| 1385 { |
| 1386 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = this->list
Items(); |
| 1387 size_t length = items.size(); |
| 1388 for (size_t i = 0; i < length; ++i) { |
| 1389 if (items[i] == &option) |
| 1390 return i; |
| 1391 } |
| 1392 return -1; |
| 1393 } |
| 1394 |
| 1395 AutoscrollController* HTMLSelectElement::autoscrollController() const |
| 1396 { |
| 1397 if (Page* page = document().page()) |
| 1398 return &page->autoscrollController(); |
| 1399 return 0; |
| 1400 } |
| 1401 |
| 1338 void HTMLSelectElement::listBoxDefaultEventHandler(Event* event) | 1402 void HTMLSelectElement::listBoxDefaultEventHandler(Event* event) |
| 1339 { | 1403 { |
| 1340 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this->
listItems(); | 1404 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this->
listItems(); |
| 1341 if (event->type() == EventTypeNames::gesturetap && event->isGestureEvent())
{ | 1405 if (event->type() == EventTypeNames::gesturetap && event->isGestureEvent())
{ |
| 1342 focus(); | 1406 focus(); |
| 1343 // Calling focus() may cause us to lose our renderer or change the rende
r type, in which case do not want to handle the event. | 1407 // Calling focus() may cause us to lose our renderer or change the rende
r type, in which case do not want to handle the event. |
| 1344 if (!renderer() || !renderer()->isListBox()) | 1408 if (!renderer() || !renderer()->isListBox()) |
| 1345 return; | 1409 return; |
| 1346 | 1410 |
| 1347 // Convert to coords relative to the list box if needed. | 1411 // Convert to coords relative to the list box if needed. |
| 1348 GestureEvent& gestureEvent = toGestureEvent(*event); | 1412 GestureEvent& gestureEvent = toGestureEvent(*event); |
| 1349 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(gestu
reEvent.absoluteLocation(), UseTransforms)); | 1413 int listIndex = listIndexForEventTargetOption(gestureEvent); |
| 1350 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize
(localOffset)); | |
| 1351 if (listIndex >= 0) { | 1414 if (listIndex >= 0) { |
| 1352 if (!isDisabledFormControl()) | 1415 if (!isDisabledFormControl()) |
| 1353 updateSelectedState(listIndex, true, gestureEvent.shiftKey()); | 1416 updateSelectedState(listIndex, true, gestureEvent.shiftKey()); |
| 1354 event->setDefaultHandled(); | 1417 event->setDefaultHandled(); |
| 1355 } | 1418 } |
| 1356 } else if (event->type() == EventTypeNames::mousedown && event->isMouseEvent
() && toMouseEvent(event)->button() == LeftButton) { | 1419 } else if (event->type() == EventTypeNames::mousedown && event->isMouseEvent
() && toMouseEvent(event)->button() == LeftButton) { |
| 1357 focus(); | 1420 focus(); |
| 1358 // Calling focus() may cause us to lose our renderer, in which case do n
ot want to handle the event. | 1421 // Calling focus() may cause us to lose our renderer, in which case do n
ot want to handle the event. |
| 1359 if (!renderer() || !renderer()->isListBox() || isDisabledFormControl()) | 1422 if (!renderer() || !renderer()->isListBox() || isDisabledFormControl()) |
| 1360 return; | 1423 return; |
| 1361 | 1424 |
| 1425 if (Page* page = document().page()) |
| 1426 page->autoscrollController().startAutoscrollForSelection(renderer())
; |
| 1427 |
| 1362 // Convert to coords relative to the list box if needed. | 1428 // Convert to coords relative to the list box if needed. |
| 1363 MouseEvent* mouseEvent = toMouseEvent(event); | 1429 MouseEvent* mouseEvent = toMouseEvent(event); |
| 1364 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(mouse
Event->absoluteLocation(), UseTransforms)); | 1430 int listIndex = listIndexForEventTargetOption(*mouseEvent); |
| 1365 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize
(localOffset)); | |
| 1366 if (listIndex >= 0) { | 1431 if (listIndex >= 0) { |
| 1367 if (!isDisabledFormControl()) { | 1432 if (!isDisabledFormControl()) { |
| 1368 #if OS(MACOSX) | 1433 #if OS(MACOSX) |
| 1369 updateSelectedState(listIndex, mouseEvent->metaKey(), mouseEvent
->shiftKey()); | 1434 updateSelectedState(listIndex, mouseEvent->metaKey(), mouseEvent
->shiftKey()); |
| 1370 #else | 1435 #else |
| 1371 updateSelectedState(listIndex, mouseEvent->ctrlKey(), mouseEvent
->shiftKey()); | 1436 updateSelectedState(listIndex, mouseEvent->ctrlKey(), mouseEvent
->shiftKey()); |
| 1372 #endif | 1437 #endif |
| 1373 } | 1438 } |
| 1374 if (LocalFrame* frame = document().frame()) | 1439 if (LocalFrame* frame = document().frame()) |
| 1375 frame->eventHandler().setMouseDownMayStartAutoscroll(); | 1440 frame->eventHandler().setMouseDownMayStartAutoscroll(); |
| 1376 | 1441 |
| 1377 event->setDefaultHandled(); | 1442 event->setDefaultHandled(); |
| 1378 } | 1443 } |
| 1379 } else if (event->type() == EventTypeNames::mousemove && event->isMouseEvent
() && !toRenderBox(renderer())->canBeScrolledAndHasScrollableArea()) { | 1444 } else if (event->type() == EventTypeNames::mousemove && event->isMouseEvent
()) { |
| 1380 MouseEvent* mouseEvent = toMouseEvent(event); | 1445 MouseEvent* mouseEvent = toMouseEvent(event); |
| 1381 if (mouseEvent->button() != LeftButton || !mouseEvent->buttonDown()) | 1446 if (mouseEvent->button() != LeftButton || !mouseEvent->buttonDown()) |
| 1382 return; | 1447 return; |
| 1383 | 1448 int listIndex = listIndexForEventTargetOption(*mouseEvent); |
| 1384 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(mouse
Event->absoluteLocation(), UseTransforms)); | |
| 1385 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize
(localOffset)); | |
| 1386 if (listIndex >= 0) { | 1449 if (listIndex >= 0) { |
| 1387 if (!isDisabledFormControl()) { | 1450 if (!isDisabledFormControl()) { |
| 1388 if (m_multiple) { | 1451 if (m_multiple) { |
| 1389 // Only extend selection if there is something selected. | 1452 // Only extend selection if there is something selected. |
| 1390 if (m_activeSelectionAnchorIndex < 0) | 1453 if (m_activeSelectionAnchorIndex < 0) |
| 1391 return; | 1454 return; |
| 1392 | 1455 |
| 1393 setActiveSelectionEndIndex(listIndex); | 1456 setActiveSelectionEndIndex(listIndex); |
| 1394 updateListBoxSelection(false); | 1457 updateListBoxSelection(false); |
| 1395 } else { | 1458 } else { |
| 1396 setActiveSelectionAnchorIndex(listIndex); | 1459 setActiveSelectionAnchorIndex(listIndex); |
| 1397 setActiveSelectionEndIndex(listIndex); | 1460 setActiveSelectionEndIndex(listIndex); |
| 1398 updateListBoxSelection(true); | 1461 updateListBoxSelection(true); |
| 1399 } | 1462 } |
| 1400 } | 1463 } |
| 1401 } | 1464 } |
| 1402 } else if (event->type() == EventTypeNames::mouseup && event->isMouseEvent()
&& toMouseEvent(event)->button() == LeftButton && renderer() && !toRenderBox(re
nderer())->autoscrollInProgress()) { | 1465 } else if (event->type() == EventTypeNames::mouseup && event->isMouseEvent()
&& toMouseEvent(event)->button() == LeftButton && renderer()) { |
| 1403 // We didn't start this click/drag on any options. | 1466 // We didn't start this click/drag on any options. |
| 1404 if (m_lastOnChangeSelection.isEmpty()) | 1467 if (m_lastOnChangeSelection.isEmpty()) |
| 1405 return; | 1468 return; |
| 1406 listBoxOnChange(); | 1469 listBoxOnChange(); |
| 1407 } else if (event->type() == EventTypeNames::keydown) { | 1470 } else if (event->type() == EventTypeNames::keydown) { |
| 1408 if (!event->isKeyboardEvent()) | 1471 if (!event->isKeyboardEvent()) |
| 1409 return; | 1472 return; |
| 1410 const String& keyIdentifier = toKeyboardEvent(event)->keyIdentifier(); | 1473 const String& keyIdentifier = toKeyboardEvent(event)->keyIdentifier(); |
| 1411 | 1474 |
| 1412 bool handled = false; | 1475 bool handled = false; |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1471 m_activeSelectionState = true; | 1534 m_activeSelectionState = true; |
| 1472 // If the anchor is unitialized, or if we're going to deselect all | 1535 // If the anchor is unitialized, or if we're going to deselect all |
| 1473 // other options, then set the anchor index equal to the end index. | 1536 // other options, then set the anchor index equal to the end index. |
| 1474 bool deselectOthers = !m_multiple || (!toKeyboardEvent(event)->shift
Key() && selectNewItem); | 1537 bool deselectOthers = !m_multiple || (!toKeyboardEvent(event)->shift
Key() && selectNewItem); |
| 1475 if (m_activeSelectionAnchorIndex < 0 || deselectOthers) { | 1538 if (m_activeSelectionAnchorIndex < 0 || deselectOthers) { |
| 1476 if (deselectOthers) | 1539 if (deselectOthers) |
| 1477 deselectItemsWithoutValidation(); | 1540 deselectItemsWithoutValidation(); |
| 1478 setActiveSelectionAnchorIndex(m_activeSelectionEndIndex); | 1541 setActiveSelectionAnchorIndex(m_activeSelectionEndIndex); |
| 1479 } | 1542 } |
| 1480 | 1543 |
| 1481 toRenderListBox(renderer())->scrollToRevealElementAtListIndex(endInd
ex); | 1544 scrollTo(endIndex); |
| 1482 if (selectNewItem) { | 1545 if (selectNewItem) { |
| 1483 updateListBoxSelection(deselectOthers); | 1546 updateListBoxSelection(deselectOthers); |
| 1484 listBoxOnChange(); | 1547 listBoxOnChange(); |
| 1485 } else | 1548 } else |
| 1486 scrollToSelection(); | 1549 scrollToSelection(); |
| 1487 | 1550 |
| 1488 event->setDefaultHandled(); | 1551 event->setDefaultHandled(); |
| 1489 } | 1552 } |
| 1490 } else if (event->type() == EventTypeNames::keypress) { | 1553 } else if (event->type() == EventTypeNames::keypress) { |
| 1491 if (!event->isKeyboardEvent()) | 1554 if (!event->isKeyboardEvent()) |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1622 ++options; | 1685 ++options; |
| 1623 } | 1686 } |
| 1624 | 1687 |
| 1625 return options; | 1688 return options; |
| 1626 } | 1689 } |
| 1627 | 1690 |
| 1628 void HTMLSelectElement::finishParsingChildren() | 1691 void HTMLSelectElement::finishParsingChildren() |
| 1629 { | 1692 { |
| 1630 HTMLFormControlElementWithState::finishParsingChildren(); | 1693 HTMLFormControlElementWithState::finishParsingChildren(); |
| 1631 updateListItemSelectedStates(); | 1694 updateListItemSelectedStates(); |
| 1695 scrollToSelection(); |
| 1632 } | 1696 } |
| 1633 | 1697 |
| 1634 bool HTMLSelectElement::anonymousIndexedSetter(unsigned index, PassRefPtrWillBeR
awPtr<HTMLOptionElement> value, ExceptionState& exceptionState) | 1698 bool HTMLSelectElement::anonymousIndexedSetter(unsigned index, PassRefPtrWillBeR
awPtr<HTMLOptionElement> value, ExceptionState& exceptionState) |
| 1635 { | 1699 { |
| 1636 if (!value) { // undefined or null | 1700 if (!value) { // undefined or null |
| 1637 remove(index); | 1701 remove(index); |
| 1638 return true; | 1702 return true; |
| 1639 } | 1703 } |
| 1640 setOption(index, value.get(), exceptionState); | 1704 setOption(index, value.get(), exceptionState); |
| 1641 return true; | 1705 return true; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1657 } | 1721 } |
| 1658 | 1722 |
| 1659 void HTMLSelectElement::trace(Visitor* visitor) | 1723 void HTMLSelectElement::trace(Visitor* visitor) |
| 1660 { | 1724 { |
| 1661 #if ENABLE(OILPAN) | 1725 #if ENABLE(OILPAN) |
| 1662 visitor->trace(m_listItems); | 1726 visitor->trace(m_listItems); |
| 1663 #endif | 1727 #endif |
| 1664 HTMLFormControlElementWithState::trace(visitor); | 1728 HTMLFormControlElementWithState::trace(visitor); |
| 1665 } | 1729 } |
| 1666 | 1730 |
| 1731 void HTMLSelectElement::didAddUserAgentShadowRoot(ShadowRoot& root) |
| 1732 { |
| 1733 RefPtrWillBeRawPtr<HTMLContentElement> content = HTMLContentElement::create(
document()); |
| 1734 content->setAttribute(selectAttr, "option,optgroup"); |
| 1735 root.appendChild(content); |
| 1736 } |
| 1737 |
| 1667 } // namespace | 1738 } // namespace |
| OLD | NEW |