1 package org.vaadin.hene.expandingtextarea.widgetset.client.ui;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import com.google.gwt.user.client.Element;
7 import com.google.gwt.user.client.Event;
8 import com.google.gwt.user.client.Timer;
9 import com.vaadin.v7.client.ui.VTextArea;
10
11
12
13
14
15 public class VExpandingTextArea extends VTextArea {
16
17
18 public static final String CLASSNAME = "v-expandingtextarea";
19
20 private static int REPEAT_INTERVAL = 400;
21
22 private Integer maxRows = null;
23
24 private final HeightObserver heightObserver;
25
26 public VExpandingTextArea() {
27 setStyleName(CLASSNAME);
28 sinkEvents(Event.ONFOCUS | Event.ONFOCUS);
29
30 heightObserver = new HeightObserver();
31 }
32
33 @Override
34 public void onBrowserEvent(Event event) {
35 super.onBrowserEvent(event);
36 if (event.getTypeInt() == Event.ONFOCUS) {
37 heightObserver.scheduleRepeating(REPEAT_INTERVAL);
38 getElement().addClassName(CLASSNAME + "-focus");
39 } else if (event.getTypeInt() == Event.ONBLUR) {
40 heightObserver.cancel();
41 getElement().removeClassName(CLASSNAME + "-focus");
42 }
43 }
44
45 public void checkHeight() {
46 int origRows = getRows(getElement());
47
48
49 int rows = origRows;
50 rows++;
51 while ((maxRows == null || rows <= maxRows)
52 && getElement().getScrollHeight() > getOffsetHeight()) {
53 setRows(rows++);
54 }
55
56
57 rows = getRows(getElement());
58 while (rows > 1) {
59 setRows(rows - 1);
60 if (!(getElement().getScrollHeight() > getOffsetHeight())) {
61 rows -= 1;
62 continue;
63 } else {
64 setRows(rows);
65 break;
66 }
67 }
68
69 int updatedRowCount = getRows(getElement()) + 1;
70
71
72 if (maxRows != null && updatedRowCount > maxRows) {
73 addStyleName("max");
74 updatedRowCount = updatedRowCount > maxRows ? maxRows
75 : updatedRowCount;
76 } else {
77 removeStyleName("max");
78 }
79
80 setRows(updatedRowCount);
81
82 if (origRows != getRows(getElement())) {
83 for (HeightChangedListener listener : heightChangedListeners) {
84 listener.heightChanged(getRows(getElement()));
85 }
86 }
87 }
88
89 public void setMaxRows(Integer maxRows) {
90 this.maxRows = maxRows;
91 }
92
93 public int getRows() {
94 return getRows(getElement());
95 }
96
97 private native int getRows(Element e)
98
99
100
101
102
103
104 ;
105
106 private class HeightObserver extends Timer {
107
108 @Override
109 public void run() {
110 checkHeight();
111 }
112 }
113
114 @Override
115 protected void onDetach() {
116 heightObserver.cancel();
117 super.onDetach();
118 }
119
120 List<HeightChangedListener> heightChangedListeners = new ArrayList<VExpandingTextArea.HeightChangedListener>();
121
122 public interface HeightChangedListener {
123 void heightChanged(int newHeight);
124 }
125
126 public void addHeightChangedListener(HeightChangedListener listener) {
127 heightChangedListeners.add(listener);
128 }
129
130 public void removeHeightChangedListener(HeightChangedListener listener) {
131 heightChangedListeners.remove(listener);
132 }
133 }