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)); }
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); } }
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); }
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); }
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())); } }