Skip to content

Commit

Permalink
Use RPC for TextField cursor position and selection range updates
Browse files Browse the repository at this point in the history
Change-Id: I48595a1d1a9a1620739d00a499d996026bd51000
  • Loading branch information
Artur- committed Aug 25, 2016
1 parent 848b877 commit 983a4e3
Show file tree
Hide file tree
Showing 7 changed files with 287 additions and 94 deletions.
Expand Up @@ -17,7 +17,6 @@
package com.vaadin.client.ui.textfield;

import com.google.gwt.core.client.Scheduler;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Timer;
import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.event.InputEvent;
Expand All @@ -26,6 +25,7 @@
import com.vaadin.client.ui.VTextField;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.Connect.LoadStyle;
import com.vaadin.shared.ui.textfield.AbstractTextFieldClientRpc;
import com.vaadin.shared.ui.textfield.AbstractTextFieldServerRpc;
import com.vaadin.shared.ui.textfield.TextFieldState;
import com.vaadin.shared.ui.textfield.ValueChangeMode;
Expand All @@ -37,6 +37,35 @@
@Connect(value = TextField.class, loadStyle = LoadStyle.EAGER)
public class TextFieldConnector extends AbstractComponentConnector {

private class AbstractTextFieldClientRpcImpl
implements AbstractTextFieldClientRpc {
@Override
public void selectRange(int start, int length) {
int textLength = getWidget().getText().length();
start = restrictTo(start, 0, textLength - 1);
length = restrictTo(length, 0, textLength - start);
getWidget().setSelectionRange(start, length);
}

private int restrictTo(int value, int min, int max) {
if (value < min) {
value = min;
}
if (value > max) {
value = max;
}

return value;
}

@Override
public void selectAll() {
getWidget().selectAll();
}
}

private int lastSentCursorPosition = -1;

private Timer valueChangeTrigger = new Timer() {
@Override
public void run() {
Expand All @@ -46,6 +75,8 @@ public void run() {

@Override
protected void init() {
registerRpc(AbstractTextFieldClientRpc.class,
new AbstractTextFieldClientRpcImpl());
ConnectorFocusAndBlurHandler.addHandlers(this);
getWidget().addChangeHandler(event -> sendValueChange());
getWidget().addDomHandler(event -> {
Expand Down Expand Up @@ -102,43 +133,20 @@ private void updateReadOnly() {
getWidget().setReadOnly(getState().readOnly);
}

@OnStateChange({ "selectionStart", "selectionLength" })
private void updateSelection() {
if (getState().selectionStart != -1) {
Scheduler.get().scheduleDeferred(new Command() {
@Override
public void execute() {
getWidget().setSelectionRange(getState().selectionStart,
getState().selectionLength);
}
});
}
}

@OnStateChange("cursorPosition")
private void updateCursorPosition() {
Scheduler.get().scheduleDeferred(new Command() {
@Override
public void execute() {
getWidget().setCursorPos(getState().cursorPosition);
}
});
}

private boolean hasStateChanged() {
boolean textChanged = !getWidget().getValue().equals(getState().text);
boolean cursorPosChanged = getWidget()
.getCursorPos() != getState().cursorPosition;
.getCursorPos() != lastSentCursorPosition;
return textChanged || cursorPosChanged;
}

private void sendValueChange() {
if (!hasStateChanged()) {
return;
}
lastSentCursorPosition = getWidget().getCursorPos();
getRpcProxy(AbstractTextFieldServerRpc.class)
.setText(getWidget().getValue(), getWidget().getCursorPos());
.setText(getWidget().getValue(), lastSentCursorPosition);
getState().text = getWidget().getValue();
getState().cursorPosition = getWidget().getCursorPos();
}
}
28 changes: 17 additions & 11 deletions server/src/main/java/com/vaadin/ui/AbstractTextField.java
Expand Up @@ -26,6 +26,7 @@
import com.vaadin.event.FieldEvents.FocusEvent;
import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.textfield.AbstractTextFieldClientRpc;
import com.vaadin.shared.ui.textfield.AbstractTextFieldServerRpc;
import com.vaadin.shared.ui.textfield.TextFieldState;
import com.vaadin.shared.ui.textfield.ValueChangeMode;
Expand Down Expand Up @@ -56,13 +57,16 @@ public void focus() {
public void setText(String text, int cursorPosition) {
getUI().getConnectorTracker().getDiffState(AbstractTextField.this)
.put("text", text);
getUI().getConnectorTracker().getDiffState(AbstractTextField.this)
.put("cursorPosition", cursorPosition);
getState(false).cursorPosition = cursorPosition;
lastKnownCursorPosition = cursorPosition;
setValue(text, true);
}
}

private int lastKnownCursorPosition = -1;

/**
* Creates a new instance.
*/
protected AbstractTextField() {
registerRpc(new TextFieldServerRpcImpl());
}
Expand Down Expand Up @@ -125,24 +129,27 @@ public String getValue() {

/**
* Selects all text in the field.
* <p>
* As a side effect the field will become focused.
*/
public void selectAll() {
setSelection(0, getValue().length());
getRpcProxy(AbstractTextFieldClientRpc.class).selectAll();
focus();
}

/**
* Sets the range of text to be selected.
*
* <p>
* As a side effect the field will become focused.
*
* @param pos
* @param start
* the position of the first character to be selected
* @param length
* the number of characters to be selected
*/
public void setSelection(int start, int length) {
getState().selectionStart = start;
getState().selectionLength = length;
getRpcProxy(AbstractTextFieldClientRpc.class).selectRange(start,
length);
focus();
}

Expand All @@ -154,16 +161,15 @@ public void setSelection(int start, int length) {
* the position for the cursor
*/
public void setCursorPosition(int pos) {
getState().cursorPosition = pos;
focus();
setSelection(pos, 0);
}

/**
* Returns the last known cursor position of the field.
*
*/
public int getCursorPosition() {
return getState(false).cursorPosition;
return lastKnownCursorPosition;
}

/**
Expand Down
@@ -0,0 +1,39 @@
/*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.shared.ui.textfield;

import com.vaadin.shared.communication.ClientRpc;

/**
* Server to client RPC interface for AbstractTextField.
*
*/
public interface AbstractTextFieldClientRpc extends ClientRpc {
/**
* Selects the given range in the field.
*
* @param start
* the start of the range
* @param length
* the length to select
*/
void selectRange(int start, int length);

/**
* Selects everything in the field.
*/
void selectAll();
}
Expand Up @@ -50,15 +50,6 @@ public class TextFieldState extends AbstractFieldState {
@NoLayout
public String text = "";

@NoLayout
public int selectionStart = -1;

@NoLayout
public int selectionLength = 0;

@NoLayout
public int cursorPosition = 0;

@NoLayout
public ValueChangeMode valueChangeMode = ValueChangeMode.LAZY;

Expand Down

0 comments on commit 983a4e3

Please sign in to comment.