001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: https://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: https://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.acacia.client.widgets;
029
030import org.opencms.acacia.client.css.I_CmsWidgetsLayoutBundle;
031import org.opencms.acacia.client.widgets.CmsTypografUtil.Typograf;
032import org.opencms.gwt.client.I_CmsHasResizeOnShow;
033import org.opencms.gwt.client.ui.input.CmsTextArea;
034import org.opencms.gwt.client.ui.input.form.I_CmsHasPlaceholder;
035import org.opencms.gwt.shared.CmsGwtConstants;
036import org.opencms.util.CmsStringUtil;
037
038import com.google.gwt.dom.client.Element;
039import com.google.gwt.event.dom.client.FocusEvent;
040import com.google.gwt.event.dom.client.FocusHandler;
041import com.google.gwt.event.logical.shared.HasResizeHandlers;
042import com.google.gwt.event.logical.shared.ResizeEvent;
043import com.google.gwt.event.logical.shared.ResizeHandler;
044import com.google.gwt.event.logical.shared.ValueChangeEvent;
045import com.google.gwt.event.logical.shared.ValueChangeHandler;
046import com.google.gwt.event.shared.HandlerRegistration;
047import com.google.gwt.user.client.ui.Composite;
048
049import elemental2.core.Global;
050import jsinterop.base.Js;
051import jsinterop.base.JsPropertyMap;
052
053/**
054 * Provides a display only widget, for use on a widget dialog.<p>
055 *
056 */
057public class CmsTextareaWidget extends Composite
058implements I_CmsEditWidget, HasResizeHandlers, I_CmsHasResizeOnShow, I_CmsHasPlaceholder {
059
060    /** Configuration option to enable automatic typographic formatting using the Typograf library. */
061    public static final String CONF_AUTO_TYPOGRAPHY = "auto-typography";
062
063    /** The monospace style key. */
064    public static final String STYLE_MONSPACE = "monospace";
065
066    /** The proportional style key. */
067    public static final String STYLE_PROPORTIONAL = "proportional";
068
069    /** Default number of rows to display. */
070    private static final int DEFAULT_ROWS_NUMBER = 5;
071
072    /** The token to control activation. */
073    private boolean m_active = true;
074
075    /** Flag to keep track of whether typographic formatting is currently happening. */
076    private boolean m_rewriting;
077
078    /** The input test area.*/
079    private CmsTextArea m_textarea = new CmsTextArea();
080
081    private Typograf m_typograf;
082
083    /**
084     * Creates a new display widget.<p>
085     *
086     * @param configJson the widget configuration string
087     */
088    public CmsTextareaWidget(String configJson) {
089
090        // All composites must call initWidget() in their constructors.
091        initWidget(m_textarea);
092        JsPropertyMap<String> configMap = Js.cast(Global.JSON.parse(configJson));
093        String config = configMap.get(CmsGwtConstants.JSON_TEXTAREA_CONFIG);
094        String locale = configMap.get(CmsGwtConstants.JSON_TEXTAREA_LOCALE);
095
096        int configheight = DEFAULT_ROWS_NUMBER;
097        boolean useProportional = false;
098        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(config)) {
099            for (String conf : config.split("\\|")) {
100                if (STYLE_PROPORTIONAL.equals(conf)) {
101                    useProportional = true;
102                } else if (STYLE_MONSPACE.equals(conf)) {
103                    useProportional = false;
104                } else if (CONF_AUTO_TYPOGRAPHY.equals(conf)) {
105                    if (m_typograf == null) {
106                        m_typograf = CmsTypografUtil.createLiveInstance(locale);
107                    }
108                } else {
109                    try {
110                        int rows = Integer.parseInt(conf);
111                        if (rows > 0) {
112                            configheight = rows;
113                        }
114                    } catch (Exception e) {
115                        // nothing to do
116                    }
117                }
118            }
119        }
120        m_textarea.setRows(configheight);
121        m_textarea.setProportionalStyle(useProportional);
122        m_textarea.getTextArea().addStyleName(I_CmsWidgetsLayoutBundle.INSTANCE.widgetCss().textAreaBox());
123        m_textarea.getTextAreaContainer().addStyleName(
124            I_CmsWidgetsLayoutBundle.INSTANCE.widgetCss().textAreaBoxPanel());
125        m_textarea.addValueChangeHandler(new ValueChangeHandler<String>() {
126
127            public void onValueChange(ValueChangeEvent<String> event) {
128
129                // If typograf library is present, try to apply it to the textarea value. If this would result in a change,
130                // we set the text area content to the new value, which causes a new change event. We prevent an infinite recursion
131                // using the m_rewriting member.
132                if ((m_typograf != null) && !m_rewriting) {
133                    String newContent = CmsTypografUtil.transform(m_typograf, event.getValue());
134                    if (!newContent.equals(event.getValue())) {
135                        m_rewriting = true;
136                        int savedPosition = m_textarea.getPosition();
137                        m_textarea.setFormValueAsString(newContent);
138                        m_textarea.setPosition(savedPosition);
139                    } else {
140                        fireChangeEvent();
141                    }
142                } else {
143                    if (m_rewriting) {
144                        m_rewriting = false;
145                    }
146                    fireChangeEvent();
147                }
148            }
149        });
150        m_textarea.addResizeHandler(new ResizeHandler() {
151
152            public void onResize(ResizeEvent event) {
153
154                fireResizeEvent(event);
155
156            }
157        });
158    }
159
160    /**
161     * @see com.google.gwt.event.dom.client.HasFocusHandlers#addFocusHandler(com.google.gwt.event.dom.client.FocusHandler)
162     */
163    public HandlerRegistration addFocusHandler(FocusHandler handler) {
164
165        return addDomHandler(handler, FocusEvent.getType());
166    }
167
168    /**
169     * @see com.google.gwt.event.logical.shared.HasResizeHandlers#addResizeHandler(com.google.gwt.event.logical.shared.ResizeHandler)
170     */
171    public HandlerRegistration addResizeHandler(ResizeHandler handler) {
172
173        return addHandler(handler, ResizeEvent.getType());
174    }
175
176    /**
177     * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler)
178     */
179    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
180
181        return addHandler(handler, ValueChangeEvent.getType());
182    }
183
184    /**
185     * Represents a value change event.<p>
186     *
187     */
188    public void fireChangeEvent() {
189
190        String result = "";
191        if (m_textarea.getFormValueAsString() != null) {
192            result = m_textarea.getFormValueAsString();
193        }
194
195        ValueChangeEvent.fire(this, result);
196    }
197
198    /**
199     * Represents a resize event.<p>
200     * @param event from text area panel
201     */
202    public void fireResizeEvent(ResizeEvent event) {
203
204        ResizeEvent.fire(this, event.getWidth(), event.getHeight());
205    }
206
207    /**
208     * @see com.google.gwt.user.client.ui.HasValue#getValue()
209     */
210    public String getValue() {
211
212        return m_textarea.getFormValueAsString();
213    }
214
215    /**
216     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#isActive()
217     */
218    public boolean isActive() {
219
220        return m_active;
221    }
222
223    /**
224     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#onAttachWidget()
225     */
226    public void onAttachWidget() {
227
228        super.onAttach();
229    }
230
231    /**
232     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#owns(com.google.gwt.dom.client.Element)
233     */
234    public boolean owns(Element element) {
235
236        return getElement().isOrHasChild(element);
237
238    }
239
240    /**
241     * @see org.opencms.gwt.client.I_CmsHasResizeOnShow#resizeOnShow()
242     */
243    public void resizeOnShow() {
244
245        m_textarea.resizeOnShow();
246    }
247
248    /**
249     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setActive(boolean)
250     */
251    public void setActive(boolean active) {
252
253        if (m_active == active) {
254            return;
255        }
256
257        m_active = active;
258        m_textarea.setEnabled(m_active);
259        if (m_active) {
260            getElement().removeClassName(org.opencms.acacia.client.css.I_CmsLayoutBundle.INSTANCE.form().inActive());
261            getElement().focus();
262        } else {
263            getElement().addClassName(org.opencms.acacia.client.css.I_CmsLayoutBundle.INSTANCE.form().inActive());
264        }
265        if (active) {
266            fireChangeEvent();
267        }
268
269    }
270
271    /**
272     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setName(java.lang.String)
273     */
274    public void setName(String name) {
275
276        m_textarea.setName(name);
277
278    }
279
280    /**
281     * @see org.opencms.gwt.client.ui.input.form.I_CmsHasPlaceholder#setPlaceholder(java.lang.String)
282     */
283    @Override
284    public void setPlaceholder(String placeholder) {
285
286        m_textarea.setPlaceholder(placeholder);
287    }
288
289    /**
290     * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object)
291     */
292    public void setValue(String value) {
293
294        setValue(value, false);
295    }
296
297    /**
298     * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object, boolean)
299     */
300    public void setValue(String value, boolean fireEvents) {
301
302        // set the saved value to the textArea
303        m_textarea.setFormValueAsString(value);
304        if (fireEvents) {
305            fireChangeEvent();
306        }
307    }
308
309}