1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.ui.vaadin.gwt.client.richtext;
35
36 import info.magnolia.ui.vaadin.gwt.client.dialog.widget.OverlayWidget;
37 import info.magnolia.ui.vaadin.gwt.client.form.widget.FormView;
38 import info.magnolia.ui.vaadin.gwt.client.jquerywrapper.JQueryWrapper;
39 import info.magnolia.ui.vaadin.richtext.TextAreaStretcher;
40
41 import com.google.gwt.core.client.Scheduler;
42 import com.google.gwt.dom.client.Element;
43 import com.google.gwt.dom.client.Style;
44 import com.google.gwt.event.logical.shared.AttachEvent;
45 import com.google.gwt.user.client.DOM;
46 import com.google.gwt.user.client.ui.Widget;
47 import com.googlecode.mgwt.dom.client.event.touch.TouchEndEvent;
48 import com.googlecode.mgwt.dom.client.event.touch.TouchEndHandler;
49 import com.googlecode.mgwt.ui.client.widget.touch.TouchDelegate;
50 import com.vaadin.client.ComponentConnector;
51 import com.vaadin.client.ComputedStyle;
52 import com.vaadin.client.LayoutManager;
53 import com.vaadin.client.ServerConnector;
54 import com.vaadin.client.Util;
55 import com.vaadin.client.communication.StateChangeEvent;
56 import com.vaadin.client.extensions.AbstractExtensionConnector;
57 import com.vaadin.client.ui.layout.ElementResizeEvent;
58 import com.vaadin.client.ui.layout.ElementResizeListener;
59 import com.vaadin.client.ui.ui.UIConnector;
60 import com.vaadin.shared.ui.Connect;
61
62
63
64
65 @Connect(TextAreaStretcher.class)
66 public class TextAreaStretcherConnector extends AbstractExtensionConnector {
67
68 public static final int DELAY_MS = 500;
69 private Widget form;
70 private Widget dialog;
71 private Widget textWidget;
72
73 private Element stretchControl = DOM.createDiv();
74 private WindowResizeListener windowResizeListener = new WindowResizeListener();
75
76 private boolean isOverlay = false;
77 private boolean isRichTextEditor = false;
78
79 private StateChangeEvent.StateChangeHandler textAreaSizeHandler = new StateChangeEvent.StateChangeHandler() {
80 @Override
81 public void onStateChanged(StateChangeEvent stateChangeEvent) {
82 stretchTextArea(textWidget.getElement().getStyle());
83 }
84 };
85
86 private ElementResizeListener formResizeListener = new ElementResizeListener() {
87 @Override
88 public void onElementResize(ElementResizeEvent e) {
89 if (isRichTextEditor) {
90 Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {
91 @Override
92 public void execute() {
93 updateSize();
94 }
95 });
96 } else {
97 updateSize();
98 }
99 }
100 };;
101
102 @Override
103 public void onStateChanged(StateChangeEvent stateChangeEvent) {
104 super.onStateChanged(stateChangeEvent);
105 if (stateChangeEvent.hasPropertyChanged("isCollapsed")) {
106 updateSize();
107 if (!getState().isCollapsed) {
108 registerSizeChangeListeners();
109 }
110 }
111 }
112
113 @Override
114 public ComponentConnector getParent() {
115 return (ComponentConnector) super.getParent();
116 }
117
118 @Override
119 protected void extend(ServerConnector target) {
120 this.textWidget = ((ComponentConnector)target).getWidget();
121 this.isRichTextEditor = target instanceof RichTextConnector;
122 this.stretchControl.setClassName("textarea-stretcher");
123 textWidget.addAttachHandler(new AttachEvent.Handler() {
124 @Override
125 public void onAttachOrDetach(AttachEvent attachEvent) {
126 initFormView();
127 initDialog();
128 checkOverlay();
129 if (!isRichTextEditor) {
130 appendStretcher(textWidget.getElement());
131 } else {
132 Scheduler.get().scheduleFixedDelay(new Scheduler.RepeatingCommand() {
133 private int repeats = 0;
134
135 @Override
136 public boolean execute() {
137 repeats++;
138 isRichTextEditor = true;
139 Element iframe = JQueryWrapper.select(textWidget).find("iframe").get(0);
140 if (iframe != null) {
141 appendStretcher(iframe);
142 stretchControl.addClassName("rich-text");
143 }
144 return iframe == null && repeats < 5;
145 }
146 }, DELAY_MS);
147 }
148 }
149 });
150 }
151
152 @Override
153 public TextAreaStretcherState getState() {
154 return (TextAreaStretcherState) super.getState();
155 }
156
157 private void appendStretcher(Element rootElement) {
158 rootElement.getParentElement().insertAfter(stretchControl, rootElement);
159 Widget parent = textWidget.getParent();
160 TouchDelegate touchDelegate = new TouchDelegate(parent);
161 touchDelegate.addTouchEndHandler(new TouchEndHandler() {
162 @Override
163 public void onTouchEnd(TouchEndEvent event) {
164 Element target = event.getNativeEvent().getEventTarget().cast();
165 if (stretchControl.isOrHasChild(target)) {
166 if (!getState().isCollapsed) {
167 unregisterSizeChangeListeners();
168 }
169 getRpcProxy(TextAreaStretcherServerRpc.class).toggle(textWidget.getOffsetWidth(), textWidget.getOffsetHeight());
170
171 }
172 }
173 });
174 }
175
176 private void registerSizeChangeListeners() {
177 final LayoutManager lm = getParent().getLayoutManager();
178 final UIConnector ui = getConnection().getUIConnector();
179 getParent().addStateChangeHandler(textAreaSizeHandler);
180 lm.addElementResizeListener(ui.getWidget().getElement(), windowResizeListener);
181
182 final ComponentConnector formConnector = Util.findConnectorFor(this.form);
183 if (formConnector != null) {
184 formConnector.getLayoutManager().addElementResizeListener(this.form.getElement(), formResizeListener);
185 }
186 }
187
188 private void updateSize() {
189 if (!getState().isCollapsed) {
190 stretchControl.replaceClassName("icon-open-fullscreen-2", "icon-close-fullscreen-2");
191 stretchControl.replaceClassName("collapsed", "stretched");
192 form.asWidget().addStyleName("textarea-stretched");
193
194 Style style = textWidget.getElement().getStyle();
195 style.setPosition(Style.Position.ABSOLUTE);
196 Element header = getDialogHeaderElement();
197 ComputedStyle headerCS = new ComputedStyle(header);
198
199 int top = form.getAbsoluteTop() - dialog.getAbsoluteTop();
200 top = isOverlay ? top : top + headerCS.getPadding()[0] + headerCS.getPadding()[2];
201
202 int left = isOverlay ? 0 : form.getAbsoluteLeft();
203
204 style.setLeft(left, Style.Unit.PX);
205 style.setTop(top, Style.Unit.PX);
206
207 stretchTextArea(style);
208 style.setZIndex(5);
209
210 if (!isOverlay && !isRichTextEditor) {
211 stretchControl.getStyle().setTop(top + 5, Style.Unit.PX);
212 stretchControl.getStyle().setLeft(left + textWidget.getOffsetWidth() - stretchControl.getOffsetWidth() - 5, Style.Unit.PX);
213
214 }
215
216 } else {
217 stretchControl.replaceClassName("stretched", "collapsed");
218 stretchControl.replaceClassName("icon-close-fullscreen-2", "icon-open-fullscreen-2");
219 form.asWidget().removeStyleName("textarea-stretched");
220 clearTraces();
221 }
222 }
223
224 private void clearTraces() {
225 Style style = textWidget.getElement().getStyle();
226 style.clearLeft();
227 style.clearTop();
228 style.clearPosition();
229 style.clearZIndex();
230
231 stretchControl.getStyle().clearTop();
232 stretchControl.getStyle().clearLeft();
233 }
234
235 private void stretchTextArea(Style style) {
236 style.setWidth(form.getOffsetWidth(), Style.Unit.PX);
237 adjustTextAreaHeightToScreen(getConnection().getUIConnector().getWidget().getOffsetHeight());
238 }
239
240 private void unregisterSizeChangeListeners() {
241 final LayoutManager lm = getParent().getLayoutManager();
242 final UIConnector ui = getConnection().getUIConnector();
243 if (ui != null) {
244 getParent().removeStateChangeHandler(textAreaSizeHandler);
245 lm.removeElementResizeListener(ui.getWidget().getElement(), windowResizeListener);
246 }
247
248 final ComponentConnector formConnector = Util.findConnectorFor(this.form);
249 if (formConnector != null) {
250 formConnector.getLayoutManager().removeElementResizeListener(this.form.getElement(), formResizeListener);
251 }
252 }
253
254 private Element getDialogHeaderElement() {
255 return JQueryWrapper.select(dialog.asWidget()).find(".dialog-header").get(0);
256 }
257
258 private void checkOverlay() {
259 Widget it = this.dialog.asWidget();
260 while (it != null && !isOverlay) {
261 it = it.getParent();
262 this.isOverlay = it instanceof OverlayWidget;
263 }
264 }
265
266 private void initDialog() {
267 this.dialog = form.getParent();
268 }
269
270 private void initFormView() {
271 Widget it = textWidget;
272 while (it != null && !(it instanceof FormView)) {
273 it = it.getParent();
274 }
275 this.form = (it instanceof FormView) ? it : null;
276 }
277
278 private void adjustTextAreaHeightToScreen(int uiHeight) {
279 int formTop = form.getAbsoluteTop();
280 textWidget.setHeight((uiHeight - formTop) + "px");
281 }
282
283 private class WindowResizeListener implements ElementResizeListener {
284 @Override
285 public void onElementResize(ElementResizeEvent e) {
286 adjustTextAreaHeightToScreen(e.getLayoutManager().getOuterHeight(e.getElement()));
287 }
288 }
289
290 }