void HTMLTextAreaElement::handleBeforeTextInsertedEvent(
    BeforeTextInsertedEvent* event) const {
  DCHECK(event);
  DCHECK(layoutObject());
  int signedMaxLength = maxLength();
  if (signedMaxLength < 0)
    return;
  unsigned unsignedMaxLength = static_cast<unsigned>(signedMaxLength);

  const String& currentValue = innerEditorValue();
  unsigned currentLength = computeLengthForAPIValue(currentValue);
  if (currentLength + computeLengthForAPIValue(event->text()) <
      unsignedMaxLength)
    return;

  // 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 = 0;
  if (isFocused()) {
    // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
    // needs to be audited.  See http://crbug.com/590369 for more details.
    document().updateStyleAndLayoutIgnorePendingStylesheets();

    selectionLength = computeLengthForAPIValue(
        document().frame()->selection().selectedText());
  }
  DCHECK_GE(currentLength, selectionLength);
  unsigned baseLength = currentLength - selectionLength;
  unsigned appendableLength =
      unsignedMaxLength > baseLength ? unsignedMaxLength - baseLength : 0;
  event->setText(sanitizeUserInputValue(event->text(), appendableLength));
}
Beispiel #2
0
void HTMLTextFormControlElement::setInnerEditorValue(const String& value)
{
    ASSERT(!openShadowRoot());
    if (!isTextFormControl() || openShadowRoot())
        return;

    bool textIsChanged = value != innerEditorValue();
    HTMLElement* innerEditor = innerEditorElement();
    if (!textIsChanged && innerEditor->hasChildren())
        return;

    // If the last child is a trailing <br> that's appended below, remove it
    // first so as to enable setInnerText() fast path of updating a text node.
    if (isHTMLBRElement(innerEditor->lastChild()))
        innerEditor->removeChild(innerEditor->lastChild(), ASSERT_NO_EXCEPTION);

    // We don't use setTextContent.  It triggers unnecessary paint.
    if (value.isEmpty())
        innerEditor->removeChildren();
    else
        replaceChildrenWithText(innerEditor, value, ASSERT_NO_EXCEPTION);

    // Add <br> so that we can put the caret at the next line of the last
    // newline.
    addPlaceholderBreakElementIfNecessary();

    if (textIsChanged && layoutObject()) {
        if (AXObjectCache* cache = document().existingAXObjectCache())
            cache->handleTextFormControlChanged(this);
    }
}
Beispiel #3
0
void HTMLTextAreaElement::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* event) const
{
    ASSERT(event);
    ASSERT(renderer());
    int signedMaxLength = maxLength();
    if (signedMaxLength < 0)
        return;
    unsigned unsignedMaxLength = static_cast<unsigned>(signedMaxLength);

    const String& currentValue = innerEditorValue();
    unsigned currentLength = computeLengthForSubmission(currentValue);
    if (currentLength + computeLengthForSubmission(event->text()) < unsignedMaxLength)
        return;

    // 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 = 0;
    if (focused()) {
        Position start, end;
        document().frame()->selection().selection().toNormalizedPositions(start, end);
        selectionLength = computeLengthForSubmission(plainText(start, end));
    }
    ASSERT(currentLength >= selectionLength);
    unsigned baseLength = currentLength - selectionLength;
    unsigned appendableLength = unsignedMaxLength > baseLength ? unsignedMaxLength - baseLength : 0;
    event->setText(sanitizeUserInputValue(event->text(), appendableLength));
}
void HTMLTextAreaElement::updateValue() const {
  if (m_valueIsUpToDate)
    return;

  m_value = innerEditorValue();
  const_cast<HTMLTextAreaElement*>(this)->m_valueIsUpToDate = true;
  const_cast<HTMLTextAreaElement*>(this)->notifyFormStateChanged();
  m_isDirty = true;
  const_cast<HTMLTextAreaElement*>(this)->updatePlaceholderVisibility();
}
void HTMLTextFormControlElement::setRangeText(const String& replacement, unsigned start, unsigned end, const String& selectionMode, ExceptionState& exceptionState)
{
    if (start > end) {
        exceptionState.throwDOMException(IndexSizeError, "The provided start value (" + String::number(start) + ") is larger than the provided end value (" + String::number(end) + ").");
        return;
    }
    if (hasAuthorShadowRoot())
        return;

    String text = innerEditorValue();
    unsigned textLength = text.length();
    unsigned replacementLength = replacement.length();
    unsigned newSelectionStart = selectionStart();
    unsigned newSelectionEnd = selectionEnd();

    start = std::min(start, textLength);
    end = std::min(end, textLength);

    if (start < end)
        text.replace(start, end - start, replacement);
    else
        text.insert(replacement, start);

    setInnerEditorValue(text);

    // FIXME: What should happen to the value (as in value()) if there's no renderer?
    if (!renderer())
        return;

    subtreeHasChanged();

    if (equalIgnoringCase(selectionMode, "select")) {
        newSelectionStart = start;
        newSelectionEnd = start + replacementLength;
    } else if (equalIgnoringCase(selectionMode, "start"))
        newSelectionStart = newSelectionEnd = start;
    else if (equalIgnoringCase(selectionMode, "end"))
        newSelectionStart = newSelectionEnd = start + replacementLength;
    else {
        // Default is "preserve".
        long delta = replacementLength - (end - start);

        if (newSelectionStart > end)
            newSelectionStart += delta;
        else if (newSelectionStart > start)
            newSelectionStart = start;

        if (newSelectionEnd > end)
            newSelectionEnd += delta;
        else if (newSelectionEnd > start)
            newSelectionEnd = start + replacementLength;
    }

    setSelectionRange(newSelectionStart, newSelectionEnd, SelectionHasNoDirection);
}
Beispiel #6
0
void HTMLTextFormControlElement::setRangeText(const String& replacement, unsigned start, unsigned end, const String& selectionMode, ExceptionState& exceptionState)
{
    if (start > end) {
        exceptionState.throwDOMException(IndexSizeError, "The provided start value (" + String::number(start) + ") is larger than the provided end value (" + String::number(end) + ").");
        return;
    }
    if (openShadowRoot())
        return;

    String text = innerEditorValue();
    unsigned textLength = text.length();
    unsigned replacementLength = replacement.length();
    unsigned newSelectionStart = selectionStart();
    unsigned newSelectionEnd = selectionEnd();

    start = std::min(start, textLength);
    end = std::min(end, textLength);

    if (start < end)
        text.replace(start, end - start, replacement);
    else
        text.insert(replacement, start);

    setValue(text, TextFieldEventBehavior::DispatchNoEvent);

    if (selectionMode == "select") {
        newSelectionStart = start;
        newSelectionEnd = start + replacementLength;
    } else if (selectionMode == "start") {
        newSelectionStart = newSelectionEnd = start;
    } else if (selectionMode == "end") {
        newSelectionStart = newSelectionEnd = start + replacementLength;
    } else {
        ASSERT(selectionMode == "preserve");
        long delta = replacementLength - (end - start);

        if (newSelectionStart > end)
            newSelectionStart += delta;
        else if (newSelectionStart > start)
            newSelectionStart = start;

        if (newSelectionEnd > end)
            newSelectionEnd += delta;
        else if (newSelectionEnd > start)
            newSelectionEnd = start + replacementLength;
    }

    setSelectionRange(newSelectionStart, newSelectionEnd, SelectionHasNoDirection);
}
Beispiel #7
0
void HTMLTextFormControlElement::setSelectionRange(int start, int end, TextFieldSelectionDirection direction, NeedToDispatchSelectEvent eventBehaviour, SelectionOption selectionOption)
{
    if (openShadowRoot() || !isTextFormControl())
        return;
    const int editorValueLength = static_cast<int>(innerEditorValue().length());
    ASSERT(editorValueLength >= 0);
    end = std::max(std::min(end, editorValueLength), 0);
    start = std::min(std::max(start, 0), end);
    cacheSelection(start, end, direction);

    if (selectionOption == NotChangeSelection || (selectionOption == ChangeSelectionIfFocused && document().focusedElement() != this) || !inShadowIncludingDocument()) {
        if (eventBehaviour == DispatchSelectEvent)
            scheduleSelectEvent();
        return;
    }

    LocalFrame* frame = document().frame();
    HTMLElement* innerEditor = innerEditorElement();
    if (!frame || !innerEditor)
        return;

    Position startPosition = positionForIndex(innerEditor, start);
    Position endPosition = start == end ? startPosition : positionForIndex(innerEditor, end);

    ASSERT(start == indexForPosition(innerEditor, startPosition));
    ASSERT(end == indexForPosition(innerEditor, endPosition));

#if ENABLE(ASSERT)
    // startPosition and endPosition can be null position for example when
    // "-webkit-user-select: none" style attribute is specified.
    if (startPosition.isNotNull() && endPosition.isNotNull()) {
        ASSERT(startPosition.anchorNode()->shadowHost() == this
            && endPosition.anchorNode()->shadowHost() == this);
    }
#endif // ENABLE(ASSERT)
    VisibleSelection newSelection;
    if (direction == SelectionHasBackwardDirection)
        newSelection.setWithoutValidation(endPosition, startPosition);
    else
        newSelection.setWithoutValidation(startPosition, endPosition);
    newSelection.setIsDirectional(direction != SelectionHasNoDirection);

    frame->selection().setSelection(newSelection, FrameSelection::DoNotAdjustInFlatTree | FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle | (selectionOption == ChangeSelectionAndFocus ? 0 : FrameSelection::DoNotSetFocus));
    if (eventBehaviour == DispatchSelectEvent)
        scheduleSelectEvent();
}
void HTMLTextFormControlElement::setInnerEditorValue(const String& value)
{
    ASSERT(!hasAuthorShadowRoot());
    if (!isTextFormControl() || hasAuthorShadowRoot())
        return;

    bool textIsChanged = value != innerEditorValue();
    if (textIsChanged || !innerEditorElement()->hasChildren()) {
        if (textIsChanged && renderer()) {
            if (AXObjectCache* cache = document().existingAXObjectCache())
                cache->postNotification(this, AXObjectCache::AXValueChanged, false);
        }
        innerEditorElement()->setInnerText(value, ASSERT_NO_EXCEPTION);

        if (value.endsWith('\n') || value.endsWith('\r'))
            innerEditorElement()->appendChild(HTMLBRElement::create(document()));
    }
}
void HTMLTextFormControlElement::setInnerEditorValue(const String& value)
{
    ASSERT(!hasOpenShadowRoot());
    if (!isTextFormControl() || hasOpenShadowRoot())
        return;

    bool textIsChanged = value != innerEditorValue();
    if (textIsChanged || !innerEditorElement()->hasChildren()) {
        if (textIsChanged && layoutObject()) {
            if (AXObjectCache* cache = document().existingAXObjectCache())
                cache->handleTextFormControlChanged(this);
        }
        innerEditorElement()->setInnerText(value, ASSERT_NO_EXCEPTION);

        if (value.endsWith('\n') || value.endsWith('\r'))
            innerEditorElement()->appendChild(HTMLBRElement::create(document()));
    }
}