Changeset 202245 in webkit


Ignore:
Timestamp:
Jun 20, 2016 2:30:36 PM (8 years ago)
Author:
benjamin@webkit.org
Message:

:default CSS pseudo-class should match checkboxes+radios with a checked attribute
https://bugs.webkit.org/show_bug.cgi?id=156230

Reviewed by Alex Christensen.

LayoutTests/imported/w3c:

  • web-platform-tests/html/semantics/selectors/pseudo-classes/default-expected.txt:

Source/WebCore:

This patch update the :default pseudo class matching to be closer to the spec:
https://html.spec.whatwg.org/multipage/scripting.html#selector-default

The main remaining difference with the spec is the definition of "default button".
This is an unrelated problem that should be addressed separately.

The implementation was missing support for:
-input elements of type "checkbox" or "radio" with the "checked" attribute defined.
-option elements with the "selected" attribute defined.

The existing support for default button was pretty bad, I fixed that too.
The owner form now has a resetDefaultButton() API. When a Form Associated Element
becomes a submit button or loses that property, the element calls its form
to update the style as needed.

Whenever the submit button changes, 2 elements needs to have their style invalidated:
-The former default button.
-The new default button.
To invalidate the former button, FormElement now caches the computed
default button. When the default button changes, the cached value is invalidated
in addition to the new value.

Computing the new default button takes linear time in the number of form associated element.
To mitigate that, resetDefaultButton() is only called when changes are related
to submit buttons. Since those changes are rare, I don't expect the invalidation
to be a problem.

Tests: fast/css/pseudo-default-basics.html

fast/selectors/default-style-update.html

  • css/SelectorChecker.cpp:

(WebCore::SelectorChecker::checkOne):

  • css/SelectorCheckerTestFunctions.h:

(WebCore::matchesDefaultPseudoClass):
(WebCore::isDefaultButtonForForm): Deleted.

  • cssjit/SelectorCompiler.cpp:

(WebCore::SelectorCompiler::addPseudoClassType):

  • dom/Element.cpp:

(WebCore::Element::matchesValidPseudoClass):
(WebCore::Element::matchesInvalidPseudoClass):
(WebCore::Element::matchesDefaultPseudoClass):

  • dom/Element.h:

(WebCore::Element::matchesValidPseudoClass): Deleted.
(WebCore::Element::matchesInvalidPseudoClass): Deleted.
(WebCore::Element::isDefaultButtonForForm): Deleted.

  • html/HTMLButtonElement.cpp:

(WebCore::HTMLButtonElement::parseAttribute):
(WebCore::HTMLButtonElement::matchesDefaultPseudoClass):

  • html/HTMLButtonElement.h:
  • html/HTMLFormControlElement.cpp:

(WebCore::HTMLFormControlElement::isDefaultButtonForForm): Deleted.

  • html/HTMLFormControlElement.h:
  • html/HTMLFormElement.cpp:

(WebCore::HTMLFormElement::~HTMLFormElement):
(WebCore::HTMLFormElement::registerFormElement):
(WebCore::HTMLFormElement::removeFormElement):
(WebCore::HTMLFormElement::defaultButton):
(WebCore::HTMLFormElement::resetDefaultButton):

  • html/HTMLFormElement.h:
  • html/HTMLInputElement.cpp:

(WebCore::HTMLInputElement::updateType):
(WebCore::HTMLInputElement::parseAttribute):
(WebCore::HTMLInputElement::matchesDefaultPseudoClass):

  • html/HTMLInputElement.h:
  • html/HTMLOptionElement.cpp:

(WebCore::HTMLOptionElement::matchesDefaultPseudoClass):
(WebCore::HTMLOptionElement::parseAttribute):

  • html/HTMLOptionElement.h:
  • style/StyleSharingResolver.cpp:

(WebCore::Style::SharingResolver::canShareStyleWithElement):
(WebCore::Style::canShareStyleWithControl): Deleted.

LayoutTests:

  • fast/css/pseudo-default-basics-expected.html: Added.
  • fast/css/pseudo-default-basics.html: Added.
  • fast/selectors/default-style-update-expected.txt: Added.
  • fast/selectors/default-style-update.html: Added.
Location:
trunk
Files:
4 added
20 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r202243 r202245  
     12016-06-20  Benjamin Poulain  <benjamin@webkit.org>
     2
     3        :default CSS pseudo-class should match checkboxes+radios with a `checked` attribute
     4        https://bugs.webkit.org/show_bug.cgi?id=156230
     5
     6        Reviewed by Alex Christensen.
     7
     8        * fast/css/pseudo-default-basics-expected.html: Added.
     9        * fast/css/pseudo-default-basics.html: Added.
     10        * fast/selectors/default-style-update-expected.txt: Added.
     11        * fast/selectors/default-style-update.html: Added.
     12
    1132016-06-20  Simon Fraser  <simon.fraser@apple.com>
    214
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r202197 r202245  
     12016-06-20  Benjamin Poulain  <benjamin@webkit.org>
     2
     3        :default CSS pseudo-class should match checkboxes+radios with a `checked` attribute
     4        https://bugs.webkit.org/show_bug.cgi?id=156230
     5
     6        Reviewed by Alex Christensen.
     7
     8        * web-platform-tests/html/semantics/selectors/pseudo-classes/default-expected.txt:
     9
    1102016-06-17  Benjamin Poulain  <benjamin@webkit.org>
    211
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/semantics/selectors/pseudo-classes/default-expected.txt

    r200309 r202245  
    1111button8  button9
    1212
    13 FAIL ':default' matches <button>s that are their form's default button, <input>s of type submit/image that are their form's default button, checked <input>s and selected <option>s assert_array_equals: lengths differ, expected 10 got 7
    14 FAIL ':default' matches dynamically changed form's default buttons assert_array_equals: lengths differ, expected 10 got 7
     13PASS ':default' matches <button>s that are their form's default button, <input>s of type submit/image that are their form's default button, checked <input>s and selected <option>s
     14PASS ':default' matches dynamically changed form's default buttons
    1515
  • trunk/Source/WebCore/ChangeLog

    r202243 r202245  
     12016-06-20  Benjamin Poulain  <benjamin@webkit.org>
     2
     3        :default CSS pseudo-class should match checkboxes+radios with a `checked` attribute
     4        https://bugs.webkit.org/show_bug.cgi?id=156230
     5
     6        Reviewed by Alex Christensen.
     7
     8        This patch update the :default pseudo class matching to be closer to the spec:
     9        https://html.spec.whatwg.org/multipage/scripting.html#selector-default
     10
     11        The main remaining difference with the spec is the definition of "default button".
     12        This is an unrelated problem that should be addressed separately.
     13
     14        The implementation was missing support for:
     15        -input elements of type "checkbox" or "radio" with the "checked" attribute defined.
     16        -option elements with the "selected" attribute defined.
     17
     18        The existing support for default button was pretty bad, I fixed that too.
     19        The owner form now has a resetDefaultButton() API. When a Form Associated Element
     20        becomes a submit button or loses that property, the element calls its form
     21        to update the style as needed.
     22
     23        Whenever the submit button changes, 2 elements needs to have their style invalidated:
     24        -The former default button.
     25        -The new default button.
     26        To invalidate the former button, FormElement now caches the computed
     27        default button. When the default button changes, the cached value is invalidated
     28        in addition to the new value.
     29
     30        Computing the new default button takes linear time in the number of form associated element.
     31        To mitigate that, resetDefaultButton() is only called when changes are related
     32        to submit buttons. Since those changes are rare, I don't expect the invalidation
     33        to be a problem.
     34
     35        Tests: fast/css/pseudo-default-basics.html
     36               fast/selectors/default-style-update.html
     37
     38        * css/SelectorChecker.cpp:
     39        (WebCore::SelectorChecker::checkOne):
     40        * css/SelectorCheckerTestFunctions.h:
     41        (WebCore::matchesDefaultPseudoClass):
     42        (WebCore::isDefaultButtonForForm): Deleted.
     43        * cssjit/SelectorCompiler.cpp:
     44        (WebCore::SelectorCompiler::addPseudoClassType):
     45        * dom/Element.cpp:
     46        (WebCore::Element::matchesValidPseudoClass):
     47        (WebCore::Element::matchesInvalidPseudoClass):
     48        (WebCore::Element::matchesDefaultPseudoClass):
     49        * dom/Element.h:
     50        (WebCore::Element::matchesValidPseudoClass): Deleted.
     51        (WebCore::Element::matchesInvalidPseudoClass): Deleted.
     52        (WebCore::Element::isDefaultButtonForForm): Deleted.
     53        * html/HTMLButtonElement.cpp:
     54        (WebCore::HTMLButtonElement::parseAttribute):
     55        (WebCore::HTMLButtonElement::matchesDefaultPseudoClass):
     56        * html/HTMLButtonElement.h:
     57        * html/HTMLFormControlElement.cpp:
     58        (WebCore::HTMLFormControlElement::isDefaultButtonForForm): Deleted.
     59        * html/HTMLFormControlElement.h:
     60        * html/HTMLFormElement.cpp:
     61        (WebCore::HTMLFormElement::~HTMLFormElement):
     62        (WebCore::HTMLFormElement::registerFormElement):
     63        (WebCore::HTMLFormElement::removeFormElement):
     64        (WebCore::HTMLFormElement::defaultButton):
     65        (WebCore::HTMLFormElement::resetDefaultButton):
     66        * html/HTMLFormElement.h:
     67        * html/HTMLInputElement.cpp:
     68        (WebCore::HTMLInputElement::updateType):
     69        (WebCore::HTMLInputElement::parseAttribute):
     70        (WebCore::HTMLInputElement::matchesDefaultPseudoClass):
     71        * html/HTMLInputElement.h:
     72        * html/HTMLOptionElement.cpp:
     73        (WebCore::HTMLOptionElement::matchesDefaultPseudoClass):
     74        (WebCore::HTMLOptionElement::parseAttribute):
     75        * html/HTMLOptionElement.h:
     76        * style/StyleSharingResolver.cpp:
     77        (WebCore::Style::SharingResolver::canShareStyleWithElement):
     78        (WebCore::Style::canShareStyleWithControl): Deleted.
     79
    1802016-06-20  Simon Fraser  <simon.fraser@apple.com>
    281
  • trunk/Source/WebCore/css/SelectorChecker.cpp

    r202197 r202245  
    966966            return isMediaDocument(element);
    967967        case CSSSelector::PseudoClassDefault:
    968             return isDefaultButtonForForm(element);
     968            return matchesDefaultPseudoClass(element);
    969969        case CSSSelector::PseudoClassDisabled:
    970970            return isDisabled(element);
  • trunk/Source/WebCore/css/SelectorCheckerTestFunctions.h

    r202197 r202245  
    4747}
    4848
    49 ALWAYS_INLINE bool isDefaultButtonForForm(const Element& element)
    50 {
    51     return element.isDefaultButtonForForm();
     49ALWAYS_INLINE bool matchesDefaultPseudoClass(const Element& element)
     50{
     51    return element.matchesDefaultPseudoClass();
    5252}
    5353
  • trunk/Source/WebCore/cssjit/SelectorCompiler.cpp

    r202197 r202245  
    536536        return FunctionType::SimpleSelectorChecker;
    537537    case CSSSelector::PseudoClassDefault:
    538         fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr(isDefaultButtonForForm));
     538        fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr(matchesDefaultPseudoClass));
    539539        return FunctionType::SimpleSelectorChecker;
    540540    case CSSSelector::PseudoClassDisabled:
  • trunk/Source/WebCore/dom/Element.cpp

    r202243 r202245  
    27482748}
    27492749
     2750bool Element::matchesValidPseudoClass() const
     2751{
     2752    return false;
     2753}
     2754
     2755bool Element::matchesInvalidPseudoClass() const
     2756{
     2757    return false;
     2758}
     2759
    27502760bool Element::matchesReadWritePseudoClass() const
    27512761{
     
    27562766{
    27572767    return shouldAppearIndeterminate();
     2768}
     2769
     2770bool Element::matchesDefaultPseudoClass() const
     2771{
     2772    return false;
    27582773}
    27592774
  • trunk/Source/WebCore/dom/Element.h

    r202243 r202245  
    392392    void didShadowTreeAwareChildrenChange();
    393393
     394    virtual bool matchesValidPseudoClass() const;
     395    virtual bool matchesInvalidPseudoClass() const;
    394396    virtual bool matchesReadWritePseudoClass() const;
    395397    virtual bool matchesIndeterminatePseudoClass() const;
     398    virtual bool matchesDefaultPseudoClass() const;
    396399    bool matches(const String& selectors, ExceptionCode&);
    397400    Element* closest(const String& selectors, ExceptionCode&);
     
    406409#endif
    407410
    408     virtual bool matchesValidPseudoClass() const { return false; }
    409     virtual bool matchesInvalidPseudoClass() const { return false; }
    410411    virtual bool isFormControlElement() const { return false; }
    411412    virtual bool isSpinButtonElement() const { return false; }
     
    413414    virtual bool isOptionalFormControl() const { return false; }
    414415    virtual bool isRequiredFormControl() const { return false; }
    415     virtual bool isDefaultButtonForForm() const { return false; }
    416416    virtual bool isInRange() const { return false; }
    417417    virtual bool isOutOfRange() const { return false; }
  • trunk/Source/WebCore/html/HTMLButtonElement.cpp

    r200041 r202245  
    33 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
    44 *           (C) 2001 Dirk Mueller (mueller@kde.org)
    5  * Copyright (C) 2004, 2005, 2006, 2007, 2010 Apple Inc. All rights reserved.
     5 * Copyright (C) 2004, 2005, 2006, 2007, 2010, 2016 Apple Inc. All rights reserved.
    66 *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
    77 * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
     
    9797{
    9898    if (name == typeAttr) {
     99        Type oldType = m_type;
    99100        if (equalLettersIgnoringASCIICase(value, "reset"))
    100101            m_type = RESET;
     
    103104        else
    104105            m_type = SUBMIT;
    105         setNeedsWillValidateCheck();
     106        if (oldType != m_type) {
     107            setNeedsWillValidateCheck();
     108            if (form() && (oldType == SUBMIT || m_type == SUBMIT))
     109                form()->resetDefaultButton();
     110        }
    106111    } else
    107112        HTMLFormControlElement::parseAttribute(name, value);
     
    165170}
    166171
     172bool HTMLButtonElement::matchesDefaultPseudoClass() const
     173{
     174    return isSuccessfulSubmitButton() && form() && form()->defaultButton() == this;
     175}
     176
    167177bool HTMLButtonElement::isActivatedSubmit() const
    168178{
  • trunk/Source/WebCore/html/HTMLButtonElement.h

    r201739 r202245  
    33 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
    44 *           (C) 2000 Dirk Mueller (mueller@kde.org)
    5  * Copyright (C) 2004, 2005, 2006, 2007, 2010 Apple Inc. All rights reserved.
     5 * Copyright (C) 2004, 2005, 2006, 2007, 2010, 2016 Apple Inc. All rights reserved.
    66 *
    77 * This library is free software; you can redistribute it and/or
     
    6464
    6565    bool isSuccessfulSubmitButton() const override;
     66    bool matchesDefaultPseudoClass() const override;
    6667    bool isActivatedSubmit() const override;
    6768    void setActivatedSubmit(bool flag) override;
  • trunk/Source/WebCore/html/HTMLFormControlElement.cpp

    r200895 r202245  
    33 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
    44 *           (C) 2001 Dirk Mueller (mueller@kde.org)
    5  * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
     5 * Copyright (C) 2004, 2005, 2006, 2007, 2016 Apple Inc. All rights reserved.
    66 *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
    77 *
     
    565565}
    566566
    567 bool HTMLFormControlElement::isDefaultButtonForForm() const
    568 {
    569     return isSuccessfulSubmitButton() && form() && form()->defaultButton() == this;
    570 }
    571 
    572567#if ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
    573568
  • trunk/Source/WebCore/html/HTMLFormControlElement.h

    r197726 r202245  
    33 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
    44 *           (C) 2000 Dirk Mueller (mueller@kde.org)
    5  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
     5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2016 Apple Inc. All rights reserved.
    66 *
    77 * This library is free software; you can redistribute it and/or
     
    7373
    7474    bool isDisabledFormControl() const override;
    75     bool isDefaultButtonForForm() const override;
    7675
    7776    bool isFocusable() const override;
  • trunk/Source/WebCore/html/HTMLFormElement.cpp

    r202242 r202245  
    8989        document().unregisterForDocumentSuspensionCallbacks(this);
    9090
     91    m_defaultButton = nullptr;
    9192    for (auto& associatedElement : m_associatedElements)
    9293        associatedElement->formWillBeDestroyed();
     
    594595{
    595596    m_associatedElements.insert(formElementIndex(e), e);
     597
     598    if (is<HTMLFormControlElement>(e)) {
     599        HTMLFormControlElement& control = downcast<HTMLFormControlElement>(*e);
     600        if (control.isSuccessfulSubmitButton()) {
     601            if (!m_defaultButton)
     602                control.setNeedsStyleRecalc();
     603            else
     604                resetDefaultButton();
     605        }
     606    }
    596607}
    597608
     
    606617    removeFromPastNamesMap(e);
    607618    m_associatedElements.remove(index);
     619
     620    if (e == m_defaultButton)
     621        resetDefaultButton();
    608622}
    609623
     
    704718HTMLFormControlElement* HTMLFormElement::defaultButton() const
    705719{
    706     for (auto& associatedElement : m_associatedElements) {
    707         if (!is<HTMLFormControlElement>(*associatedElement))
    708             continue;
    709         HTMLFormControlElement& control = downcast<HTMLFormControlElement>(*associatedElement);
    710         if (control.isSuccessfulSubmitButton())
    711             return &control;
    712     }
    713 
    714     return nullptr;
     720    if (!m_defaultButton) {
     721        for (auto& associatedElement : m_associatedElements) {
     722            if (!is<HTMLFormControlElement>(*associatedElement))
     723                continue;
     724            HTMLFormControlElement& control = downcast<HTMLFormControlElement>(*associatedElement);
     725            if (control.isSuccessfulSubmitButton()) {
     726                m_defaultButton = &control;
     727                break;
     728            }
     729        }
     730    }
     731    return m_defaultButton;
     732}
     733
     734void HTMLFormElement::resetDefaultButton()
     735{
     736    if (!m_defaultButton) {
     737        // Computing the default button is not cheap, we don't want to do it unless needed.
     738        // If there was no default button set, the only style to invalidate is the element
     739        // being added to the form. This is done explicitely in registerFormElement().
     740        return;
     741    }
     742
     743    HTMLFormControlElement* oldDefault = m_defaultButton;
     744    m_defaultButton = nullptr;
     745    defaultButton();
     746    if (m_defaultButton != oldDefault) {
     747        if (oldDefault)
     748            oldDefault->setNeedsStyleRecalc();
     749        if (m_defaultButton)
     750            m_defaultButton->setNeedsStyleRecalc();
     751    }
    715752}
    716753
  • trunk/Source/WebCore/html/HTMLFormElement.h

    r201659 r202245  
    117117
    118118    HTMLFormControlElement* defaultButton() const;
     119    void resetDefaultButton();
    119120
    120121    bool checkValidity();
     
    187188
    188189    RadioButtonGroups m_radioButtonGroups;
     190    mutable HTMLFormControlElement* m_defaultButton { nullptr };
    189191
    190192    unsigned m_associatedElementsBeforeIndex;
  • trunk/Source/WebCore/html/HTMLInputElement.cpp

    r202243 r202245  
    466466    bool neededSuspensionCallback = needsSuspensionCallback();
    467467    bool didRespectHeightAndWidth = m_inputType->shouldRespectHeightAndWidthAttributes();
     468    bool wasSuccessfulSubmitButtonCandidate = m_inputType->canBeSuccessfulSubmitButton();
    468469
    469470    m_inputType->destroyShadowSubtree();
     
    507508            attributeChanged(alignAttr, nullAtom, align->value());
    508509    }
     510
     511    if (form() && wasSuccessfulSubmitButtonCandidate != m_inputType->canBeSuccessfulSubmitButton())
     512        form()->resetDefaultButton();
    509513
    510514    runPostTypeUpdateTasks();
     
    678682        m_valueAttributeWasUpdatedAfterParsing = !m_parsingInProgress;
    679683    } else if (name == checkedAttr) {
     684        if (m_inputType->isCheckable())
     685            setNeedsStyleRecalc();
     686
    680687        // Another radio button in the same group might be checked by state
    681688        // restore. We shouldn't call setChecked() even if this has the checked
     
    817824}
    818825
     826bool HTMLInputElement::matchesDefaultPseudoClass() const
     827{
     828    ASSERT(m_inputType);
     829    if (m_inputType->canBeSuccessfulSubmitButton())
     830        return !isDisabledFormControl() && form() && form()->defaultButton() == this;
     831    return m_inputType->isCheckable() && fastHasAttribute(checkedAttr);
     832}
     833
    819834bool HTMLInputElement::isActivatedSubmit() const
    820835{
  • trunk/Source/WebCore/html/HTMLInputElement.h

    r202197 r202245  
    381381
    382382    bool isSuccessfulSubmitButton() const final;
     383    bool matchesDefaultPseudoClass() const final;
    383384
    384385    void reset() final;
  • trunk/Source/WebCore/html/HTMLOptionElement.cpp

    r200895 r202245  
    44 *           (C) 2001 Dirk Mueller (mueller@kde.org)
    55 *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
    6  * Copyright (C) 2004, 2005, 2006, 2010 Apple Inc. All rights reserved.
     6 * Copyright (C) 2004, 2005, 2006, 2010, 2016 Apple Inc. All rights reserved.
    77 * Copyright (C) 2010 Google Inc. All rights reserved.
    88 * Copyright (C) 2011 Motorola Mobility, Inc.  All rights reserved.
     
    9797}
    9898
     99bool HTMLOptionElement::matchesDefaultPseudoClass() const
     100{
     101    return fastHasAttribute(selectedAttr);
     102}
     103
    99104String HTMLOptionElement::text() const
    100105{
     
    175180        }
    176181    } else if (name == selectedAttr) {
     182        setNeedsStyleRecalc();
     183
    177184        // FIXME: This doesn't match what the HTML specification says.
    178185        // The specification implies that removing the selected attribute or
  • trunk/Source/WebCore/html/HTMLOptionElement.h

    r197563 r202245  
    33 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
    44 *           (C) 2000 Dirk Mueller (mueller@kde.org)
    5  * Copyright (C) 2004, 2005, 2006, 2010, 2011 Apple Inc. All rights reserved.
     5 * Copyright (C) 2004, 2005, 2006, 2010, 2011, 2016 Apple Inc. All rights reserved.
    66 * Copyright (C) 2010 Google Inc. All rights reserved.
    77 *
     
    7272    bool isFocusable() const override;
    7373    bool rendererIsNeeded(const RenderStyle&) override { return false; }
     74    bool matchesDefaultPseudoClass() const override;
    7475
    7576    void parseAttribute(const QualifiedName&, const AtomicString&) override;
  • trunk/Source/WebCore/style/StyleSharingResolver.cpp

    r202197 r202245  
    186186        return false;
    187187
    188     if (formElement.isDefaultButtonForForm() != element.isDefaultButtonForForm())
    189         return false;
    190 
    191188    if (formElement.isInRange() != element.isInRange())
    192189        return false;
     
    283280
    284281    if (candidateElement.matchesIndeterminatePseudoClass() != element.matchesIndeterminatePseudoClass())
     282        return false;
     283
     284    if (candidateElement.matchesDefaultPseudoClass() != element.matchesDefaultPseudoClass())
    285285        return false;
    286286
Note: See TracChangeset for help on using the changeset viewer.