You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

VTextField.java 9.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. /*
  2. @ITMillApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.terminal.gwt.client.ui;
  5. import com.google.gwt.event.dom.client.BlurEvent;
  6. import com.google.gwt.event.dom.client.BlurHandler;
  7. import com.google.gwt.event.dom.client.ChangeEvent;
  8. import com.google.gwt.event.dom.client.ChangeHandler;
  9. import com.google.gwt.event.dom.client.FocusEvent;
  10. import com.google.gwt.event.dom.client.FocusHandler;
  11. import com.google.gwt.user.client.Command;
  12. import com.google.gwt.user.client.DOM;
  13. import com.google.gwt.user.client.DeferredCommand;
  14. import com.google.gwt.user.client.Element;
  15. import com.google.gwt.user.client.Event;
  16. import com.google.gwt.user.client.ui.TextBoxBase;
  17. import com.vaadin.terminal.gwt.client.ApplicationConnection;
  18. import com.vaadin.terminal.gwt.client.BrowserInfo;
  19. import com.vaadin.terminal.gwt.client.Paintable;
  20. import com.vaadin.terminal.gwt.client.UIDL;
  21. import com.vaadin.terminal.gwt.client.Util;
  22. import com.vaadin.terminal.gwt.client.VTooltip;
  23. /**
  24. * This class represents a basic text input field with one row.
  25. *
  26. * @author IT Mill Ltd.
  27. *
  28. */
  29. public class VTextField extends TextBoxBase implements Paintable, Field,
  30. ChangeHandler, FocusHandler, BlurHandler {
  31. /**
  32. * The input node CSS classname.
  33. */
  34. public static final String CLASSNAME = "v-textfield";
  35. /**
  36. * This CSS classname is added to the input node on hover.
  37. */
  38. public static final String CLASSNAME_FOCUS = "focus";
  39. protected String id;
  40. protected ApplicationConnection client;
  41. private String valueBeforeEdit = null;
  42. private boolean immediate = false;
  43. private int extraHorizontalPixels = -1;
  44. private int extraVerticalPixels = -1;
  45. private int maxLength = -1;
  46. private static final String CLASSNAME_PROMPT = "prompt";
  47. private static final String ATTR_INPUTPROMPT = "prompt";
  48. public static final String FOCUS_EVENT_IDENTIFIER = "focus";
  49. public static final String BLUR_EVENT_IDENTIFIER = "blur";
  50. private String inputPrompt = null;
  51. private boolean prompting = false;
  52. public VTextField() {
  53. this(DOM.createInputText());
  54. }
  55. protected VTextField(Element node) {
  56. super(node);
  57. if (BrowserInfo.get().getIEVersion() > 0
  58. && BrowserInfo.get().getIEVersion() < 8) {
  59. // Fixes IE margin problem (#2058)
  60. DOM.setStyleAttribute(node, "marginTop", "-1px");
  61. DOM.setStyleAttribute(node, "marginBottom", "-1px");
  62. }
  63. setStyleName(CLASSNAME);
  64. addChangeHandler(this);
  65. addFocusHandler(this);
  66. addBlurHandler(this);
  67. sinkEvents(VTooltip.TOOLTIP_EVENTS);
  68. }
  69. @Override
  70. public void onBrowserEvent(Event event) {
  71. super.onBrowserEvent(event);
  72. if (client != null) {
  73. client.handleTooltipEvent(event, this);
  74. }
  75. }
  76. public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
  77. this.client = client;
  78. id = uidl.getId();
  79. if (client.updateComponent(this, uidl, true)) {
  80. return;
  81. }
  82. if (uidl.getBooleanAttribute("readonly")) {
  83. setReadOnly(true);
  84. } else {
  85. setReadOnly(false);
  86. }
  87. inputPrompt = uidl.getStringAttribute(ATTR_INPUTPROMPT);
  88. setMaxLength(uidl.hasAttribute("maxLength") ? uidl
  89. .getIntAttribute("maxLength") : -1);
  90. immediate = uidl.getBooleanAttribute("immediate");
  91. if (uidl.hasAttribute("cols")) {
  92. setColumns(new Integer(uidl.getStringAttribute("cols")).intValue());
  93. }
  94. String text = uidl.hasVariable("text") ? uidl.getStringVariable("text")
  95. : null;
  96. setPrompting(inputPrompt != null && focusedTextField != this
  97. && (text == null || text.equals("")));
  98. final String fieldValue;
  99. if (prompting) {
  100. fieldValue = inputPrompt;
  101. addStyleDependentName(CLASSNAME_PROMPT);
  102. } else {
  103. fieldValue = text;
  104. removeStyleDependentName(CLASSNAME_PROMPT);
  105. }
  106. if (BrowserInfo.get().isGecko()) {
  107. /*
  108. * Gecko is really sluggish when updating input attached to dom.
  109. * Some optimizations seems to work much better in Gecko if we
  110. * update the actual content lazily when the rest of the DOM has
  111. * stabilized. In tests, about ten times better performance is
  112. * achieved with this optimization. See for eg. #2898
  113. */
  114. DeferredCommand.addCommand(new Command() {
  115. public void execute() {
  116. setText(fieldValue);
  117. }
  118. });
  119. } else {
  120. setText(fieldValue);
  121. }
  122. valueBeforeEdit = uidl.getStringVariable("text");
  123. }
  124. private void setMaxLength(int newMaxLength) {
  125. if (newMaxLength > 0) {
  126. maxLength = newMaxLength;
  127. if (getElement().getTagName().toLowerCase().equals("textarea")) {
  128. // NOP no maxlength property for textarea
  129. } else {
  130. getElement().setPropertyInt("maxLength", maxLength);
  131. }
  132. } else if (maxLength != -1) {
  133. if (getElement().getTagName().toLowerCase().equals("textarea")) {
  134. // NOP no maxlength property for textarea
  135. } else {
  136. getElement().setAttribute("maxlength", "");
  137. }
  138. maxLength = -1;
  139. }
  140. }
  141. protected int getMaxLength() {
  142. return maxLength;
  143. }
  144. public void onChange(ChangeEvent event) {
  145. if (client != null && id != null) {
  146. String newText = getText();
  147. if (!prompting && newText != null
  148. && !newText.equals(valueBeforeEdit)) {
  149. client.updateVariable(id, "text", getText(), immediate);
  150. valueBeforeEdit = newText;
  151. }
  152. }
  153. }
  154. private static VTextField focusedTextField;
  155. public static void flushChangesFromFocusedTextField() {
  156. if (focusedTextField != null) {
  157. focusedTextField.onChange(null);
  158. }
  159. }
  160. public void onFocus(FocusEvent event) {
  161. addStyleDependentName(CLASSNAME_FOCUS);
  162. if (prompting) {
  163. setText("");
  164. removeStyleDependentName(CLASSNAME_PROMPT);
  165. if (BrowserInfo.get().isIE6()) {
  166. // IE6 does not show the cursor when tabbing into the field
  167. setCursorPos(0);
  168. }
  169. }
  170. focusedTextField = this;
  171. if (client.hasEventListeners(this, FOCUS_EVENT_IDENTIFIER)) {
  172. client.updateVariable(client.getPid(this), FOCUS_EVENT_IDENTIFIER,
  173. "", true);
  174. }
  175. }
  176. public void onBlur(BlurEvent event) {
  177. removeStyleDependentName(CLASSNAME_FOCUS);
  178. focusedTextField = null;
  179. String text = getText();
  180. setPrompting(inputPrompt != null && (text == null || "".equals(text)));
  181. if (prompting) {
  182. setText(inputPrompt);
  183. addStyleDependentName(CLASSNAME_PROMPT);
  184. }
  185. onChange(null);
  186. if (client.hasEventListeners(this, BLUR_EVENT_IDENTIFIER)) {
  187. client.updateVariable(client.getPid(this), BLUR_EVENT_IDENTIFIER,
  188. "", true);
  189. }
  190. }
  191. private void setPrompting(boolean prompting) {
  192. this.prompting = prompting;
  193. }
  194. public void setColumns(int columns) {
  195. setColumns(getElement(), columns);
  196. }
  197. private native void setColumns(Element e, int c)
  198. /*-{
  199. try {
  200. switch(e.tagName.toLowerCase()) {
  201. case "input":
  202. //e.size = c;
  203. e.style.width = c+"em";
  204. break;
  205. case "textarea":
  206. //e.cols = c;
  207. e.style.width = c+"em";
  208. break;
  209. default:;
  210. }
  211. } catch (e) {}
  212. }-*/;
  213. /**
  214. * @return space used by components paddings and borders
  215. */
  216. private int getExtraHorizontalPixels() {
  217. if (extraHorizontalPixels < 0) {
  218. detectExtraSizes();
  219. }
  220. return extraHorizontalPixels;
  221. }
  222. /**
  223. * @return space used by components paddings and borders
  224. */
  225. private int getExtraVerticalPixels() {
  226. if (extraVerticalPixels < 0) {
  227. detectExtraSizes();
  228. }
  229. return extraVerticalPixels;
  230. }
  231. /**
  232. * Detects space used by components paddings and borders. Used when
  233. * relational size are used.
  234. */
  235. private void detectExtraSizes() {
  236. Element clone = Util.cloneNode(getElement(), false);
  237. DOM.setElementAttribute(clone, "id", "");
  238. DOM.setStyleAttribute(clone, "visibility", "hidden");
  239. DOM.setStyleAttribute(clone, "position", "absolute");
  240. // due FF3 bug set size to 10px and later subtract it from extra pixels
  241. DOM.setStyleAttribute(clone, "width", "10px");
  242. DOM.setStyleAttribute(clone, "height", "10px");
  243. DOM.appendChild(DOM.getParent(getElement()), clone);
  244. extraHorizontalPixels = DOM.getElementPropertyInt(clone, "offsetWidth") - 10;
  245. extraVerticalPixels = DOM.getElementPropertyInt(clone, "offsetHeight") - 10;
  246. DOM.removeChild(DOM.getParent(getElement()), clone);
  247. }
  248. @Override
  249. public void setHeight(String height) {
  250. if (height.endsWith("px")) {
  251. int h = Integer.parseInt(height.substring(0, height.length() - 2));
  252. h -= getExtraVerticalPixels();
  253. if (h < 0) {
  254. h = 0;
  255. }
  256. super.setHeight(h + "px");
  257. } else {
  258. super.setHeight(height);
  259. }
  260. }
  261. @Override
  262. public void setWidth(String width) {
  263. if (width.endsWith("px")) {
  264. int w = Integer.parseInt(width.substring(0, width.length() - 2));
  265. w -= getExtraHorizontalPixels();
  266. if (w < 0) {
  267. w = 0;
  268. }
  269. super.setWidth(w + "px");
  270. } else {
  271. super.setWidth(width);
  272. }
  273. }
  274. }