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