rubyjs 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. data/README +128 -0
  2. data/Rakefile +9 -0
  3. data/bin/rubyjs +140 -0
  4. data/examples/ex1/Rakefile +7 -0
  5. data/examples/ex1/ex1.js +771 -0
  6. data/examples/ex1/ex1.rb +42 -0
  7. data/examples/ex1/index.html +7 -0
  8. data/examples/hw/Rakefile +9 -0
  9. data/examples/hw/hw.js +635 -0
  10. data/examples/hw/hw.rb +7 -0
  11. data/examples/hw/index.html +7 -0
  12. data/patches/parse_tree.rb.diff +34 -0
  13. data/rubyjs.gemspec +24 -0
  14. data/src/rubyjs.rb +4 -0
  15. data/src/rubyjs/code_generator.rb +474 -0
  16. data/src/rubyjs/compiler.rb +2007 -0
  17. data/src/rubyjs/debug_name_generator.rb +75 -0
  18. data/src/rubyjs/encoder.rb +171 -0
  19. data/src/rubyjs/eval_into.rb +59 -0
  20. data/src/rubyjs/lib/core.rb +1008 -0
  21. data/src/rubyjs/lib/json.rb +101 -0
  22. data/src/rubyjs/model.rb +287 -0
  23. data/src/rubyjs/name_generator.rb +71 -0
  24. data/src/rwt/AbsolutePanel.rb +161 -0
  25. data/src/rwt/DOM.Konqueror.rb +89 -0
  26. data/src/rwt/DOM.Opera.rb +65 -0
  27. data/src/rwt/DOM.rb +1044 -0
  28. data/src/rwt/Event.Opera.rb +35 -0
  29. data/src/rwt/Event.rb +429 -0
  30. data/src/rwt/HTTPRequest.IE6.rb +5 -0
  31. data/src/rwt/HTTPRequest.rb +74 -0
  32. data/src/rwt/Label.rb +164 -0
  33. data/src/rwt/Panel.rb +90 -0
  34. data/src/rwt/RootPanel.rb +16 -0
  35. data/src/rwt/UIObject.rb +495 -0
  36. data/src/rwt/Widget.rb +193 -0
  37. data/src/rwt/ported-from/AbsolutePanel.java +158 -0
  38. data/src/rwt/ported-from/DOM.java +571 -0
  39. data/src/rwt/ported-from/DOMImpl.java +426 -0
  40. data/src/rwt/ported-from/DOMImplOpera.java +82 -0
  41. data/src/rwt/ported-from/DOMImplStandard.java +234 -0
  42. data/src/rwt/ported-from/HTTPRequest.java +81 -0
  43. data/src/rwt/ported-from/HTTPRequestImpl.java +103 -0
  44. data/src/rwt/ported-from/Label.java +163 -0
  45. data/src/rwt/ported-from/Panel.java +99 -0
  46. data/src/rwt/ported-from/UIObject.java +614 -0
  47. data/src/rwt/ported-from/Widget.java +221 -0
  48. data/test/benchmark/bm_call_conv1.js +16 -0
  49. data/test/benchmark/bm_call_conv2.js +14 -0
  50. data/test/benchmark/bm_var_acc1.js +13 -0
  51. data/test/benchmark/bm_var_acc2.js +11 -0
  52. data/test/benchmark/bm_vm1_block.js +15 -0
  53. data/test/benchmark/bm_vm1_block.rb +15 -0
  54. data/test/benchmark/bm_vm1_const.js +13 -0
  55. data/test/benchmark/bm_vm1_const.rb +13 -0
  56. data/test/benchmark/bm_vm1_ensure.js +17 -0
  57. data/test/benchmark/bm_vm1_ensure.rb +15 -0
  58. data/test/benchmark/common.js +4 -0
  59. data/test/benchmark/common.rb +5 -0
  60. data/test/benchmark/params.yaml +7 -0
  61. data/test/browser.test.html +4059 -0
  62. data/test/browser.test.js +3225 -0
  63. data/test/common.Browser.rb +13 -0
  64. data/test/common.rb +8 -0
  65. data/test/gen_browser_test_suite.rb +129 -0
  66. data/test/gen_test_suite.rb +41 -0
  67. data/test/run_benchs.rb +58 -0
  68. data/test/run_tests.rb +22 -0
  69. data/test/test_args.rb +24 -0
  70. data/test/test_array.rb +26 -0
  71. data/test/test_case.rb +35 -0
  72. data/test/test_class.rb +55 -0
  73. data/test/test_eql.rb +9 -0
  74. data/test/test_exception.rb +61 -0
  75. data/test/test_expr.rb +12 -0
  76. data/test/test_hash.rb +29 -0
  77. data/test/test_if.rb +28 -0
  78. data/test/test_inspect.rb +10 -0
  79. data/test/test_lebewesen.rb +39 -0
  80. data/test/test_massign.rb +66 -0
  81. data/test/test_new.rb +12 -0
  82. data/test/test_range.rb +53 -0
  83. data/test/test_regexp.rb +22 -0
  84. data/test/test_send.rb +65 -0
  85. data/test/test_simple_output.rb +5 -0
  86. data/test/test_splat.rb +21 -0
  87. data/test/test_string.rb +51 -0
  88. data/test/test_yield.rb +152 -0
  89. data/utils/js/Makefile +9 -0
  90. data/utils/js/RunScript.class +0 -0
  91. data/utils/js/RunScript.java +73 -0
  92. data/utils/js/js.jar +0 -0
  93. data/utils/js/run.sh +3 -0
  94. data/utils/jsc/Makefile +7 -0
  95. data/utils/jsc/README +3 -0
  96. data/utils/jsc/RunScript.c +93 -0
  97. data/utils/jsc/run.sh +15 -0
  98. data/utils/yuicompressor/README +1 -0
  99. data/utils/yuicompressor/yuicompressor-2.2.5.jar +0 -0
  100. data/vendor/ParseTree-1.7.1-patched/History.txt +217 -0
  101. data/vendor/ParseTree-1.7.1-patched/Manifest.txt +22 -0
  102. data/vendor/ParseTree-1.7.1-patched/README.txt +110 -0
  103. data/vendor/ParseTree-1.7.1-patched/Rakefile +41 -0
  104. data/vendor/ParseTree-1.7.1-patched/bin/parse_tree_abc +89 -0
  105. data/vendor/ParseTree-1.7.1-patched/bin/parse_tree_audit +28 -0
  106. data/vendor/ParseTree-1.7.1-patched/bin/parse_tree_deps +62 -0
  107. data/vendor/ParseTree-1.7.1-patched/bin/parse_tree_show +49 -0
  108. data/vendor/ParseTree-1.7.1-patched/demo/printer.rb +20 -0
  109. data/vendor/ParseTree-1.7.1-patched/lib/composite_sexp_processor.rb +49 -0
  110. data/vendor/ParseTree-1.7.1-patched/lib/parse_tree.rb +1013 -0
  111. data/vendor/ParseTree-1.7.1-patched/lib/sexp.rb +235 -0
  112. data/vendor/ParseTree-1.7.1-patched/lib/sexp_processor.rb +330 -0
  113. data/vendor/ParseTree-1.7.1-patched/lib/unique.rb +15 -0
  114. data/vendor/ParseTree-1.7.1-patched/test/pt_testcase.rb +1221 -0
  115. data/vendor/ParseTree-1.7.1-patched/test/something.rb +53 -0
  116. data/vendor/ParseTree-1.7.1-patched/test/test_all.rb +13 -0
  117. data/vendor/ParseTree-1.7.1-patched/test/test_composite_sexp_processor.rb +69 -0
  118. data/vendor/ParseTree-1.7.1-patched/test/test_parse_tree.rb +216 -0
  119. data/vendor/ParseTree-1.7.1-patched/test/test_sexp.rb +291 -0
  120. data/vendor/ParseTree-1.7.1-patched/test/test_sexp_processor.rb +244 -0
  121. data/vendor/ParseTree-1.7.1-patched/validate.sh +31 -0
  122. data/vendor/ParseTree-1.7.1/History.txt +217 -0
  123. data/vendor/ParseTree-1.7.1/Manifest.txt +22 -0
  124. data/vendor/ParseTree-1.7.1/README.txt +110 -0
  125. data/vendor/ParseTree-1.7.1/Rakefile +41 -0
  126. data/vendor/ParseTree-1.7.1/bin/parse_tree_abc +89 -0
  127. data/vendor/ParseTree-1.7.1/bin/parse_tree_audit +28 -0
  128. data/vendor/ParseTree-1.7.1/bin/parse_tree_deps +62 -0
  129. data/vendor/ParseTree-1.7.1/bin/parse_tree_show +49 -0
  130. data/vendor/ParseTree-1.7.1/demo/printer.rb +20 -0
  131. data/vendor/ParseTree-1.7.1/lib/composite_sexp_processor.rb +49 -0
  132. data/vendor/ParseTree-1.7.1/lib/parse_tree.rb +1004 -0
  133. data/vendor/ParseTree-1.7.1/lib/sexp.rb +235 -0
  134. data/vendor/ParseTree-1.7.1/lib/sexp_processor.rb +330 -0
  135. data/vendor/ParseTree-1.7.1/lib/unique.rb +15 -0
  136. data/vendor/ParseTree-1.7.1/test/pt_testcase.rb +1221 -0
  137. data/vendor/ParseTree-1.7.1/test/something.rb +53 -0
  138. data/vendor/ParseTree-1.7.1/test/test_all.rb +13 -0
  139. data/vendor/ParseTree-1.7.1/test/test_composite_sexp_processor.rb +69 -0
  140. data/vendor/ParseTree-1.7.1/test/test_parse_tree.rb +216 -0
  141. data/vendor/ParseTree-1.7.1/test/test_sexp.rb +291 -0
  142. data/vendor/ParseTree-1.7.1/test/test_sexp_processor.rb +244 -0
  143. data/vendor/ParseTree-1.7.1/validate.sh +31 -0
  144. metadata +230 -0
@@ -0,0 +1,99 @@
1
+ /*
2
+ * Copyright 2006 Google Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5
+ * use this file except in compliance with the License. You may obtain a copy of
6
+ * the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ * License for the specific language governing permissions and limitations under
14
+ * the License.
15
+ */
16
+ package com.google.gwt.user.client.ui;
17
+
18
+ import com.google.gwt.user.client.DOM;
19
+ import com.google.gwt.user.client.Element;
20
+
21
+ import java.util.Iterator;
22
+
23
+ /**
24
+ * Abstract base class for all panels, which are widgets that can contain other
25
+ * widgets.
26
+ */
27
+ public abstract class Panel extends Widget implements HasWidgets {
28
+
29
+ public void add(Widget w) {
30
+ throw new UnsupportedOperationException("This panel does not support no-arg add()");
31
+ }
32
+
33
+ public void clear() {
34
+ Iterator it = iterator();
35
+ while (it.hasNext()) {
36
+ it.next();
37
+ it.remove();
38
+ }
39
+ }
40
+
41
+ /**
42
+ * This method must be called as part of the add method of any panel. It
43
+ * ensures that the Widget's parent is set properly, and that it is removed
44
+ * from any existing parent widget. It also attaches the child widget's
45
+ * DOM element to its new container, ensuring that this process occurs in the
46
+ * right order.
47
+ *
48
+ * @param w the widget to be adopted
49
+ * @param container the element within which it will be contained
50
+ */
51
+ protected void adopt(Widget w, Element container) {
52
+ // Remove the widget from its current parent, if any.
53
+ w.removeFromParent();
54
+
55
+ // Attach it at the DOM and GWT levels.
56
+ if (container != null) {
57
+ DOM.appendChild(container, w.getElement());
58
+ }
59
+ w.setParent(this);
60
+ }
61
+
62
+ /**
63
+ * This method must be called whenever a Widget is removed. It ensures that
64
+ * the Widget's parent is cleared.
65
+ *
66
+ * @param w the widget to be disowned
67
+ */
68
+ protected void disown(Widget w) {
69
+ // Only disown it if it's actually contained in this panel.
70
+ if (w.getParent() != this) {
71
+ throw new IllegalArgumentException("w is not a child of this panel");
72
+ }
73
+
74
+ // Remove it at the DOM and GWT levels.
75
+ Element elem = w.getElement();
76
+ w.setParent(null);
77
+ DOM.removeChild(DOM.getParent(elem), elem);
78
+ }
79
+
80
+ protected void onAttach() {
81
+ super.onAttach();
82
+
83
+ // Ensure that all child widgets are attached.
84
+ for (Iterator it = iterator(); it.hasNext();) {
85
+ Widget child = (Widget) it.next();
86
+ child.onAttach();
87
+ }
88
+ }
89
+
90
+ protected void onDetach() {
91
+ super.onDetach();
92
+
93
+ // Ensure that all child widgets are detached.
94
+ for (Iterator it = iterator(); it.hasNext();) {
95
+ Widget child = (Widget) it.next();
96
+ child.onDetach();
97
+ }
98
+ }
99
+ }
@@ -0,0 +1,614 @@
1
+ /*
2
+ * Copyright 2007 Google Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5
+ * use this file except in compliance with the License. You may obtain a copy of
6
+ * the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ * License for the specific language governing permissions and limitations under
14
+ * the License.
15
+ */
16
+ package com.google.gwt.user.client.ui;
17
+
18
+ import com.google.gwt.user.client.DOM;
19
+ import com.google.gwt.user.client.Element;
20
+
21
+ /**
22
+ * The superclass for all user-interface objects. It simply wraps a DOM element,
23
+ * and cannot receive events. Most interesting user-interface classes derive
24
+ * from {@link com.google.gwt.user.client.ui.Widget}.
25
+ *
26
+ * <h3>Styling With CSS</h3>
27
+ * <p>
28
+ * All <code>UIObject</code> objects can be styled using CSS. Style names that
29
+ * are specified programmatically in Java source are implicitly associated with
30
+ * CSS style rules. In terms of HTML and CSS, a GWT style name is the element's
31
+ * CSS "class". By convention, GWT style names are of the form
32
+ * <code>[project]-[widget]</code>.
33
+ * </p>
34
+ *
35
+ * <p>
36
+ * For example, the {@link Button} widget has the style name
37
+ * <code>gwt-Button</code>, meaning that within the <code>Button</code>
38
+ * constructor, the following call occurs:
39
+ *
40
+ * <pre class="code">
41
+ * setStyleName("gwt-Button");</pre>
42
+ *
43
+ * A corresponding CSS style rule can then be written as follows:
44
+ *
45
+ * <pre class="code">
46
+ * // Example of how you might choose to style a Button widget
47
+ * .gwt-Button {
48
+ * background-color: yellow;
49
+ * color: black;
50
+ * font-size: 24pt;
51
+ * }</pre>
52
+ *
53
+ * Note the dot prefix in the CSS style rule. This syntax is called a <a
54
+ * href="http://www.w3.org/TR/REC-CSS2/selector.html#class-html">CSS class
55
+ * selector</a>.
56
+ * </p>
57
+ *
58
+ * <h3>Style Name Specifics</h3>
59
+ * <p>
60
+ * Every <code>UIObject</code> has a <i>primary style name</i> that
61
+ * identifies the key CSS style rule that should always be applied to it. Use
62
+ * {@link #setStyleName(String)} to specify an object's primary style name. In
63
+ * most cases, the primary style name is set in a widget's constructor and never
64
+ * changes again during execution. In the case that no primary style name is
65
+ * specified, it defaults to <code>gwt-nostyle</code>.
66
+ * </p>
67
+ *
68
+ * <p>
69
+ * More complex styling behavior can be achieved by manipulating an object's
70
+ * <i>secondary style names</i>. Secondary style names can be added and removed
71
+ * using {@link #addStyleName(String)} and {@link #removeStyleName(String)}.
72
+ * The purpose of secondary style names is to associate a variety of CSS style
73
+ * rules over time as an object progresses through different visual states.
74
+ * </p>
75
+ *
76
+ * <p>
77
+ * There is an important special formulation of secondary style names called
78
+ * <i>dependent style names</i>. A dependent style name is a secondary style
79
+ * name prefixed with the primary style name of the widget itself. See
80
+ * {@link #addStyleName(String)} for details.
81
+ * </p>
82
+ */
83
+ public abstract class UIObject {
84
+
85
+ private static final String EMPTY_STYLENAME_MSG = "Style names cannot be empty";
86
+
87
+ private static final String NULL_HANDLE_MSG = "Null widget handle. If you "
88
+ + "are creating a composite, ensure that initWidget() has been called.";
89
+
90
+ private static final String STYLE_EMPTY = "gwt-nostyle";
91
+
92
+ public static native boolean isVisible(Element elem) /*-{
93
+ return (elem.style.display != 'none');
94
+ }-*/;
95
+
96
+ public static native void setVisible(Element elem, boolean visible) /*-{
97
+ elem.style.display = visible ? '' : 'none';
98
+ }-*/;
99
+
100
+ /**
101
+ * Sets the object's primary style name and updates all dependent style names.
102
+ *
103
+ * @param elem the element whose style is to be reset
104
+ * @param style the new primary style name
105
+ * @see #setStyleName(Element, String, boolean)
106
+ */
107
+ protected static void resetStyleName(Element elem, String style) {
108
+ if (elem == null) {
109
+ throw new RuntimeException(NULL_HANDLE_MSG);
110
+ }
111
+
112
+ // Style names cannot contain leading or trailing whitespace, and cannot
113
+ // legally be empty.
114
+ style = style.trim();
115
+ if (style.length() == 0) {
116
+ throw new IllegalArgumentException(EMPTY_STYLENAME_MSG);
117
+ }
118
+
119
+ ensurePrimaryStyleName(elem);
120
+ updatePrimaryAndDependentStyleNames(elem, style);
121
+ }
122
+
123
+ /**
124
+ * This convenience method adds or removes a secondary style name to the
125
+ * primary style name for a given element. Set {@link #setStyleName(String)}
126
+ * for a description of how primary and secondary style names are used.
127
+ *
128
+ * @param elem the element whose style is to be modified
129
+ * @param style the secondary style name to be added or removed
130
+ * @param add <code>true</code> to add the given style, <code>false</code>
131
+ * to remove it
132
+ */
133
+ protected static void setStyleName(Element elem, String style, boolean add) {
134
+ if (elem == null) {
135
+ throw new RuntimeException(NULL_HANDLE_MSG);
136
+ }
137
+
138
+ style = style.trim();
139
+ if (style.length() == 0) {
140
+ throw new IllegalArgumentException(EMPTY_STYLENAME_MSG);
141
+ }
142
+
143
+ // Get the current style string.
144
+ String oldStyle = ensurePrimaryStyleName(elem);
145
+ int idx;
146
+ if (oldStyle == null) {
147
+ idx = -1;
148
+ oldStyle = "";
149
+ } else {
150
+ idx = oldStyle.indexOf(style);
151
+ }
152
+
153
+ // Calculate matching index.
154
+ while (idx != -1) {
155
+ if (idx == 0 || oldStyle.charAt(idx - 1) == ' ') {
156
+ int last = idx + style.length();
157
+ int lastPos = oldStyle.length();
158
+ if ((last == lastPos)
159
+ || ((last < lastPos) && (oldStyle.charAt(last) == ' '))) {
160
+ break;
161
+ }
162
+ }
163
+ idx = oldStyle.indexOf(style, idx + 1);
164
+ }
165
+
166
+ if (add) {
167
+ // Only add the style if it's not already present.
168
+ if (idx == -1) {
169
+ if (oldStyle.length() > 0) {
170
+ oldStyle += " ";
171
+ }
172
+ DOM.setElementProperty(elem, "className", oldStyle + style);
173
+ }
174
+ } else {
175
+ // Don't try to remove the style if it's not there.
176
+ if (idx != -1) {
177
+ if (idx == 0) {
178
+ // You can't remove the base (i.e. the first) style name.
179
+ throw new IllegalArgumentException("Cannot remove base style name");
180
+ }
181
+ String begin = oldStyle.substring(0, idx);
182
+ String end = oldStyle.substring(idx + style.length());
183
+ DOM.setElementProperty(elem, "className", begin + end);
184
+ }
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Ensure that the root element has a primary style name. If one is not
190
+ * already present, then it is assigned the default style name.
191
+ *
192
+ * @return the primary style name
193
+ */
194
+ private static String ensurePrimaryStyleName(Element elem) {
195
+ String className = DOM.getElementProperty(elem, "className").trim();
196
+
197
+ if ("".equals(className)) {
198
+ className = STYLE_EMPTY;
199
+ DOM.setElementProperty(elem, "className", className);
200
+ }
201
+
202
+ return className;
203
+ }
204
+
205
+ /**
206
+ * Replaces all instances of the primary style name with newPrimaryStyleName.
207
+ */
208
+ private static native void updatePrimaryAndDependentStyleNames(Element elem, String newStyle) /*-{
209
+ var className = elem.className;
210
+
211
+ var spaceIdx = className.indexOf(' ');
212
+ if (spaceIdx >= 0) {
213
+ // Get the old base style name from the beginning of the className.
214
+ var oldStyle = className.substring(0, spaceIdx);
215
+
216
+ // Replace oldStyle with newStyle. We have to do this by hand because
217
+ // there is no String.replaceAll() and String.replace() takes a regex,
218
+ // which we can't guarantee is safe on arbitrary class names.
219
+ var newClassName = '', curIdx = 0;
220
+ while (true) {
221
+ var idx = className.indexOf(oldStyle, curIdx);
222
+ if (idx == -1) {
223
+ newClassName += className.substring(curIdx);
224
+ break;
225
+ }
226
+
227
+ newClassName += className.substring(curIdx, idx);
228
+ newClassName += newStyle;
229
+ curIdx = idx + oldStyle.length;
230
+ }
231
+
232
+ elem.className = newClassName;
233
+ } else {
234
+ // There was no space, and therefore only one class name, which we can
235
+ // simply clobber.
236
+ elem.className = newStyle;
237
+ }
238
+ }-*/;
239
+
240
+ private Element element;
241
+
242
+ /**
243
+ * Adds a secondary or dependent style name to this object. A secondary style
244
+ * name is an additional style name that is, in HTML/CSS terms, included as a
245
+ * space-separated token in the value of the CSS <code>class</code>
246
+ * attribute for this object's root element.
247
+ *
248
+ * <p>
249
+ * The most important use for this method is to add a special kind of
250
+ * secondary style name called a <i>dependent style name</i>. To add a
251
+ * dependent style name, prefix the 'style' argument with the result of
252
+ * {@link #getStyleName()}. For example, suppose the primary style name is
253
+ * <code>gwt-TextBox</code>. If the following method is called as
254
+ * <code>obj.setReadOnly(true)</code>:
255
+ * </p>
256
+ *
257
+ * <pre class="code">
258
+ * public void setReadOnly(boolean readOnly) {
259
+ * isReadOnlyMode = readOnly;
260
+ *
261
+ * // Create a dependent style name.
262
+ * String readOnlyStyle = getStyleName() + "-readonly";
263
+ *
264
+ * if (readOnly) {
265
+ * addStyleName(readOnlyStyle);
266
+ * } else {
267
+ * removeStyleName(readOnlyStyle);
268
+ * }
269
+ * }</pre>
270
+ *
271
+ * <p>
272
+ * then both of the CSS style rules below will be applied:
273
+ * </p>
274
+ *
275
+ * <pre class="code">
276
+ *
277
+ * // This rule is based on the primary style name and is always active.
278
+ * .gwt-TextBox {
279
+ * font-size: 12pt;
280
+ * }
281
+ *
282
+ * // This rule is based on a dependent style name that is only active
283
+ * // when the widget has called addStyleName(getStyleName() + "-readonly").
284
+ * .gwt-TextBox-readonly {
285
+ * background-color: lightgrey;
286
+ * border: none;
287
+ * }</pre>
288
+ *
289
+ * <p>
290
+ * Dependent style names are powerful because they are automatically updated
291
+ * whenever the primary style name changes. Continuing with the example above,
292
+ * if the primary style name changed due to the following call:
293
+ * </p>
294
+ *
295
+ * <pre class="code">setStyleName("my-TextThingy");</pre>
296
+ *
297
+ * <p>
298
+ * then the object would be re-associated with style rules below rather than
299
+ * those above:
300
+ * </p>
301
+ *
302
+ * <pre class="code">
303
+ * .my-TextThingy {
304
+ * font-size: 12pt;
305
+ * }
306
+ *
307
+ * .my-TextThingy-readonly {
308
+ * background-color: lightgrey;
309
+ * border: none;
310
+ * }</pre>
311
+ *
312
+ * <p>
313
+ * Secondary style names that are not dependent style names are not
314
+ * automatically updated when the primary style name changes.
315
+ * </p>
316
+ *
317
+ * @param style the secondary style name to be added
318
+ * @see UIObject
319
+ * @see #removeStyleName(String)
320
+ */
321
+ public void addStyleName(String style) {
322
+ setStyleName(getStyleElement(), style, true);
323
+ }
324
+
325
+ /**
326
+ * Gets the object's absolute left position in pixels, as measured from the
327
+ * browser window's client area.
328
+ *
329
+ * @return the object's absolute left position
330
+ */
331
+ public int getAbsoluteLeft() {
332
+ return DOM.getAbsoluteLeft(getElement());
333
+ }
334
+
335
+ /**
336
+ * Gets the object's absolute top position in pixels, as measured from the
337
+ * browser window's client area.
338
+ *
339
+ * @return the object's absolute top position
340
+ */
341
+ public int getAbsoluteTop() {
342
+ return DOM.getAbsoluteTop(getElement());
343
+ }
344
+
345
+ /**
346
+ * Gets a handle to the object's underlying DOM element.
347
+ *
348
+ * @return the object's browser element
349
+ */
350
+ public Element getElement() {
351
+ return element;
352
+ }
353
+
354
+ /**
355
+ * Gets the object's offset height in pixels. This is the total height of the
356
+ * object, including decorations such as border, margin, and padding.
357
+ *
358
+ * @return the object's offset height
359
+ */
360
+ public int getOffsetHeight() {
361
+ return DOM.getElementPropertyInt(element, "offsetHeight");
362
+ }
363
+
364
+ /**
365
+ * Gets the object's offset width in pixels. This is the total width of the
366
+ * object, including decorations such as border, margin, and padding.
367
+ *
368
+ * @return the object's offset width
369
+ */
370
+ public int getOffsetWidth() {
371
+ return DOM.getElementPropertyInt(element, "offsetWidth");
372
+ }
373
+
374
+ /**
375
+ * Gets the primary style name associated with the object.
376
+ *
377
+ * @return the object's primary style name
378
+ * @see #setStyleName(String)
379
+ * @see #addStyleName(String)
380
+ * @see #removeStyleName(String)
381
+ */
382
+ public String getStyleName() {
383
+ String fullClassName = ensurePrimaryStyleName(getStyleElement());
384
+
385
+ // The base style name is always the first token of the full CSS class
386
+ // name. There can be no leading whitespace in the class name, so it's not
387
+ // necessary to trim() it.
388
+ int spaceIdx = fullClassName.indexOf(' ');
389
+ if (spaceIdx >= 0) {
390
+ return fullClassName.substring(0, spaceIdx);
391
+ }
392
+ return fullClassName;
393
+ }
394
+
395
+ /**
396
+ * Gets the title associated with this object. The title is the 'tool-tip'
397
+ * displayed to users when they hover over the object.
398
+ *
399
+ * @return the object's title
400
+ */
401
+ public String getTitle() {
402
+ return DOM.getElementProperty(element, "title");
403
+ }
404
+
405
+ /**
406
+ * Determines whether or not this object is visible.
407
+ *
408
+ * @return <code>true</code> if the object is visible
409
+ */
410
+ public boolean isVisible() {
411
+ return isVisible(element);
412
+ }
413
+
414
+ /**
415
+ * Removes a secondary style name.
416
+ *
417
+ * @param style the secondary style name to be removed
418
+ * @see #addStyleName(String)
419
+ */
420
+ public void removeStyleName(String style) {
421
+ setStyleName(getStyleElement(), style, false);
422
+ }
423
+
424
+ /**
425
+ * Sets the object's height. This height does not include decorations such as
426
+ * border, margin, and padding.
427
+ *
428
+ * @param height the object's new height, in CSS units (e.g. "10px", "1em")
429
+ */
430
+ public void setHeight(String height) {
431
+ // This exists to deal with an inconsistency in IE's implementation where
432
+ // it won't accept negative numbers in length measurements
433
+ assert extractLengthValue(height.trim().toLowerCase()) >= 0 :
434
+ "CSS heights should not be negative";
435
+ DOM.setStyleAttribute(element, "height", height);
436
+ }
437
+
438
+ /**
439
+ * Sets the object's size, in pixels, not including decorations such as
440
+ * border, margin, and padding.
441
+ *
442
+ * @param width the object's new width, in pixels
443
+ * @param height the object's new height, in pixels
444
+ */
445
+ public void setPixelSize(int width, int height) {
446
+ if (width >= 0) {
447
+ setWidth(width + "px");
448
+ }
449
+ if (height >= 0) {
450
+ setHeight(height + "px");
451
+ }
452
+ }
453
+
454
+ /**
455
+ * Sets the object's size. This size does not include decorations such as
456
+ * border, margin, and padding.
457
+ *
458
+ * @param width the object's new width, in CSS units (e.g. "10px", "1em")
459
+ * @param height the object's new height, in CSS units (e.g. "10px", "1em")
460
+ */
461
+ public void setSize(String width, String height) {
462
+ setWidth(width);
463
+ setHeight(height);
464
+ }
465
+
466
+ /**
467
+ * Sets the object's primary style name and updates all dependent style names.
468
+ *
469
+ * @param style the new primary style name
470
+ * @see #addStyleName(String)
471
+ * @see #removeStyleName(String)
472
+ */
473
+ public void setStyleName(String style) {
474
+ resetStyleName(getStyleElement(), style);
475
+ }
476
+
477
+ /**
478
+ * Sets the title associated with this object. The title is the 'tool-tip'
479
+ * displayed to users when they hover over the object.
480
+ *
481
+ * @param title the object's new title
482
+ */
483
+ public void setTitle(String title) {
484
+ if (title == null || title.length() == 0) {
485
+ DOM.removeElementAttribute(element, "title");
486
+ } else {
487
+ DOM.setElementAttribute(element, "title", title);
488
+ }
489
+ }
490
+
491
+ /**
492
+ * Sets whether this object is visible.
493
+ *
494
+ * @param visible <code>true</code> to show the object, <code>false</code>
495
+ * to hide it
496
+ */
497
+ public void setVisible(boolean visible) {
498
+ setVisible(element, visible);
499
+ }
500
+
501
+ /**
502
+ * Sets the object's width. This width does not include decorations such as
503
+ * border, margin, and padding.
504
+ *
505
+ * @param width the object's new width, in CSS units (e.g. "10px", "1em")
506
+ */
507
+ public void setWidth(String width) {
508
+ // This exists to deal with an inconsistency in IE's implementation where
509
+ // it won't accept negative numbers in length measurements
510
+ assert extractLengthValue(width.trim().toLowerCase()) >= 0 :
511
+ "CSS widths should not be negative";
512
+ DOM.setStyleAttribute(element, "width", width);
513
+ }
514
+
515
+ /**
516
+ * Adds a set of events to be sunk by this object. Note that only
517
+ * {@link Widget widgets} may actually receive events, but can receive events
518
+ * from all objects contained within them.
519
+ *
520
+ * @param eventBitsToAdd a bitfield representing the set of events to be added
521
+ * to this element's event set
522
+ * @see com.google.gwt.user.client.Event
523
+ */
524
+ public void sinkEvents(int eventBitsToAdd) {
525
+ DOM.sinkEvents(getElement(), eventBitsToAdd
526
+ | DOM.getEventsSunk(getElement()));
527
+ }
528
+
529
+ /**
530
+ * This method is overridden so that any object can be viewed in the debugger
531
+ * as an HTML snippet.
532
+ *
533
+ * @return a string representation of the object
534
+ */
535
+ public String toString() {
536
+ if (element == null) {
537
+ return "(null handle)";
538
+ }
539
+ return DOM.toString(element);
540
+ }
541
+
542
+ /**
543
+ * Removes a set of events from this object's event list.
544
+ *
545
+ * @param eventBitsToRemove a bitfield representing the set of events to be
546
+ * removed from this element's event set
547
+ * @see #sinkEvents
548
+ * @see com.google.gwt.user.client.Event
549
+ */
550
+ public void unsinkEvents(int eventBitsToRemove) {
551
+ DOM.sinkEvents(getElement(), DOM.getEventsSunk(getElement())
552
+ & (~eventBitsToRemove));
553
+ }
554
+
555
+ /**
556
+ * Template method that returns the element to which style names will be
557
+ * applied. By default it returns the root element, but this method may be
558
+ * overridden to apply styles to a child element.
559
+ *
560
+ * @return the element to which style names will be applied
561
+ */
562
+ protected Element getStyleElement() {
563
+ return element;
564
+ }
565
+
566
+ /**
567
+ * Sets this object's browser element. UIObject subclasses must call this
568
+ * method before attempting to call any other methods.
569
+ *
570
+ * If the browser element has already been set, then the current element's
571
+ * position is located in the DOM and removed. The new element is added into
572
+ * the previous element's position.
573
+ *
574
+ * @param elem the object's new element
575
+ */
576
+ protected void setElement(Element elem) {
577
+ if (this.element != null) {
578
+ // replace this.element in its parent with elem.
579
+ replaceNode(this.element, elem);
580
+ }
581
+
582
+ this.element = elem;
583
+
584
+ // We do not actually force the creation of a primary style name here.
585
+ // Instead, we do it lazily -- when it is aboslutely required --
586
+ // in getStyleName(), addStyleName(), and removeStyleName().
587
+ }
588
+
589
+ /**
590
+ * Intended to be used to pull the value out of a CSS length. We rely on the
591
+ * behavior of parseFloat to ignore non-numeric chars in its input. If the
592
+ * value is "auto" or "inherit", 0 will be returned.
593
+ *
594
+ * @param s The CSS length string to extract
595
+ * @return The leading numeric portion of <code>s</code>, or 0 if "auto" or
596
+ * "inherit" are passed in.
597
+ */
598
+ private native double extractLengthValue(String s) /*-{
599
+ if (s == "auto" || s == "inherit" || s == "") {
600
+ return 0;
601
+ } else {
602
+ return parseFloat(s);
603
+ }
604
+ }-*/;
605
+
606
+ private native void replaceNode(Element node, Element newNode) /*-{
607
+ var p = node.parentNode;
608
+ if (!p) {
609
+ return;
610
+ }
611
+ p.insertBefore(newNode, node);
612
+ p.removeChild(node);
613
+ }-*/;
614
+ }