📄 inputelement.cpp
字号:
/* * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */#include "config.h"#include "InputElement.h"#include "BeforeTextInsertedEvent.h"#include "ChromeClient.h"#include "Document.h"#include "Event.h"#include "EventNames.h"#include "FormControlElement.h"#include "Frame.h"#include "HTMLInputElement.h"#include "HTMLNames.h"#include "Page.h"#include "RenderTextControlSingleLine.h"#include "SelectionController.h"#include "TextIterator.h"#include "TextBreakIterator.h"#if ENABLE(WML)#include "WMLInputElement.h"#include "WMLNames.h"#endifnamespace WebCore {using namespace HTMLNames;// FIXME: According to HTML4, the length attribute's value can be arbitrarily// large. However, due to http://bugs.webkit.org/show_bugs.cgi?id=14536 things// get rather sluggish when a text field has a larger number of characters than// this, even when just clicking in the text field.const int InputElement::s_maximumLength = 524288;const int InputElement::s_defaultSize = 20;void InputElement::dispatchFocusEvent(InputElementData& data, Document* document){ if (!data.inputElement()->isTextField()) return; updatePlaceholderVisibility(data, document); if (data.inputElement()->isPasswordField() && document->frame()) document->setUseSecureKeyboardEntryWhenActive(true);}void InputElement::dispatchBlurEvent(InputElementData& data, Document* document){ if (!data.inputElement()->isTextField()) return; Frame* frame = document->frame(); if (!frame) return; updatePlaceholderVisibility(data, document); if (data.inputElement()->isPasswordField()) document->setUseSecureKeyboardEntryWhenActive(false); frame->textFieldDidEndEditing(data.element());}void InputElement::updatePlaceholderVisibility(InputElementData& data, Document* document, bool placeholderValueChanged){ ASSERT(data.inputElement()->isTextField()); bool oldPlaceholderShouldBeVisible = data.placeholderShouldBeVisible(); Element* element = data.element(); data.setPlaceholderShouldBeVisible(data.inputElement()->value().isEmpty() && document->focusedNode() != element && !data.inputElement()->placeholderValue().isEmpty()); if ((oldPlaceholderShouldBeVisible != data.placeholderShouldBeVisible() || placeholderValueChanged) && element->renderer()) static_cast<RenderTextControlSingleLine*>(element->renderer())->updatePlaceholderVisibility();}void InputElement::updateFocusAppearance(InputElementData& data, Document* document, bool restorePreviousSelection){ ASSERT(data.inputElement()->isTextField()); if (!restorePreviousSelection || data.cachedSelectionStart() == -1) data.inputElement()->select(); else // Restore the cached selection. updateSelectionRange(data, data.cachedSelectionStart(), data.cachedSelectionEnd()); if (document && document->frame()) document->frame()->revealSelection();}void InputElement::updateSelectionRange(InputElementData& data, int start, int end){ if (!data.inputElement()->isTextField()) return; if (RenderTextControl* renderer = toRenderTextControl(data.element()->renderer())) renderer->setSelectionRange(start, end);}void InputElement::aboutToUnload(InputElementData& data, Document* document){ if (!data.inputElement()->isTextField() || !data.element()->focused() || !document->frame()) return; document->frame()->textFieldDidEndEditing(data.element());}void InputElement::setValueFromRenderer(InputElementData& data, Document* document, const String& value){ // Renderer and our event handler are responsible for constraining values. ASSERT(value == data.inputElement()->constrainValue(value) || data.inputElement()->constrainValue(value).isEmpty()); if (data.inputElement()->isTextField()) updatePlaceholderVisibility(data, document); // Workaround for bug where trailing \n is included in the result of textContent. // The assert macro above may also be simplified to: value == constrainValue(value) // http://bugs.webkit.org/show_bug.cgi?id=9661 if (value == "\n") data.setValue(""); else data.setValue(value); Element* element = data.element(); FormControlElement* formControlElement = toFormControlElement(element); ASSERT(formControlElement); formControlElement->setValueMatchesRenderer(); // Fire the "input" DOM event element->dispatchEventForType(eventNames().inputEvent, true, false); notifyFormStateChanged(data, document);}static int numCharactersInGraphemeClusters(StringImpl* s, int numGraphemeClusters){ if (!s) return 0; TextBreakIterator* it = characterBreakIterator(s->characters(), s->length()); if (!it) return 0; for (int i = 0; i < numGraphemeClusters; ++i) { if (textBreakNext(it) == TextBreakDone) return s->length(); } return textBreakCurrent(it);}String InputElement::constrainValue(const InputElementData& data, const String& proposedValue, int maxLength){ String string = proposedValue; if (!data.inputElement()->isTextField()) return string; string.replace("\r\n", " "); string.replace('\r', ' '); string.replace('\n', ' '); StringImpl* s = string.impl(); int newLength = numCharactersInGraphemeClusters(s, maxLength); for (int i = 0; i < newLength; ++i) { const UChar& current = (*s)[i]; if (current < ' ' && current != '\t') { newLength = i; break; } } if (newLength < static_cast<int>(string.length())) return string.left(newLength); return string;}static int numGraphemeClusters(StringImpl* s){ if (!s) return 0; TextBreakIterator* it = characterBreakIterator(s->characters(), s->length()); if (!it) return 0; int num = 0; while (textBreakNext(it) != TextBreakDone) ++num; return num;}void InputElement::handleBeforeTextInsertedEvent(InputElementData& data, Document* document, Event* event){ ASSERT(event->isBeforeTextInsertedEvent()); // Make sure that the text to be inserted will not violate the maxLength. int oldLength = numGraphemeClusters(data.inputElement()->value().impl()); ASSERT(oldLength <= data.maxLength()); int selectionLength = numGraphemeClusters(plainText(document->frame()->selection()->selection().toNormalizedRange().get()).impl()); ASSERT(oldLength >= selectionLength); int maxNewLength = data.maxLength() - (oldLength - selectionLength); // Truncate the inserted text to avoid violating the maxLength and other constraints. BeforeTextInsertedEvent* textEvent = static_cast<BeforeTextInsertedEvent*>(event); textEvent->setText(constrainValue(data, textEvent->text(), maxNewLength));}void InputElement::parseSizeAttribute(InputElementData& data, MappedAttribute* attribute){ data.setSize(attribute->isNull() ? InputElement::s_defaultSize : attribute->value().toInt()); if (RenderObject* renderer = data.element()->renderer()) renderer->setNeedsLayoutAndPrefWidthsRecalc();}void InputElement::parseMaxLengthAttribute(InputElementData& data, MappedAttribute* attribute){ int maxLength = attribute->isNull() ? InputElement::s_maximumLength : attribute->value().toInt(); if (maxLength <= 0 || maxLength > InputElement::s_maximumLength) maxLength = InputElement::s_maximumLength; int oldMaxLength = data.maxLength(); data.setMaxLength(maxLength); if (oldMaxLength != maxLength) updateValueIfNeeded(data); data.element()->setChanged();}void InputElement::updateValueIfNeeded(InputElementData& data){ String oldValue = data.value(); String newValue = data.inputElement()->constrainValue(oldValue); if (newValue != oldValue) data.inputElement()->setValue(newValue);}void InputElement::notifyFormStateChanged(InputElementData& data, Document* document){ Frame* frame = document->frame(); if (!frame) return; if (Page* page = frame->page()) page->chrome()->client()->formStateDidChange(data.element());}// InputElementDataInputElementData::InputElementData(InputElement* inputElement, Element* element) : m_inputElement(inputElement) , m_element(element) , m_placeholderShouldBeVisible(false) , m_size(InputElement::s_defaultSize) , m_maxLength(InputElement::s_maximumLength) , m_cachedSelectionStart(-1) , m_cachedSelectionEnd(-1){ ASSERT(m_inputElement); ASSERT(m_element);}InputElementData::~InputElementData(){}const AtomicString& InputElementData::name() const{ return m_name.isNull() ? emptyAtom : m_name;}InputElement* toInputElement(Element* element){ if (element->isHTMLElement() && (element->hasTagName(inputTag) || element->hasTagName(isindexTag))) return static_cast<HTMLInputElement*>(element);#if ENABLE(WML) if (element->isWMLElement() && element->hasTagName(WMLNames::inputTag)) return static_cast<WMLInputElement*>(element);#endif return 0;}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -