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