From 5ea677d377c96c60fbc546eb2381bb88f2d4b478 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Tue, 12 Mar 2013 18:34:18 +0200 Subject: Make TextArea.setCursorPosition work in all browsers (#8769) svn changeset:25579/svn branch:6.8 Conflicts: client/src/com/vaadin/client/ui/VTextField.java Change-Id: I3b53be8df4ce0564f34d8aa9bc1ce1c34648eadd --- client/src/com/vaadin/client/ui/VTextArea.java | 114 ++++++++++++++ client/src/com/vaadin/client/ui/VTextField.java | 4 + .../tests/components/textarea/ScrollCursor.html | 169 +++++++++++++++++++++ .../tests/components/textarea/ScrollCursor.java | 89 +++++++++++ 4 files changed, 376 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/components/textarea/ScrollCursor.html create mode 100644 uitest/src/com/vaadin/tests/components/textarea/ScrollCursor.java diff --git a/client/src/com/vaadin/client/ui/VTextArea.java b/client/src/com/vaadin/client/ui/VTextArea.java index 4a5de23828..45e0532451 100644 --- a/client/src/com/vaadin/client/ui/VTextArea.java +++ b/client/src/com/vaadin/client/ui/VTextArea.java @@ -63,6 +63,120 @@ public class VTextArea extends VTextField { getTextAreaElement().setRows(rows); } + @Override + public void setSelectionRange(int pos, int length) { + super.setSelectionRange(pos, length); + final String value = getValue(); + /* + * Align position to index inside string value + */ + int index = pos; + if (index < 0) { + index = 0; + } + if (index > value.length()) { + index = value.length(); + } + // Get pixels count required to scroll textarea vertically + int scrollTop = getScrollTop(value, index); + int scrollLeft = -1; + /* + * Check if textarea has wrap attribute set to "off". In the latter case + * horizontal scroll is also required. + */ + if (!isWordwrap()) { + // Get pixels count required to scroll textarea horizontally + scrollLeft = getScrollLeft(value, index); + } + // Set back original text if previous methods calls changed it + if (!isWordwrap() || index < value.length()) { + setValue(value, false); + } + /* + * Call original method to set cursor position. In most browsers it + * doesn't lead to scrolling. + */ + super.setSelectionRange(pos, length); + /* + * Align vertical scroll to middle of textarea view (height) if + * scrolling is reqiured at all. + */ + if (scrollTop > 0) { + scrollTop += getElement().getClientHeight() / 2; + } + /* + * Align horizontal scroll to middle of textarea view (widht) if + * scrolling is reqiured at all. + */ + if (scrollLeft > 0) { + scrollLeft += getElement().getClientWidth() / 2; + } + /* + * Scroll if computed scrollTop is greater than scroll after cursor + * setting + */ + if (getElement().getScrollTop() < scrollTop) { + getElement().setScrollTop(scrollTop); + } + /* + * Scroll if computed scrollLeft is greater than scroll after cursor + * setting + */ + if (getElement().getScrollLeft() < scrollLeft) { + getElement().setScrollLeft(scrollLeft); + } + } + + /* + * Get horizontal scroll value required to get position visible. Method is + * called only when text wrapping is off. There is need to scroll + * horizontally in case words are wrapped. + */ + private int getScrollLeft(String value, int index) { + String beginning = value.substring(0, index); + // Compute beginning of the current line + int begin = beginning.lastIndexOf('\n'); + String line = value.substring(begin + 1); + index = index - begin - 1; + if (index < line.length()) { + index++; + } + line = line.substring(0, index); + /* + * Now line contains current line up to index position + */ + setValue(line.trim(), false); // Set this line to the textarea. + /* + * Scroll textarea up to the end of the line (maximum possible + * horizontal scrolling value). Now the end line becomes visible. + */ + getElement().setScrollLeft(getElement().getScrollWidth()); + // Return resulting horizontal scrolling value. + return getElement().getScrollLeft(); + } + + /* + * Get vertical scroll value required to get position visible + */ + private int getScrollTop(String value, int index) { + /* + * Trim text after position and set this trimmed text if index is not + * very end. + */ + if (index < value.length()) { + String beginning = value.substring(0, index); + setValue(beginning, false); + } + /* + * Now textarea contains trimmed text and could be scrolled up to the + * top. Scroll it to maximum possible value to get end of the text + * visible. + */ + getElement().setScrollTop(getElement().getScrollHeight()); + // Return resulting vertical scrolling value. + return getElement().getScrollTop(); + } + private class MaxLengthHandler implements KeyUpHandler, ChangeHandler { @Override diff --git a/client/src/com/vaadin/client/ui/VTextField.java b/client/src/com/vaadin/client/ui/VTextField.java index 0fbed0dd90..da9445c811 100644 --- a/client/src/com/vaadin/client/ui/VTextField.java +++ b/client/src/com/vaadin/client/ui/VTextField.java @@ -446,4 +446,8 @@ public class VTextField extends TextBoxBase implements Field, ChangeHandler, this.inputPrompt = inputPrompt; } + protected boolean isWordwrap() { + String wrap = getElement().getAttribute("wrap"); + return !"off".equals(wrap); + } } diff --git a/uitest/src/com/vaadin/tests/components/textarea/ScrollCursor.html b/uitest/src/com/vaadin/tests/components/textarea/ScrollCursor.html new file mode 100644 index 0000000000..9eaa1ceada --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/textarea/ScrollCursor.html @@ -0,0 +1,169 @@ + + + + + + +New Test + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
New Test
open/run/com.vaadin.tests.components.textarea.ScrollCursor?restartApplication
mouseClickvaadin=runcomvaadintestscomponentstextareaScrollCursor::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[0]191,94
clickvaadin=runcomvaadintestscomponentstextareaScrollCursor::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VButton[0]/domChild[0]/domChild[0]
clickvaadin=runcomvaadintestscomponentstextareaScrollCursor::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]
screenCapturewrap-start
clickvaadin=runcomvaadintestscomponentstextareaScrollCursor::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VButton[0]/domChild[0]/domChild[0]
clickvaadin=runcomvaadintestscomponentstextareaScrollCursor::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]
screenCapturewrap-middle
clickvaadin=runcomvaadintestscomponentstextareaScrollCursor::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VButton[0]/domChild[0]/domChild[0]
clickvaadin=runcomvaadintestscomponentstextareaScrollCursor::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]
screenCapturewrap-end
clickvaadin=runcomvaadintestscomponentstextareaScrollCursor::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VButton[0]/domChild[0]/domChild[0]
clickvaadin=runcomvaadintestscomponentstextareaScrollCursor::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]
screenCapturewrap-end-start
clickvaadin=runcomvaadintestscomponentstextareaScrollCursor::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]
clickvaadin=runcomvaadintestscomponentstextareaScrollCursor::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VButton[0]/domChild[0]/domChild[0]
clickvaadin=runcomvaadintestscomponentstextareaScrollCursor::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]
screenCapturenowrap-start
clickvaadin=runcomvaadintestscomponentstextareaScrollCursor::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VButton[0]/domChild[0]/domChild[0]
clickvaadin=runcomvaadintestscomponentstextareaScrollCursor::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]
screenCapturenowrap-middle
clickvaadin=runcomvaadintestscomponentstextareaScrollCursor::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VButton[0]/domChild[0]/domChild[0]
clickvaadin=runcomvaadintestscomponentstextareaScrollCursor::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]
screenCapturenowrap-end
clickvaadin=runcomvaadintestscomponentstextareaScrollCursor::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VButton[0]/domChild[0]/domChild[0]
clickvaadin=runcomvaadintestscomponentstextareaScrollCursor::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]
screenCapturenowrap-end-start
+ + diff --git a/uitest/src/com/vaadin/tests/components/textarea/ScrollCursor.java b/uitest/src/com/vaadin/tests/components/textarea/ScrollCursor.java new file mode 100644 index 0000000000..c95731d94f --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/textarea/ScrollCursor.java @@ -0,0 +1,89 @@ +package com.vaadin.tests.components.textarea; + +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.TextArea; + +/** + * @author denis + * + */ +public class ScrollCursor extends TestBase { + + private TextArea textArea; + private int position; + + @Override + protected void setup() { + textArea = new TextArea(); + textArea.setValue("saddddddddddd fdgdfgfdgfd\n" + + "aasddddddddddd\n" + "dsaffffffdsf\n" + "sdf\n" + + "dsfsdfsdfsdfsd\n\n" + "ffffffffffffffffffff\n" + + "sdfdsfdsfsdfsdfsd xxxxxxxxxxxxxxxx\n" + "sdgfsd\n" + + "dsf\n" + "ds\n" + "fds\n" + "fds\nfs"); + addComponent(textArea); + Button button = new Button("Scroll"); + button.addListener(new ClickListener() { + + public void buttonClick(ClickEvent event) { + textArea.setCursorPosition(getPosition()); + } + }); + Button wrap = new Button("Set wrap"); + wrap.addListener(new ClickListener() { + + public void buttonClick(ClickEvent event) { + textArea.setWordwrap(false); + } + }); + + Button toBegin = new Button("To begin"); + toBegin.addListener(new ClickListener() { + + public void buttonClick(ClickEvent event) { + position = 3; + } + }); + + Button toMiddle = new Button("To middle"); + toMiddle.addListener(new ClickListener() { + + public void buttonClick(ClickEvent event) { + position = 130; + } + }); + + Button toEnd = new Button("To end"); + toEnd.addListener(new ClickListener() { + + public void buttonClick(ClickEvent event) { + position = textArea.getValue().toString().length(); + } + }); + + addComponent(button); + addComponent(wrap); + addComponent(toBegin); + addComponent(toMiddle); + addComponent(toEnd); + } + + @Override + protected String getDescription() { + return "Tests scrolling for TextArea with different word wrapping settings. " + + "Sets cursor position at the beginning, middle and the end " + + "of text and checks textarea is scrolled."; + } + + @Override + protected Integer getTicketNumber() { + return 8769; + } + + private int getPosition() { + return position; + } + +} -- cgit v1.2.3