1/* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#include "SearchInputType.h" 33 34#include "HTMLInputElement.h" 35#include "HTMLNames.h" 36#include "InputTypeNames.h" 37#include "KeyboardEvent.h" 38#include "RenderSearchField.h" 39#include "ShadowRoot.h" 40#include "TextControlInnerElements.h" 41 42namespace WebCore { 43 44using namespace HTMLNames; 45 46SearchInputType::SearchInputType(HTMLInputElement& element) 47 : BaseTextInputType(element) 48 , m_resultsButton(0) 49 , m_cancelButton(0) 50 , m_searchEventTimer(this, &SearchInputType::searchEventTimerFired) 51{ 52} 53 54void SearchInputType::addSearchResult() 55{ 56#if !PLATFORM(IOS) 57 if (RenderObject* renderer = element().renderer()) 58 toRenderSearchField(renderer)->addSearchResult(); 59#endif 60} 61 62RenderPtr<RenderElement> SearchInputType::createInputRenderer(PassRef<RenderStyle> style) 63{ 64 return createRenderer<RenderSearchField>(element(), WTF::move(style)); 65} 66 67const AtomicString& SearchInputType::formControlType() const 68{ 69 return InputTypeNames::search(); 70} 71 72bool SearchInputType::shouldRespectSpeechAttribute() 73{ 74 return true; 75} 76 77bool SearchInputType::isSearchField() const 78{ 79 return true; 80} 81 82bool SearchInputType::needsContainer() const 83{ 84 return true; 85} 86 87void SearchInputType::createShadowSubtree() 88{ 89 ASSERT(!m_resultsButton); 90 ASSERT(!m_cancelButton); 91 92 TextFieldInputType::createShadowSubtree(); 93 HTMLElement* container = containerElement(); 94 HTMLElement* textWrapper = innerBlockElement(); 95 ASSERT(container); 96 ASSERT(textWrapper); 97 98 RefPtr<SearchFieldResultsButtonElement> resultsButton = SearchFieldResultsButtonElement::create(element().document()); 99 m_resultsButton = resultsButton.get(); 100 container->insertBefore(m_resultsButton, textWrapper, IGNORE_EXCEPTION); 101 102 RefPtr<SearchFieldCancelButtonElement> cancelButton = SearchFieldCancelButtonElement::create(element().document()); 103 m_cancelButton = cancelButton.get(); 104 container->insertBefore(m_cancelButton, textWrapper->nextSibling(), IGNORE_EXCEPTION); 105} 106 107HTMLElement* SearchInputType::resultsButtonElement() const 108{ 109 return m_resultsButton; 110} 111 112HTMLElement* SearchInputType::cancelButtonElement() const 113{ 114 return m_cancelButton; 115} 116 117void SearchInputType::handleKeydownEvent(KeyboardEvent* event) 118{ 119 if (element().isDisabledOrReadOnly()) { 120 TextFieldInputType::handleKeydownEvent(event); 121 return; 122 } 123 124 const String& key = event->keyIdentifier(); 125 if (key == "U+001B") { 126 Ref<HTMLInputElement> input(this->element()); 127 input->setValueForUser(""); 128 input->onSearch(); 129 event->setDefaultHandled(); 130 return; 131 } 132 TextFieldInputType::handleKeydownEvent(event); 133} 134 135void SearchInputType::destroyShadowSubtree() 136{ 137 TextFieldInputType::destroyShadowSubtree(); 138 m_resultsButton = 0; 139 m_cancelButton = 0; 140} 141 142void SearchInputType::startSearchEventTimer() 143{ 144 ASSERT(element().renderer()); 145 unsigned length = element().innerTextValue().length(); 146 147 if (!length) { 148 stopSearchEventTimer(); 149 element().onSearch(); 150 return; 151 } 152 153 // After typing the first key, we wait 0.5 seconds. 154 // After the second key, 0.4 seconds, then 0.3, then 0.2 from then on. 155 m_searchEventTimer.startOneShot(std::max(0.2, 0.6 - 0.1 * length)); 156} 157 158void SearchInputType::stopSearchEventTimer() 159{ 160 m_searchEventTimer.stop(); 161} 162 163void SearchInputType::searchEventTimerFired(Timer<SearchInputType>*) 164{ 165 element().onSearch(); 166} 167 168bool SearchInputType::searchEventsShouldBeDispatched() const 169{ 170 return element().hasAttribute(incrementalAttr); 171} 172 173void SearchInputType::didSetValueByUserEdit(ValueChangeState state) 174{ 175 if (m_cancelButton) 176 toRenderSearchField(element().renderer())->updateCancelButtonVisibility(); 177 178 // If the incremental attribute is set, then dispatch the search event 179 if (searchEventsShouldBeDispatched()) 180 startSearchEventTimer(); 181 182 TextFieldInputType::didSetValueByUserEdit(state); 183} 184 185bool SearchInputType::sizeShouldIncludeDecoration(int, int& preferredSize) const 186{ 187 preferredSize = element().size(); 188 return true; 189} 190 191float SearchInputType::decorationWidth() const 192{ 193 float width = 0; 194 if (m_resultsButton) 195 width += m_resultsButton->computedStyle()->logicalWidth().value(); 196 if (m_cancelButton) 197 width += m_cancelButton->computedStyle()->logicalWidth().value(); 198 return width; 199} 200 201} // namespace WebCore 202