| Index: Source/core/html/TextFieldInputType.cpp
|
| diff --git a/Source/core/html/TextFieldInputType.cpp b/Source/core/html/TextFieldInputType.cpp
|
| deleted file mode 100644
|
| index 65693bd25f7d9493f92aca42a9e097f91430facf..0000000000000000000000000000000000000000
|
| --- a/Source/core/html/TextFieldInputType.cpp
|
| +++ /dev/null
|
| @@ -1,491 +0,0 @@
|
| -/*
|
| - * Copyright (C) 2010 Google Inc. All rights reserved.
|
| - * Copyright (C) 2011 Apple Inc. All rights reserved.
|
| - *
|
| - * Redistribution and use in source and binary forms, with or without
|
| - * modification, are permitted provided that the following conditions are
|
| - * met:
|
| - *
|
| - * * Redistributions of source code must retain the above copyright
|
| - * notice, this list of conditions and the following disclaimer.
|
| - * * Redistributions in binary form must reproduce the above
|
| - * copyright notice, this list of conditions and the following disclaimer
|
| - * in the documentation and/or other materials provided with the
|
| - * distribution.
|
| - * * Neither the name of Google Inc. nor the names of its
|
| - * contributors may be used to endorse or promote products derived from
|
| - * this software without specific prior written permission.
|
| - *
|
| - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| - */
|
| -
|
| -#include "config.h"
|
| -#include "core/html/TextFieldInputType.h"
|
| -
|
| -#include "HTMLNames.h"
|
| -#include "bindings/v8/ExceptionStatePlaceholder.h"
|
| -#include "core/dom/BeforeTextInsertedEvent.h"
|
| -#include "core/dom/KeyboardEvent.h"
|
| -#include "core/dom/NodeRenderStyle.h"
|
| -#include "core/dom/TextEvent.h"
|
| -#include "core/dom/shadow/ShadowRoot.h"
|
| -#include "core/editing/Editor.h"
|
| -#include "core/editing/FrameSelection.h"
|
| -#include "core/editing/TextIterator.h"
|
| -#include "core/html/FormDataList.h"
|
| -#include "core/html/HTMLInputElement.h"
|
| -#include "core/html/shadow/ShadowElementNames.h"
|
| -#include "core/html/shadow/TextControlInnerElements.h"
|
| -#include "core/page/Frame.h"
|
| -#include "core/page/Page.h"
|
| -#include "core/page/Settings.h"
|
| -#include "core/rendering/RenderLayer.h"
|
| -#include "core/rendering/RenderTextControlSingleLine.h"
|
| -#include "core/rendering/RenderTheme.h"
|
| -#include "wtf/text/WTFString.h"
|
| -
|
| -namespace WebCore {
|
| -
|
| -using namespace HTMLNames;
|
| -
|
| -TextFieldInputType::TextFieldInputType(HTMLInputElement* element)
|
| - : InputType(element)
|
| -{
|
| -}
|
| -
|
| -TextFieldInputType::~TextFieldInputType()
|
| -{
|
| - if (SpinButtonElement* spinButton = spinButtonElement())
|
| - spinButton->removeSpinButtonOwner();
|
| -}
|
| -
|
| -SpinButtonElement* TextFieldInputType::spinButtonElement() const
|
| -{
|
| - return toSpinButtonElement(element()->userAgentShadowRoot()->getElementById(ShadowElementNames::spinButton()));
|
| -}
|
| -
|
| -bool TextFieldInputType::shouldShowFocusRingOnMouseFocus() const
|
| -{
|
| - return true;
|
| -}
|
| -
|
| -bool TextFieldInputType::isTextField() const
|
| -{
|
| - return true;
|
| -}
|
| -
|
| -static inline bool shouldIgnoreRequiredAttribute(const HTMLInputElement& input)
|
| -{
|
| - if (!input.document().settings() || !input.document().settings()->needsSiteSpecificQuirks())
|
| - return false;
|
| - if (!equalIgnoringCase(input.document().url().host(), "egov.uscis.gov"))
|
| - return false;
|
| - return input.fastGetAttribute(requiredAttr) == "no";
|
| -}
|
| -
|
| -bool TextFieldInputType::valueMissing(const String& value) const
|
| -{
|
| - return !shouldIgnoreRequiredAttribute(*element()) && element()->isRequired() && value.isEmpty();
|
| -}
|
| -
|
| -bool TextFieldInputType::canSetSuggestedValue()
|
| -{
|
| - return true;
|
| -}
|
| -
|
| -void TextFieldInputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
|
| -{
|
| - // Grab this input element to keep reference even if JS event handler
|
| - // changes input type.
|
| - RefPtr<HTMLInputElement> input(element());
|
| -
|
| - // We don't ask InputType::setValue to dispatch events because
|
| - // TextFieldInputType dispatches events different way from InputType.
|
| - InputType::setValue(sanitizedValue, valueChanged, DispatchNoEvent);
|
| -
|
| - if (valueChanged)
|
| - updateInnerTextValue();
|
| -
|
| - unsigned max = visibleValue().length();
|
| - if (input->focused())
|
| - input->setSelectionRange(max, max);
|
| - else
|
| - input->cacheSelectionInResponseToSetValue(max);
|
| -
|
| - if (!valueChanged)
|
| - return;
|
| -
|
| - switch (eventBehavior) {
|
| - case DispatchChangeEvent:
|
| - // If the user is still editing this field, dispatch an input event rather than a change event.
|
| - // The change event will be dispatched when editing finishes.
|
| - if (input->focused())
|
| - input->dispatchFormControlInputEvent();
|
| - else
|
| - input->dispatchFormControlChangeEvent();
|
| - break;
|
| -
|
| - case DispatchInputAndChangeEvent: {
|
| - input->dispatchFormControlInputEvent();
|
| - input->dispatchFormControlChangeEvent();
|
| - break;
|
| - }
|
| -
|
| - case DispatchNoEvent:
|
| - break;
|
| - }
|
| -
|
| - if (!input->focused())
|
| - input->setTextAsOfLastFormControlChangeEvent(sanitizedValue);
|
| -}
|
| -
|
| -void TextFieldInputType::handleKeydownEvent(KeyboardEvent* event)
|
| -{
|
| - if (!element()->focused())
|
| - return;
|
| - Frame* frame = element()->document().frame();
|
| - if (!frame || !frame->editor().doTextFieldCommandFromEvent(element(), event))
|
| - return;
|
| - event->setDefaultHandled();
|
| -}
|
| -
|
| -void TextFieldInputType::handleKeydownEventForSpinButton(KeyboardEvent* event)
|
| -{
|
| - if (element()->isDisabledOrReadOnly())
|
| - return;
|
| - const String& key = event->keyIdentifier();
|
| - if (key == "Up")
|
| - spinButtonStepUp();
|
| - else if (key == "Down")
|
| - spinButtonStepDown();
|
| - else
|
| - return;
|
| - event->setDefaultHandled();
|
| -}
|
| -
|
| -void TextFieldInputType::forwardEvent(Event* event)
|
| -{
|
| - if (SpinButtonElement* spinButton = spinButtonElement()) {
|
| - spinButton->forwardEvent(event);
|
| - if (event->defaultHandled())
|
| - return;
|
| - }
|
| -
|
| - if (element()->renderer() && (event->isMouseEvent() || event->isDragEvent() || event->hasInterface(eventNames().interfaceForWheelEvent) || event->type() == eventNames().blurEvent || event->type() == eventNames().focusEvent)) {
|
| - RenderTextControlSingleLine* renderTextControl = toRenderTextControlSingleLine(element()->renderer());
|
| - if (event->type() == eventNames().blurEvent) {
|
| - if (RenderBox* innerTextRenderer = innerTextElement()->renderBox()) {
|
| - if (RenderLayer* innerLayer = innerTextRenderer->layer()) {
|
| - IntSize scrollOffset(!renderTextControl->style()->isLeftToRightDirection() ? innerLayer->scrollWidth() : 0, 0);
|
| - innerLayer->scrollToOffset(scrollOffset, ScrollOffsetClamped);
|
| - }
|
| - }
|
| -
|
| - renderTextControl->capsLockStateMayHaveChanged();
|
| - } else if (event->type() == eventNames().focusEvent)
|
| - renderTextControl->capsLockStateMayHaveChanged();
|
| -
|
| - element()->forwardEvent(event);
|
| - }
|
| -}
|
| -
|
| -void TextFieldInputType::handleFocusEvent(Element* oldFocusedNode, FocusDirection focusDirection)
|
| -{
|
| - InputType::handleFocusEvent(oldFocusedNode, focusDirection);
|
| - element()->beginEditing();
|
| -}
|
| -
|
| -void TextFieldInputType::handleBlurEvent()
|
| -{
|
| - InputType::handleBlurEvent();
|
| - element()->endEditing();
|
| -}
|
| -
|
| -bool TextFieldInputType::shouldSubmitImplicitly(Event* event)
|
| -{
|
| - return (event->type() == eventNames().textInputEvent && event->hasInterface(eventNames().interfaceForTextEvent) && static_cast<TextEvent*>(event)->data() == "\n") || InputType::shouldSubmitImplicitly(event);
|
| -}
|
| -
|
| -RenderObject* TextFieldInputType::createRenderer(RenderStyle*) const
|
| -{
|
| - return new RenderTextControlSingleLine(element());
|
| -}
|
| -
|
| -bool TextFieldInputType::needsContainer() const
|
| -{
|
| -#if ENABLE(INPUT_SPEECH)
|
| - return element()->isSpeechEnabled();
|
| -#else
|
| - return false;
|
| -#endif
|
| -}
|
| -
|
| -bool TextFieldInputType::shouldHaveSpinButton() const
|
| -{
|
| - return RenderTheme::theme().shouldHaveSpinButton(element());
|
| -}
|
| -
|
| -void TextFieldInputType::createShadowSubtree()
|
| -{
|
| - ASSERT(element()->shadow());
|
| - ShadowRoot* shadowRoot = element()->userAgentShadowRoot();
|
| - ASSERT(!shadowRoot->hasChildNodes());
|
| -
|
| - Document& document = element()->document();
|
| - bool shouldHaveSpinButton = this->shouldHaveSpinButton();
|
| - bool createsContainer = shouldHaveSpinButton || needsContainer();
|
| -
|
| - m_innerText = TextControlInnerTextElement::create(document);
|
| - if (!createsContainer) {
|
| - shadowRoot->appendChild(m_innerText);
|
| - return;
|
| - }
|
| -
|
| - m_container = TextControlInnerContainer::create(document);
|
| - m_container->setPart(AtomicString("-webkit-textfield-decoration-container", AtomicString::ConstructFromLiteral));
|
| - shadowRoot->appendChild(m_container);
|
| -
|
| - RefPtr<EditingViewPortElement> editingViewPort = EditingViewPortElement::create(document);
|
| - editingViewPort->appendChild(m_innerText);
|
| - m_container->appendChild(editingViewPort.release());
|
| -
|
| -#if ENABLE(INPUT_SPEECH)
|
| - if (element()->isSpeechEnabled())
|
| - m_container->appendChild(InputFieldSpeechButtonElement::create(document));
|
| -#endif
|
| -
|
| - if (shouldHaveSpinButton)
|
| - m_container->appendChild(SpinButtonElement::create(document, *this));
|
| -}
|
| -
|
| -HTMLElement* TextFieldInputType::containerElement() const
|
| -{
|
| - return m_container.get();
|
| -}
|
| -
|
| -HTMLElement* TextFieldInputType::innerTextElement() const
|
| -{
|
| - ASSERT(m_innerText);
|
| - return m_innerText.get();
|
| -}
|
| -
|
| -void TextFieldInputType::destroyShadowSubtree()
|
| -{
|
| - InputType::destroyShadowSubtree();
|
| - m_innerText.clear();
|
| - if (SpinButtonElement* spinButton = spinButtonElement())
|
| - spinButton->removeSpinButtonOwner();
|
| - m_container.clear();
|
| -}
|
| -
|
| -void TextFieldInputType::attributeChanged()
|
| -{
|
| - // FIXME: Updating the inner text on any attribute update should
|
| - // be unnecessary. We should figure out what attributes affect.
|
| - updateInnerTextValue();
|
| -}
|
| -
|
| -void TextFieldInputType::disabledAttributeChanged()
|
| -{
|
| - if (SpinButtonElement* spinButton = spinButtonElement())
|
| - spinButton->releaseCapture();
|
| -}
|
| -
|
| -void TextFieldInputType::readonlyAttributeChanged()
|
| -{
|
| - if (SpinButtonElement* spinButton = spinButtonElement())
|
| - spinButton->releaseCapture();
|
| -}
|
| -
|
| -bool TextFieldInputType::supportsReadOnly() const
|
| -{
|
| - return true;
|
| -}
|
| -
|
| -bool TextFieldInputType::shouldUseInputMethod() const
|
| -{
|
| - return true;
|
| -}
|
| -
|
| -static bool isASCIILineBreak(UChar c)
|
| -{
|
| - return c == '\r' || c == '\n';
|
| -}
|
| -
|
| -static String limitLength(const String& string, unsigned maxLength)
|
| -{
|
| - unsigned newLength = std::min(maxLength, string.length());
|
| - // FIXME: We should not truncate the string at a control character. It's not
|
| - // compatible with IE and Firefox.
|
| - for (unsigned i = 0; i < newLength; ++i) {
|
| - const UChar current = string[i];
|
| - if (current < ' ' && current != '\t') {
|
| - newLength = i;
|
| - break;
|
| - }
|
| - }
|
| - if (newLength == string.length())
|
| - return string;
|
| - if (newLength > 0 && U16_IS_LEAD(string[newLength - 1]))
|
| - --newLength;
|
| - return string.left(newLength);
|
| -}
|
| -
|
| -String TextFieldInputType::sanitizeValue(const String& proposedValue) const
|
| -{
|
| - return limitLength(proposedValue.removeCharacters(isASCIILineBreak), HTMLInputElement::maximumLength);
|
| -}
|
| -
|
| -void TextFieldInputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* event)
|
| -{
|
| - // Make sure that the text to be inserted will not violate the maxLength.
|
| -
|
| - // We use HTMLInputElement::innerTextValue() instead of
|
| - // HTMLInputElement::value() because they can be mismatched by
|
| - // sanitizeValue() in HTMLInputElement::subtreeHasChanged() in some cases.
|
| - unsigned oldLength = element()->innerTextValue().length();
|
| -
|
| - // selectionLength represents the selection length of this text field to be
|
| - // removed by this insertion.
|
| - // If the text field has no focus, we don't need to take account of the
|
| - // selection length. The selection is the source of text drag-and-drop in
|
| - // that case, and nothing in the text field will be removed.
|
| - unsigned selectionLength = element()->focused() ? plainText(element()->document().frame()->selection().selection().toNormalizedRange().get()).length() : 0;
|
| - ASSERT(oldLength >= selectionLength);
|
| -
|
| - // Selected characters will be removed by the next text event.
|
| - unsigned baseLength = oldLength - selectionLength;
|
| - unsigned maxLength = static_cast<unsigned>(isTextType() ? element()->maxLength() : HTMLInputElement::maximumLength); // maxLength can never be negative.
|
| - unsigned appendableLength = maxLength > baseLength ? maxLength - baseLength : 0;
|
| -
|
| - // Truncate the inserted text to avoid violating the maxLength and other constraints.
|
| - String eventText = event->text();
|
| - unsigned textLength = eventText.length();
|
| - while (textLength > 0 && isASCIILineBreak(eventText[textLength - 1]))
|
| - textLength--;
|
| - eventText.truncate(textLength);
|
| - eventText.replace("\r\n", " ");
|
| - eventText.replace('\r', ' ');
|
| - eventText.replace('\n', ' ');
|
| -
|
| - event->setText(limitLength(eventText, appendableLength));
|
| -}
|
| -
|
| -bool TextFieldInputType::shouldRespectListAttribute()
|
| -{
|
| - return InputType::themeSupportsDataListUI(this);
|
| -}
|
| -
|
| -void TextFieldInputType::updatePlaceholderText()
|
| -{
|
| - if (!supportsPlaceholder())
|
| - return;
|
| - HTMLElement* placeholder = element()->placeholderElement();
|
| - String placeholderText = element()->strippedPlaceholder();
|
| - if (placeholderText.isEmpty()) {
|
| - if (placeholder)
|
| - placeholder->remove(ASSERT_NO_EXCEPTION);
|
| - return;
|
| - }
|
| - if (!placeholder) {
|
| - RefPtr<HTMLElement> newElement = HTMLDivElement::create(element()->document());
|
| - placeholder = newElement.get();
|
| - placeholder->setPart(AtomicString("-webkit-input-placeholder", AtomicString::ConstructFromLiteral));
|
| - placeholder->setAttribute(idAttr, ShadowElementNames::placeholder());
|
| - element()->userAgentShadowRoot()->insertBefore(placeholder, m_container ? m_container->nextSibling() : innerTextElement()->nextSibling());
|
| - }
|
| - placeholder->setTextContent(placeholderText, ASSERT_NO_EXCEPTION);
|
| -}
|
| -
|
| -bool TextFieldInputType::appendFormData(FormDataList& list, bool multipart) const
|
| -{
|
| - InputType::appendFormData(list, multipart);
|
| - const AtomicString& dirnameAttrValue = element()->fastGetAttribute(dirnameAttr);
|
| - if (!dirnameAttrValue.isNull())
|
| - list.appendData(dirnameAttrValue, element()->directionForFormData());
|
| - return true;
|
| -}
|
| -
|
| -String TextFieldInputType::convertFromVisibleValue(const String& visibleValue) const
|
| -{
|
| - return visibleValue;
|
| -}
|
| -
|
| -void TextFieldInputType::subtreeHasChanged()
|
| -{
|
| - ASSERT(element()->renderer());
|
| -
|
| - bool wasChanged = element()->wasChangedSinceLastFormControlChangeEvent();
|
| - element()->setChangedSinceLastFormControlChangeEvent(true);
|
| -
|
| - // We don't need to call sanitizeUserInputValue() function here because
|
| - // HTMLInputElement::handleBeforeTextInsertedEvent() has already called
|
| - // sanitizeUserInputValue().
|
| - // sanitizeValue() is needed because IME input doesn't dispatch BeforeTextInsertedEvent.
|
| - element()->setValueFromRenderer(sanitizeValue(convertFromVisibleValue(element()->innerTextValue())));
|
| - element()->updatePlaceholderVisibility(false);
|
| - // Recalc for :invalid change.
|
| - element()->setNeedsStyleRecalc();
|
| -
|
| - didSetValueByUserEdit(wasChanged ? ValueChangeStateChanged : ValueChangeStateNone);
|
| -}
|
| -
|
| -void TextFieldInputType::didSetValueByUserEdit(ValueChangeState state)
|
| -{
|
| - if (!element()->focused())
|
| - return;
|
| - if (Frame* frame = element()->document().frame())
|
| - frame->editor().textDidChangeInTextField(element());
|
| -}
|
| -
|
| -void TextFieldInputType::spinButtonStepDown()
|
| -{
|
| - stepUpFromRenderer(-1);
|
| -}
|
| -
|
| -void TextFieldInputType::spinButtonStepUp()
|
| -{
|
| - stepUpFromRenderer(1);
|
| -}
|
| -
|
| -void TextFieldInputType::updateInnerTextValue()
|
| -{
|
| - if (!element()->suggestedValue().isNull()) {
|
| - element()->setInnerTextValue(element()->suggestedValue());
|
| - element()->updatePlaceholderVisibility(false);
|
| - } else if (!element()->formControlValueMatchesRenderer()) {
|
| - // Update the renderer value if the formControlValueMatchesRenderer() flag is false.
|
| - // It protects an unacceptable renderer value from being overwritten with the DOM value.
|
| - element()->setInnerTextValue(visibleValue());
|
| - element()->updatePlaceholderVisibility(false);
|
| - }
|
| -}
|
| -
|
| -void TextFieldInputType::focusAndSelectSpinButtonOwner()
|
| -{
|
| - RefPtr<HTMLInputElement> input(element());
|
| - input->focus();
|
| - input->select();
|
| -}
|
| -
|
| -bool TextFieldInputType::shouldSpinButtonRespondToMouseEvents()
|
| -{
|
| - return !element()->isDisabledOrReadOnly();
|
| -}
|
| -
|
| -bool TextFieldInputType::shouldSpinButtonRespondToWheelEvents()
|
| -{
|
| - return shouldSpinButtonRespondToMouseEvents() && element()->focused();
|
| -}
|
| -
|
| -} // namespace WebCore
|
|
|