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_CmsLayoutBundle; 031import org.opencms.acacia.client.widgets.CmsTypografUtil.Typograf; 032import org.opencms.gwt.client.util.CmsDomUtil; 033import org.opencms.gwt.shared.CmsGwtConstants; 034import org.opencms.gwt.shared.CmsGwtLog; 035 036import java.util.Objects; 037 038import com.google.gwt.core.client.GWT; 039import com.google.gwt.dom.client.Element; 040import com.google.gwt.event.dom.client.BlurEvent; 041import com.google.gwt.event.dom.client.ClickEvent; 042import com.google.gwt.event.dom.client.FocusEvent; 043import com.google.gwt.event.dom.client.FocusHandler; 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.uibinder.client.UiBinder; 048import com.google.gwt.uibinder.client.UiField; 049import com.google.gwt.uibinder.client.UiHandler; 050import com.google.gwt.user.client.ui.Composite; 051import com.google.gwt.user.client.ui.FocusPanel; 052import com.google.gwt.user.client.ui.HTMLPanel; 053import com.google.gwt.user.client.ui.TextBox; 054 055import elemental2.core.Global; 056import elemental2.dom.HTMLInputElement; 057import jsinterop.base.Js; 058import jsinterop.base.JsPropertyMap; 059 060/** 061 * Provides a display only widget, for use on a widget dialog.<p> 062 * 063 * */ 064public class CmsTextboxWidget extends Composite implements I_CmsEditWidget { 065 066 /** 067 * The UI binder interface.<p> 068 */ 069 interface I_CmsTextboxWidgetUiBinder extends UiBinder<HTMLPanel, CmsTextboxWidget> { 070 // nothing to do 071 } 072 073 /** The UI binder instance. */ 074 private static I_CmsTextboxWidgetUiBinder uiBinder = GWT.create(I_CmsTextboxWidgetUiBinder.class); 075 076 /** The fader of this widget. */ 077 @UiField 078 FocusPanel m_fadePanel; 079 080 /**The main panel of this widget. */ 081 HTMLPanel m_mainPanel; 082 083 /** The input test area.*/ 084 @UiField 085 TextBox m_textbox; 086 087 /** The token to control activation. */ 088 private boolean m_active = true; 089 090 /** The previous value. */ 091 private String m_previousValue; 092 093 /** Typograf instance used for typography, if configured. */ 094 private Typograf m_typograf; 095 096 /** The value changed handler initialized flag. */ 097 private boolean m_valueChangeHandlerInitialized; 098 099 /** 100 * Creates a new display widget.<p> 101 * 102 * @param config the widget configuration 103 */ 104 public CmsTextboxWidget(String config) { 105 106 m_mainPanel = uiBinder.createAndBindUi(this); 107 if (config != null) { 108 try { 109 JsPropertyMap<String> configMap = Js.cast(Global.JSON.parse(config)); 110 String locale = configMap.get(CmsGwtConstants.JSON_INPUT_LOCALE); 111 String typograf = configMap.get(CmsGwtConstants.JSON_INPUT_TYPOGRAF); 112 boolean typografEnabled = "auto".equals(typograf); 113 if ((locale != null) && typografEnabled && Typograf.hasLocale(locale)) { 114 m_typograf = CmsTypografUtil.createLiveInstance(locale); 115 } 116 } catch (Exception e) { 117 CmsGwtLog.log(e.getMessage()); 118 } 119 } 120 121 initWidget(m_mainPanel); 122 } 123 124 /** 125 * @see com.google.gwt.event.dom.client.HasFocusHandlers#addFocusHandler(com.google.gwt.event.dom.client.FocusHandler) 126 */ 127 public HandlerRegistration addFocusHandler(FocusHandler handler) { 128 129 return addDomHandler(handler, FocusEvent.getType()); 130 } 131 132 /** 133 * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler) 134 */ 135 public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) { 136 137 // Initialization code 138 if (!m_valueChangeHandlerInitialized) { 139 m_valueChangeHandlerInitialized = true; 140 HTMLInputElement inputElem = Js.cast(m_textbox.getElement()); 141 inputElem.addEventListener("input", event -> { 142 if (m_typograf != null) { 143 try { 144 String oldValue = inputElem.value; 145 String newValue = CmsTypografUtil.transform(m_typograf, oldValue); 146 if (!Objects.equals(oldValue, newValue)) { 147 int pos = inputElem.selectionStart; 148 inputElem.value = newValue; 149 inputElem.setSelectionRange(pos, pos); 150 } 151 } catch (Exception e) { 152 CmsGwtLog.log(e.getMessage()); 153 } 154 } 155 fireValueChange(false); 156 }); 157 } 158 return addHandler(handler, ValueChangeEvent.getType()); 159 } 160 161 /** 162 * Represents a value change event.<p> 163 * 164 */ 165 public void fireChangeEvent() { 166 167 String result = ""; 168 if (m_textbox.getText() != null) { 169 result = m_textbox.getText(); 170 } 171 172 ValueChangeEvent.fire(this, result); 173 } 174 175 /** 176 * @see com.google.gwt.user.client.ui.HasValue#getValue() 177 */ 178 public String getValue() { 179 180 return m_textbox.getText(); 181 } 182 183 /** 184 * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#isActive() 185 */ 186 public boolean isActive() { 187 188 return m_active; 189 } 190 191 /** 192 * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#onAttachWidget() 193 */ 194 public void onAttachWidget() { 195 196 super.onAttach(); 197 } 198 199 /** 200 * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#owns(com.google.gwt.dom.client.Element) 201 */ 202 public boolean owns(Element element) { 203 204 // TODO implement this in case we want the delete behavior for optional fields 205 return false; 206 207 } 208 209 /** 210 * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setActive(boolean) 211 */ 212 public void setActive(boolean active) { 213 214 if (m_active == active) { 215 return; 216 } 217 218 m_active = active; 219 if (m_active) { 220 getElement().removeClassName(I_CmsLayoutBundle.INSTANCE.form().inActive()); 221 getElement().focus(); 222 } else { 223 getElement().addClassName(I_CmsLayoutBundle.INSTANCE.form().inActive()); 224 } 225 if (active) { 226 fireChangeEvent(); 227 } 228 } 229 230 /** 231 * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setName(java.lang.String) 232 */ 233 public void setName(String name) { 234 235 m_textbox.setName(name); 236 237 } 238 239 /** 240 * @see com.google.gwt.user.client.ui.UIObject#setTitle(java.lang.String) 241 */ 242 @Override 243 public void setTitle(String title) { 244 245 if ((title.length() * 6.88) > m_mainPanel.getOffsetWidth()) { 246 m_mainPanel.getElement().setTitle(title); 247 } else { 248 m_mainPanel.getElement().setTitle(""); 249 } 250 } 251 252 /** 253 * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object) 254 */ 255 public void setValue(String value) { 256 257 m_textbox.setText(value); 258 } 259 260 /** 261 * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object, boolean) 262 */ 263 public void setValue(String value, boolean fireEvents) { 264 265 // set the saved value to the textArea 266 m_textbox.setText(value); 267 m_previousValue = value; 268 if (fireEvents) { 269 fireChangeEvent(); 270 } 271 } 272 273 /** 274 * Fires the value change event, if the value has changed.<p> 275 * 276 * @param force <code>true</code> to force firing the event, not regarding an actually changed value 277 */ 278 protected void fireValueChange(boolean force) { 279 280 String currentValue = getValue(); 281 if (force || !currentValue.equals(m_previousValue)) { 282 m_previousValue = currentValue; 283 ValueChangeEvent.fire(this, currentValue); 284 } 285 } 286 287 /** 288 * Handles fade panel clicks.<p> 289 * 290 * @param event the click event 291 */ 292 @UiHandler("m_fadePanel") 293 void onFadeClick(ClickEvent event) { 294 295 m_textbox.setFocus(true); 296 m_textbox.setCursorPos(m_textbox.getText().length()); 297 } 298 299 /** 300 * Handles text box blur.<p> 301 * 302 * @param event the blur event 303 */ 304 @UiHandler("m_textbox") 305 void onTextboxBlur(BlurEvent event) { 306 307 m_mainPanel.add(m_fadePanel); 308 setTitle(m_textbox.getText()); 309 } 310 311 /** 312 * Handles text box focus.<p> 313 * 314 * @param event the focus event 315 */ 316 @UiHandler("m_textbox") 317 void onTextboxFocus(FocusEvent event) { 318 319 m_mainPanel.remove(m_fadePanel); 320 setTitle(""); 321 CmsDomUtil.fireFocusEvent(this); 322 } 323 324 /** 325 * Handles text box value change.<p> 326 * 327 * @param event the value change event 328 */ 329 @UiHandler("m_textbox") 330 void onTextboxValueChange(ValueChangeEvent<String> event) { 331 332 fireValueChange(false); 333 } 334 335}