Home | History | Annotate | Download | only in shadow
      1 /*
      2  * Copyright (C) 2006, 2008, 2010 Apple Inc. All rights reserved.
      3  * Copyright (C) 2010 Google Inc. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 #include "core/html/shadow/TextControlInnerElements.h"
     29 
     30 #include "core/HTMLNames.h"
     31 #include "core/dom/Document.h"
     32 #include "core/dom/NodeRenderStyle.h"
     33 #include "core/events/MouseEvent.h"
     34 #include "core/events/TextEvent.h"
     35 #include "core/events/TextEventInputType.h"
     36 #include "core/frame/LocalFrame.h"
     37 #include "core/html/HTMLInputElement.h"
     38 #include "core/html/shadow/ShadowElementNames.h"
     39 #include "core/page/EventHandler.h"
     40 #include "core/rendering/RenderTextControlSingleLine.h"
     41 #include "core/rendering/RenderView.h"
     42 #include "platform/UserGestureIndicator.h"
     43 
     44 namespace blink {
     45 
     46 using namespace HTMLNames;
     47 
     48 TextControlInnerContainer::TextControlInnerContainer(Document& document)
     49     : HTMLDivElement(document)
     50 {
     51 }
     52 
     53 PassRefPtrWillBeRawPtr<TextControlInnerContainer> TextControlInnerContainer::create(Document& document)
     54 {
     55     RefPtrWillBeRawPtr<TextControlInnerContainer> element = adoptRefWillBeNoop(new TextControlInnerContainer(document));
     56     element->setAttribute(idAttr, ShadowElementNames::textFieldContainer());
     57     return element.release();
     58 }
     59 
     60 RenderObject* TextControlInnerContainer::createRenderer(RenderStyle*)
     61 {
     62     return new RenderTextControlInnerContainer(this);
     63 }
     64 
     65 // ---------------------------
     66 
     67 EditingViewPortElement::EditingViewPortElement(Document& document)
     68     : HTMLDivElement(document)
     69 {
     70     setHasCustomStyleCallbacks();
     71 }
     72 
     73 PassRefPtrWillBeRawPtr<EditingViewPortElement> EditingViewPortElement::create(Document& document)
     74 {
     75     RefPtrWillBeRawPtr<EditingViewPortElement> element = adoptRefWillBeNoop(new EditingViewPortElement(document));
     76     element->setAttribute(idAttr, ShadowElementNames::editingViewPort());
     77     return element.release();
     78 }
     79 
     80 PassRefPtr<RenderStyle> EditingViewPortElement::customStyleForRenderer()
     81 {
     82     // FXIME: Move these styles to html.css.
     83 
     84     RefPtr<RenderStyle> style = RenderStyle::create();
     85     style->inheritFrom(shadowHost()->renderStyle());
     86 
     87     style->setFlexGrow(1);
     88     style->setDisplay(BLOCK);
     89     style->setDirection(LTR);
     90 
     91     // We don't want the shadow dom to be editable, so we set this block to
     92     // read-only in case the input itself is editable.
     93     style->setUserModify(READ_ONLY);
     94     style->setUnique();
     95 
     96     return style.release();
     97 }
     98 
     99 // ---------------------------
    100 
    101 inline TextControlInnerEditorElement::TextControlInnerEditorElement(Document& document)
    102     : HTMLDivElement(document)
    103 {
    104     setHasCustomStyleCallbacks();
    105 }
    106 
    107 PassRefPtrWillBeRawPtr<TextControlInnerEditorElement> TextControlInnerEditorElement::create(Document& document)
    108 {
    109     RefPtrWillBeRawPtr<TextControlInnerEditorElement> element = adoptRefWillBeNoop(new TextControlInnerEditorElement(document));
    110     element->setAttribute(idAttr, ShadowElementNames::innerEditor());
    111     return element.release();
    112 }
    113 
    114 void TextControlInnerEditorElement::defaultEventHandler(Event* event)
    115 {
    116     // FIXME: In the future, we should add a way to have default event listeners.
    117     // Then we would add one to the text field's inner div, and we wouldn't need this subclass.
    118     // Or possibly we could just use a normal event listener.
    119     if (event->isBeforeTextInsertedEvent() || event->type() == EventTypeNames::webkitEditableContentChanged) {
    120         Element* shadowAncestor = shadowHost();
    121         // A TextControlInnerTextElement can have no host if its been detached,
    122         // but kept alive by an EditCommand. In this case, an undo/redo can
    123         // cause events to be sent to the TextControlInnerTextElement. To
    124         // prevent an infinite loop, we must check for this case before sending
    125         // the event up the chain.
    126         if (shadowAncestor)
    127             shadowAncestor->defaultEventHandler(event);
    128     }
    129     if (!event->defaultHandled())
    130         HTMLDivElement::defaultEventHandler(event);
    131 }
    132 
    133 RenderObject* TextControlInnerEditorElement::createRenderer(RenderStyle*)
    134 {
    135     return new RenderTextControlInnerBlock(this);
    136 }
    137 
    138 PassRefPtr<RenderStyle> TextControlInnerEditorElement::customStyleForRenderer()
    139 {
    140     RenderObject* parentRenderer = shadowHost()->renderer();
    141     if (!parentRenderer || !parentRenderer->isTextControl())
    142         return originalStyleForRenderer();
    143     RenderTextControl* textControlRenderer = toRenderTextControl(parentRenderer);
    144     return textControlRenderer->createInnerEditorStyle(textControlRenderer->style());
    145 }
    146 
    147 // ----------------------------
    148 
    149 inline SearchFieldDecorationElement::SearchFieldDecorationElement(Document& document)
    150     : HTMLDivElement(document)
    151 {
    152 }
    153 
    154 PassRefPtrWillBeRawPtr<SearchFieldDecorationElement> SearchFieldDecorationElement::create(Document& document)
    155 {
    156     RefPtrWillBeRawPtr<SearchFieldDecorationElement> element = adoptRefWillBeNoop(new SearchFieldDecorationElement(document));
    157     element->setAttribute(idAttr, ShadowElementNames::searchDecoration());
    158     return element.release();
    159 }
    160 
    161 const AtomicString& SearchFieldDecorationElement::shadowPseudoId() const
    162 {
    163     DEFINE_STATIC_LOCAL(AtomicString, resultsDecorationId, ("-webkit-search-results-decoration", AtomicString::ConstructFromLiteral));
    164     DEFINE_STATIC_LOCAL(AtomicString, decorationId, ("-webkit-search-decoration", AtomicString::ConstructFromLiteral));
    165     Element* host = shadowHost();
    166     if (!host)
    167         return resultsDecorationId;
    168     if (isHTMLInputElement(*host)) {
    169         if (toHTMLInputElement(host)->maxResults() < 0)
    170             return decorationId;
    171         return resultsDecorationId;
    172     }
    173     return resultsDecorationId;
    174 }
    175 
    176 void SearchFieldDecorationElement::defaultEventHandler(Event* event)
    177 {
    178     // On mousedown, focus the search field
    179     HTMLInputElement* input = toHTMLInputElement(shadowHost());
    180     if (input && event->type() == EventTypeNames::mousedown && event->isMouseEvent() && toMouseEvent(event)->button() == LeftButton) {
    181         input->focus();
    182         input->select();
    183         event->setDefaultHandled();
    184     }
    185 
    186     if (!event->defaultHandled())
    187         HTMLDivElement::defaultEventHandler(event);
    188 }
    189 
    190 bool SearchFieldDecorationElement::willRespondToMouseClickEvents()
    191 {
    192     return true;
    193 }
    194 
    195 // ----------------------------
    196 
    197 inline SearchFieldCancelButtonElement::SearchFieldCancelButtonElement(Document& document)
    198     : HTMLDivElement(document)
    199     , m_capturing(false)
    200 {
    201 }
    202 
    203 PassRefPtrWillBeRawPtr<SearchFieldCancelButtonElement> SearchFieldCancelButtonElement::create(Document& document)
    204 {
    205     RefPtrWillBeRawPtr<SearchFieldCancelButtonElement> element = adoptRefWillBeNoop(new SearchFieldCancelButtonElement(document));
    206     element->setShadowPseudoId(AtomicString("-webkit-search-cancel-button", AtomicString::ConstructFromLiteral));
    207     element->setAttribute(idAttr, ShadowElementNames::clearButton());
    208     return element.release();
    209 }
    210 
    211 void SearchFieldCancelButtonElement::detach(const AttachContext& context)
    212 {
    213     if (m_capturing) {
    214         if (LocalFrame* frame = document().frame())
    215             frame->eventHandler().setCapturingMouseEventsNode(nullptr);
    216     }
    217     HTMLDivElement::detach(context);
    218 }
    219 
    220 
    221 void SearchFieldCancelButtonElement::defaultEventHandler(Event* event)
    222 {
    223     // If the element is visible, on mouseup, clear the value, and set selection
    224     RefPtrWillBeRawPtr<HTMLInputElement> input(toHTMLInputElement(shadowHost()));
    225     if (!input || input->isDisabledOrReadOnly()) {
    226         if (!event->defaultHandled())
    227             HTMLDivElement::defaultEventHandler(event);
    228         return;
    229     }
    230 
    231 
    232     if (event->type() == EventTypeNames::click && event->isMouseEvent() && toMouseEvent(event)->button() == LeftButton) {
    233         input->setValueForUser("");
    234         input->setAutofilled(false);
    235         input->onSearch();
    236         event->setDefaultHandled();
    237     }
    238 
    239     if (!event->defaultHandled())
    240         HTMLDivElement::defaultEventHandler(event);
    241 }
    242 
    243 bool SearchFieldCancelButtonElement::willRespondToMouseClickEvents()
    244 {
    245     const HTMLInputElement* input = toHTMLInputElement(shadowHost());
    246     if (input && !input->isDisabledOrReadOnly())
    247         return true;
    248 
    249     return HTMLDivElement::willRespondToMouseClickEvents();
    250 }
    251 
    252 }
    253