All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opencms.gwt.client.ui.input.CmsTextArea Maven / Gradle / Ivy

Go to download

OpenCms is an enterprise-ready, easy to use website content management system based on Java and XML technology. Offering a complete set of features, OpenCms helps content managers worldwide to create and maintain beautiful websites fast and efficiently.

The newest version!
/*
 * This library is part of OpenCms -
 * the Open Source Content Management System
 *
 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * For further information about Alkacon Software, please see the
 * company website: http://www.alkacon.com
 *
 * For further information about OpenCms, please see the
 * project website: http://www.opencms.org
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.opencms.gwt.client.ui.input;

import org.opencms.gwt.client.I_CmsHasInit;
import org.opencms.gwt.client.I_CmsHasResizeOnShow;
import org.opencms.gwt.client.ui.CmsScrollPanel;
import org.opencms.gwt.client.ui.I_CmsAutoHider;
import org.opencms.gwt.client.ui.css.I_CmsInputLayoutBundle;
import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle;
import org.opencms.gwt.client.ui.input.form.CmsWidgetFactoryRegistry;
import org.opencms.gwt.client.ui.input.form.I_CmsFormWidgetFactory;
import org.opencms.gwt.client.util.CmsDomUtil;
import org.opencms.util.CmsStringUtil;

import java.util.Map;

import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.HasFocusHandlers;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.logical.shared.HasResizeHandlers;
import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.TextArea;

import elemental2.dom.HTMLInputElement;
import jsinterop.base.Js;

/**
 * Basic text area widget for forms.

* * @since 8.0.0 * */ public class CmsTextArea extends Composite implements I_CmsFormWidget, I_CmsHasInit, HasValueChangeHandlers, HasResizeHandlers, HasFocusHandlers, I_CmsHasResizeOnShow, I_CmsHasGhostValue { /** The widget type identifier for this widget. */ private static final String WIDGET_TYPE = "textarea"; /** The default rows set. */ int m_defaultRows; /** The fade panel. */ Panel m_fadePanel = new SimplePanel(); /** The root panel containing the other components of this widget. */ Panel m_panel = new FlowPanel(); /** The internal text area widget used by this widget. */ TextArea m_textArea = new TextArea(); /** The container for the text area. */ CmsScrollPanel m_textAreaContainer = GWT.create(CmsScrollPanel.class); /** Overlay to disable the text area. */ private Element m_disabledOverlay; /** The error display for this widget. */ private CmsErrorWidget m_error = new CmsErrorWidget(); /** True if we are currently focused. */ private boolean m_focus; /** The 'ghost value' to display when no value is set. */ private String m_ghostValue; /** The real, logical value which might be different from the value displayed in the internal textarea. */ private String m_realValue = ""; /** A timer to schedule the widget size recalculation. */ private Timer m_updateSizeTimer; /** * Text area widgets for ADE forms.

*/ public CmsTextArea() { super(); initWidget(m_panel); m_panel.setStyleName(I_CmsInputLayoutBundle.INSTANCE.inputCss().textArea()); m_textAreaContainer.addStyleName(I_CmsInputLayoutBundle.INSTANCE.inputCss().textAreaBoxPanel()); m_textArea.setStyleName(I_CmsInputLayoutBundle.INSTANCE.inputCss().textAreaBox()); m_fadePanel.addStyleName(I_CmsInputLayoutBundle.INSTANCE.inputCss().fader()); m_panel.add(m_textAreaContainer); m_textAreaContainer.setResizable(true); m_textAreaContainer.add(m_textArea); m_fadePanel.addDomHandler(new ClickHandler() { public void onClick(ClickEvent event) { m_textArea.setFocus(true); } }, ClickEvent.getType()); m_textArea.addKeyUpHandler(new KeyUpHandler() { @SuppressWarnings("synthetic-access") public void onKeyUp(KeyUpEvent event) { scheduleResize(); actionChangeTextareaValue(m_textArea.getValue()); } }); m_textArea.addValueChangeHandler(new ValueChangeHandler() { @SuppressWarnings("synthetic-access") public void onValueChange(ValueChangeEvent event) { actionChangeTextareaValue(event.getValue()); } }); m_panel.add(m_error); m_textAreaContainer.addStyleName(I_CmsLayoutBundle.INSTANCE.generalCss().cornerAll()); m_textArea.addFocusHandler(new FocusHandler() { @SuppressWarnings("synthetic-access") public void onFocus(FocusEvent event) { m_panel.remove(m_fadePanel); CmsDomUtil.fireFocusEvent(CmsTextArea.this); m_focus = true; updateGhostStyle(); } }); m_textArea.addBlurHandler(new BlurHandler() { @SuppressWarnings("synthetic-access") public void onBlur(BlurEvent event) { showFadePanelIfNeeded(); m_textAreaContainer.scrollToTop(); m_focus = false; updateGhostStyle(); } }); } /** * Initializes this class.

*/ public static void initClass() { // registers a factory for creating new instances of this widget CmsWidgetFactoryRegistry.instance().registerFactory(WIDGET_TYPE, new I_CmsFormWidgetFactory() { public I_CmsFormWidget createWidget(Map widgetParams, Optional defaultValue) { return new CmsTextArea(); } }); } /** * @see com.google.gwt.event.dom.client.HasFocusHandlers#addFocusHandler(com.google.gwt.event.dom.client.FocusHandler) */ public HandlerRegistration addFocusHandler(FocusHandler handler) { return addDomHandler(handler, FocusEvent.getType()); } /** * @see com.google.gwt.event.logical.shared.HasResizeHandlers#addResizeHandler(com.google.gwt.event.logical.shared.ResizeHandler) */ public HandlerRegistration addResizeHandler(ResizeHandler handler) { return m_textAreaContainer.addResizeHandler(handler); } /** * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler) */ public HandlerRegistration addValueChangeHandler(ValueChangeHandler handler) { return addHandler(handler, ValueChangeEvent.getType()); } /** * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#getApparentValue() */ public String getApparentValue() { return getFormValueAsString(); } /** * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#getFieldType() */ public FieldType getFieldType() { return I_CmsFormWidget.FieldType.STRING; } /** * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#getFormValue() */ public Object getFormValue() { return nullToEmpty(m_realValue); } /** * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#getFormValueAsString() */ public String getFormValueAsString() { return (String)getFormValue(); } /** * Gets the cursor position. * * @return the cursor position */ public int getPosition() { HTMLInputElement elem = Js.uncheckedCast(m_textArea.getElement()); // wrong class, but works return elem.selectionStart; } /** * Returns the text contained in the text area.

* * @return the text in the text area */ public String getText() { return m_textArea.getText(); } /** * Returns the textarea of this widget.

* * @return the textarea */ public TextArea getTextArea() { return m_textArea; } /** * Returns the text area container of this widget.

* * @return the text area container */ public CmsScrollPanel getTextAreaContainer() { return m_textAreaContainer; } /** * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#isEnabled() */ public boolean isEnabled() { return m_textArea.isEnabled(); } /** * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#reset() */ public void reset() { m_textArea.setText(""); } /** * @see org.opencms.gwt.client.I_CmsHasResizeOnShow#resizeOnShow() */ public void resizeOnShow() { m_textAreaContainer.onResizeDescendant(); updateContentSize(); showFadePanelIfNeeded(); } /** * Selects all content.

*/ public void selectAll() { m_textArea.selectAll(); } /** * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#setAutoHideParent(org.opencms.gwt.client.ui.I_CmsAutoHider) */ public void setAutoHideParent(I_CmsAutoHider autoHideParent) { // nothing to do } /** * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#setEnabled(boolean) */ public void setEnabled(boolean enabled) { m_textArea.setEnabled(enabled); // hide / show resize handle m_textAreaContainer.setResizable(enabled); if (enabled) { if (m_disabledOverlay != null) { m_disabledOverlay.removeFromParent(); m_disabledOverlay = null; } } else { if (m_disabledOverlay == null) { m_disabledOverlay = DOM.createDiv(); m_disabledOverlay.setClassName(I_CmsInputLayoutBundle.INSTANCE.inputCss().disableTextArea()); m_panel.getElement().appendChild(m_disabledOverlay); } } } /** * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#setErrorMessage(java.lang.String) */ public void setErrorMessage(String errorMessage) { m_error.setText(errorMessage); } /** * Sets or removes focus.

* * @param b true if the text area should be focused */ public void setFocus(boolean b) { m_textArea.setFocus(b); } /** * Sets the value of the widget.

* * @param value the new value */ public void setFormValue(Object value) { setRealValue((String)value); updateGhostStyle(); } /** * @see org.opencms.gwt.client.ui.input.I_CmsFormWidget#setFormValueAsString(java.lang.String) */ public void setFormValueAsString(String newValue) { setFormValue(newValue); } /** * Not used.

* * This widget automatically decides whether it's in ghost mode depending on the real value and ghost value set.

* * @param ghostMode not used */ public void setGhostMode(boolean ghostMode) { // do nothing } /** * Enables or disables the 'ghost mode' style.

* * @param enabled true if 'ghost mode' style should be enabled */ public void setGhostStyleEnabled(boolean enabled) { String styleName = I_CmsInputLayoutBundle.INSTANCE.inputCss().textAreaGhostMode(); if (enabled) { addStyleName(styleName); } else { removeStyleName(styleName); } } /** * @see org.opencms.gwt.client.ui.input.I_CmsHasGhostValue#setGhostValue(java.lang.String, boolean) */ public void setGhostValue(String value, boolean ghostMode) { m_ghostValue = value; updateGhostStyle(); } /** * Sets the name of the input field.

* * @param name of the input field * * */ public void setName(String name) { m_textArea.setName(name); } /** * Sets the cursor position. * * @param position the cursor position */ public void setPosition(int position) { HTMLInputElement elem = Js.uncheckedCast(m_textArea.getElement()); // wrong class, but works elem.setSelectionRange(position, position); } /** * Sets the text area to use a proportional font.

* * @param proportional true to use a proportional font */ public void setProportionalStyle(boolean proportional) { if (proportional) { m_panel.addStyleName(I_CmsInputLayoutBundle.INSTANCE.inputCss().textAreaProportional()); } else { m_panel.removeStyleName(I_CmsInputLayoutBundle.INSTANCE.inputCss().textAreaProportional()); } } /** * Sets the height of this textarea.

* * @param rows the value of rows should be shown */ public void setRows(int rows) { m_defaultRows = rows; double height_scroll = (rows * 17.95) + 8; m_textArea.setVisibleLines(rows); m_textAreaContainer.setHeight(height_scroll + "px"); m_textAreaContainer.setDefaultHeight(height_scroll); m_textAreaContainer.onResizeDescendant(); } /** * Sets the height of this textarea. Especial for the image Gallery.

* * @param rows the value of rows should be shown */ public void setRowsGallery(int rows) { m_defaultRows = rows; double height_scroll = (rows * 17.95) + 8 + 5; m_textArea.setVisibleLines(rows); m_textAreaContainer.setHeight(height_scroll + "px"); m_textAreaContainer.setDefaultHeight(height_scroll); m_textAreaContainer.onResizeDescendant(); } /** * Sets the text in the text area.

* * @param text the new text */ public void setText(String text) { m_textArea.setText(text); } /** * @see com.google.gwt.user.client.ui.Composite#onAttach() */ @Override protected void onAttach() { super.onAttach(); Scheduler.get().scheduleDeferred(new ScheduledCommand() { public void execute() { resizeOnShow(); } }); } /** * Schedules resizing the widget.

*/ protected void scheduleResize() { if (m_updateSizeTimer != null) { m_updateSizeTimer.cancel(); } m_updateSizeTimer = new Timer() { @Override public void run() { updateContentSize(); } }; m_updateSizeTimer.schedule(300); } /** * Shows the fade panel if the text area content exceeds the visible area.

*/ protected void showFadePanelIfNeeded() { if (m_defaultRows < m_textArea.getVisibleLines()) { m_panel.add(m_fadePanel); } } /** * Updates the text area height according to the current text content.

*/ protected void updateContentSize() { // The scrolling should be done by the CmsScrollPanel and not by the text area, // so we try to make the text area itself as big as its content here. int offsetHeight = m_textArea.getOffsetHeight(); int origRows = m_textArea.getVisibleLines(); // sanity check: don't do anything, if the measured height doesn't make any sense, e.g. if element is not attached if (offsetHeight > 5) { int scrollPosition = m_textAreaContainer.getVerticalScrollPosition(); Element textareaElem = m_textArea.getElement(); int rows = Math.max(0, m_defaultRows - 1); // we add 1 to it later, and the sum should be at least 1 and at least the default row number int scrollHeight; int prevOffsetHeight = -1; do { rows += 1; m_textArea.setVisibleLines(rows); scrollHeight = textareaElem.getScrollHeight(); offsetHeight = textareaElem.getOffsetHeight(); if (offsetHeight <= prevOffsetHeight) { // Increasing the number of rows should normally increase the offset height. // If it doesn't, e.g. because of CSS rules limiting the text area height, there is no point in continuing with the loop break; } prevOffsetHeight = offsetHeight; } while (offsetHeight < scrollHeight); m_textAreaContainer.setVerticalScrollPosition(scrollPosition); if (origRows != rows) { m_textAreaContainer.onResizeDescendant(); } } } /** * This method is called when the value of the internal textarea changes.

* * @param value the textarea value */ private void actionChangeTextareaValue(String value) { if (m_focus) { setRealValue(value); updateGhostStyle(); } } /** * Converts null to an empty string, leaves other strings unchanged.

* * @param s the input string * @return the input string if it was not null, otherwise the empty string */ private String nullToEmpty(String s) { if (s == null) { return ""; } return s; } /** * Sets the 'real' (logical) value.

* * @param value the real value */ private void setRealValue(String value) { if (!Objects.equal(value, m_realValue)) { m_realValue = value; ValueChangeEvent.fire(this, value); } } /** * Updates the styling and content of the internal text area based on the real value, the ghost value, and whether * it has focus. */ private void updateGhostStyle() { if (CmsStringUtil.isEmpty(m_realValue)) { if (CmsStringUtil.isEmpty(m_ghostValue)) { updateTextArea(m_realValue); return; } if (!m_focus) { setGhostStyleEnabled(true); updateTextArea(m_ghostValue); } else { // don't show ghost mode while focused setGhostStyleEnabled(false); } } else { setGhostStyleEnabled(false); updateTextArea(m_realValue); } } /** * Updates the content of the internal textarea.

* * @param value the new content */ private void updateTextArea(String value) { String oldValue = m_textArea.getValue(); if (!oldValue.equals(value)) { int l1 = oldValue.split("\n").length; int l2 = value.split("\n").length; m_textArea.setValue(value); if (l1 != l2) { scheduleResize(); } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy