superchris-rubyjs 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +131 -0
- data/Rakefile +65 -0
- data/bin/rubyjs +144 -0
- data/rubyjs.gemspec +112 -0
- data/src/rubyjs.rb +3 -0
- data/src/rubyjs/code_generator.rb +474 -0
- data/src/rubyjs/compiler.rb +2061 -0
- data/src/rubyjs/debug_name_generator.rb +95 -0
- data/src/rubyjs/encoder.rb +171 -0
- data/src/rubyjs/eval_into.rb +59 -0
- data/src/rubyjs/lib/core.rb +1016 -0
- data/src/rubyjs/lib/dom_element.rb +66 -0
- data/src/rubyjs/lib/json.rb +101 -0
- data/src/rubyjs/lib/microunit.rb +188 -0
- data/src/rubyjs/model.rb +293 -0
- data/src/rubyjs/name_generator.rb +71 -0
- data/src/rwt/AbsolutePanel.rb +161 -0
- data/src/rwt/DOM.Konqueror.rb +89 -0
- data/src/rwt/DOM.Opera.rb +65 -0
- data/src/rwt/DOM.rb +1044 -0
- data/src/rwt/Event.Opera.rb +35 -0
- data/src/rwt/Event.rb +429 -0
- data/src/rwt/HTTPRequest.IE6.rb +5 -0
- data/src/rwt/HTTPRequest.rb +74 -0
- data/src/rwt/Label.rb +164 -0
- data/src/rwt/Panel.rb +90 -0
- data/src/rwt/RootPanel.rb +16 -0
- data/src/rwt/UIObject.rb +495 -0
- data/src/rwt/Widget.rb +193 -0
- data/src/rwt/ported-from/AbsolutePanel.java +158 -0
- data/src/rwt/ported-from/DOM.java +571 -0
- data/src/rwt/ported-from/DOMImpl.java +426 -0
- data/src/rwt/ported-from/DOMImplOpera.java +82 -0
- data/src/rwt/ported-from/DOMImplStandard.java +234 -0
- data/src/rwt/ported-from/HTTPRequest.java +81 -0
- data/src/rwt/ported-from/HTTPRequestImpl.java +103 -0
- data/src/rwt/ported-from/Label.java +163 -0
- data/src/rwt/ported-from/Panel.java +99 -0
- data/src/rwt/ported-from/UIObject.java +614 -0
- data/src/rwt/ported-from/Widget.java +221 -0
- data/test/benchmark/bm_vm1_block.rb +15 -0
- data/test/benchmark/bm_vm1_const.rb +13 -0
- data/test/benchmark/bm_vm1_ensure.rb +15 -0
- data/test/benchmark/common.rb +5 -0
- data/test/benchmark/params.yaml +7 -0
- data/test/common.Browser.rb +13 -0
- data/test/common.rb +8 -0
- data/test/gen_browser_test_suite.rb +129 -0
- data/test/gen_test_suite.rb +41 -0
- data/test/run_benchs.rb +58 -0
- data/test/run_tests.rb +22 -0
- data/test/test_args.rb +24 -0
- data/test/test_array.rb +22 -0
- data/test/test_case.rb +35 -0
- data/test/test_class.rb +55 -0
- data/test/test_eql.rb +9 -0
- data/test/test_exception.rb +61 -0
- data/test/test_expr.rb +12 -0
- data/test/test_hash.rb +29 -0
- data/test/test_hot_ruby.rb +146 -0
- data/test/test_if.rb +28 -0
- data/test/test_insertion_sort.rb +25 -0
- data/test/test_inspect.rb +10 -0
- data/test/test_lebewesen.rb +39 -0
- data/test/test_massign.rb +66 -0
- data/test/test_new.rb +12 -0
- data/test/test_range.rb +70 -0
- data/test/test_regexp.rb +22 -0
- data/test/test_send.rb +65 -0
- data/test/test_simple_output.rb +5 -0
- data/test/test_splat.rb +21 -0
- data/test/test_string.rb +51 -0
- data/test/test_test.rb +17 -0
- data/test/test_yield.rb +154 -0
- data/utils/js/Makefile +9 -0
- data/utils/js/RunScript.class +0 -0
- data/utils/js/RunScript.java +73 -0
- data/utils/js/js.jar +0 -0
- data/utils/js/run.sh +3 -0
- data/utils/jsc/Makefile +7 -0
- data/utils/jsc/README +3 -0
- data/utils/jsc/RunScript.c +93 -0
- data/utils/jsc/run.sh +15 -0
- data/utils/yuicompressor/README +1 -0
- data/utils/yuicompressor/yuicompressor-2.2.5.jar +0 -0
- metadata +157 -0
@@ -0,0 +1,74 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007 by Michael Neumann (mneumann@ntecs.de)
|
3
|
+
#
|
4
|
+
# Copyright 2006 Google Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
7
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
8
|
+
# the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
+
# License for the specific language governing permissions and limitations under
|
16
|
+
# the License.
|
17
|
+
#++
|
18
|
+
|
19
|
+
class HTTPRequest
|
20
|
+
|
21
|
+
#
|
22
|
+
# Makes an asynchronous HTTP GET to a remote server.
|
23
|
+
#
|
24
|
+
# url:: the absolute url to GET
|
25
|
+
# returns:: +false+ if the invocation fails to issue
|
26
|
+
# yields:: the response
|
27
|
+
#
|
28
|
+
def self.asyncGet(url, user=nil, pwd=nil, &block)
|
29
|
+
asyncImpl(url, "GET", "", user, pwd, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Makes an asynchronous HTTP POST to a remote server.
|
34
|
+
#
|
35
|
+
# url:: the absolute url to which the POST data is delivered
|
36
|
+
# postData:: the data to post
|
37
|
+
# returns:: +false+ if the invocation fails to issue
|
38
|
+
# yields:: the response
|
39
|
+
#
|
40
|
+
def self.asyncPost(url, postData, user=nil, pwd=nil, &block)
|
41
|
+
asyncImpl(url, "POST", postData, user, pwd, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def self.createXmlHTTPRequest()
|
47
|
+
`return new XMLHttpRequest()`
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.asyncImpl(url, method, data="", user=nil, pwd=nil)
|
51
|
+
xmlHttp = createXmlHTTPRequest()
|
52
|
+
`
|
53
|
+
try {
|
54
|
+
#<xmlHttp>.open(#<method>, #<url>, true);
|
55
|
+
#<xmlHttp>.setRequestHeader("Content-Type", "text/plain; charset=utf-8");
|
56
|
+
#<xmlHttp>.onreadystatechange = function() {
|
57
|
+
if (#<xmlHttp>.readyState == 4) {
|
58
|
+
#<xmlHttp>.onreadystatechange = #<globalattr:null_func>; `
|
59
|
+
|
60
|
+
yield `(#<xmlHttp>.responseText || "")`
|
61
|
+
|
62
|
+
`}
|
63
|
+
};
|
64
|
+
#<xmlHttp>.send(#<data>);
|
65
|
+
return true;
|
66
|
+
} catch (e) {
|
67
|
+
#<xmlHttp>.onreadystatechange = #<globalattr:null_func>;
|
68
|
+
return false;
|
69
|
+
} `
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
|
data/src/rwt/Label.rb
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007 by Michael Neumann (mneumann@ntecs.de)
|
3
|
+
#
|
4
|
+
# Copyright 2007 Google Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
7
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
8
|
+
# the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
+
# License for the specific language governing permissions and limitations under
|
16
|
+
# the License.
|
17
|
+
#++
|
18
|
+
|
19
|
+
|
20
|
+
#
|
21
|
+
# Map Event types to methods.
|
22
|
+
#
|
23
|
+
# We use a hack in that we assign the keys directly to
|
24
|
+
# the object. As long as the keys (== event types) are
|
25
|
+
# integers (and they are) there is no problem with that
|
26
|
+
# approach. This saves us an extra object!
|
27
|
+
#
|
28
|
+
module EventDispatchMap
|
29
|
+
|
30
|
+
def onBrowserEvent(event)
|
31
|
+
eventType = Event.getType(event)
|
32
|
+
`
|
33
|
+
var cb = #<self>[#<eventType>];
|
34
|
+
if (cb) cb.apply(#<self>, [#<nil>, #<event>]);
|
35
|
+
return #<nil>
|
36
|
+
`
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def mapEvent(eventType, method)
|
42
|
+
`#<self>[#<eventType>] = #<method>`
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
#
|
49
|
+
# A widget that contains arbitrary text, <i>not</i> interpreted as HTML.
|
50
|
+
#
|
51
|
+
class Label < Widget
|
52
|
+
|
53
|
+
#include EventDispatchMap
|
54
|
+
|
55
|
+
#
|
56
|
+
# Creates a label, either empty or with the specified text.
|
57
|
+
#
|
58
|
+
# text:: the new label's text. if +nil+, label is empty.
|
59
|
+
# wordWrap:: +false+ to disable wordwrapping, +true+ to enable,
|
60
|
+
# +nil+ to don't care.
|
61
|
+
#
|
62
|
+
def initialize(text=nil, wordWrap=nil)
|
63
|
+
setElement(DOM.createDiv)
|
64
|
+
sinkEvents(Event::ONCLICK | Event::MOUSEEVENTS | Event::ONMOUSEWHEEL)
|
65
|
+
setStyleName("rwt-Label")
|
66
|
+
setText(text) if text
|
67
|
+
setWordWrap(wordWrap) unless wordWrap.nil?
|
68
|
+
|
69
|
+
#
|
70
|
+
# setup event map
|
71
|
+
#
|
72
|
+
=begin
|
73
|
+
mapEvent(Event::ONCLICK, `this.#<m:onClick>`)
|
74
|
+
mapEvent(Event::ONMOUSEDOWN, `this.#<m:onMouse>`)
|
75
|
+
mapEvent(Event::ONMOUSEUP, `this.#<m:onMouse>`)
|
76
|
+
mapEvent(Event::ONMOUSEMOVE, `this.#<m:onMouse>`)
|
77
|
+
mapEvent(Event::ONMOUSEOVER, `this.#<m:onMouse>`)
|
78
|
+
mapEvent(Event::ONMOUSEOUT, `this.#<m:onMouse>`)
|
79
|
+
mapEvent(Event::ONMOUSEWHEEL, `this.#<m:onMouseWheel>`)
|
80
|
+
=end
|
81
|
+
end
|
82
|
+
|
83
|
+
def addClickListener(listener)
|
84
|
+
@clickListeners ||= []
|
85
|
+
@clickListeners << listener
|
86
|
+
end
|
87
|
+
|
88
|
+
def addMouseListener(listener)
|
89
|
+
@mouseListeners ||= []
|
90
|
+
@mouseListeners << listener
|
91
|
+
end
|
92
|
+
|
93
|
+
def addMouseWheelListener(listener)
|
94
|
+
@mouseWheelListeners ||= []
|
95
|
+
@mouseWheelListeners << listener
|
96
|
+
end
|
97
|
+
|
98
|
+
def removeClickListener(listener)
|
99
|
+
@clickListeners.delete(listener) if @clickListeners
|
100
|
+
end
|
101
|
+
|
102
|
+
def removeMouseListener(listener)
|
103
|
+
@mouseListeners.delete(listener) if @mouseListeners
|
104
|
+
end
|
105
|
+
|
106
|
+
def removeMouseWheelListener(listener)
|
107
|
+
@mouseListeners.delete(listener) if @mouseWheelListeners
|
108
|
+
end
|
109
|
+
|
110
|
+
=begin
|
111
|
+
def getHorizontalAlignment
|
112
|
+
@horzAlign
|
113
|
+
end
|
114
|
+
|
115
|
+
def setHorizontalAlignment(align)
|
116
|
+
@horzAlign = align
|
117
|
+
Element.setStyleAttribute(getElement(), "textAlign", align.getTextAlignString())
|
118
|
+
end
|
119
|
+
=end
|
120
|
+
|
121
|
+
def getText
|
122
|
+
DOM.getInnerText(getElement())
|
123
|
+
end
|
124
|
+
|
125
|
+
def getWordWrap
|
126
|
+
DOM.getStyleAttribute(getElement(), "whiteSpace") != 'nowrap'
|
127
|
+
end
|
128
|
+
|
129
|
+
def setText(text)
|
130
|
+
DOM.setInnerText(getElement(), text)
|
131
|
+
end
|
132
|
+
|
133
|
+
def setWordWrap(wrap)
|
134
|
+
DOM.setStyleAttribute(getElement(), "whiteSpace", wrap ? "normal" : "nowrap")
|
135
|
+
end
|
136
|
+
|
137
|
+
def onBrowserEvent(event)
|
138
|
+
eventType = Event.getType(event)
|
139
|
+
|
140
|
+
if eventType == Event::ONCLICK
|
141
|
+
if @clickListeners
|
142
|
+
@clickListeners.each {|l| l.onClick(self) }
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
=begin
|
148
|
+
def onClick(event)
|
149
|
+
if @clickListeners
|
150
|
+
@clickListeners.each {|l| l.onClick(self) }
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def onMouse(event)
|
155
|
+
if @mouseListeners
|
156
|
+
#@mouseListeners.each {|l| l.onClick(self) }
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def onMouseWheel(event)
|
161
|
+
end
|
162
|
+
=end
|
163
|
+
|
164
|
+
end
|
data/src/rwt/Panel.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007 by Michael Neumann (mneumann@ntecs.de)
|
3
|
+
#
|
4
|
+
# Copyright 2006 Google Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
7
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
8
|
+
# the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
+
# License for the specific language governing permissions and limitations under
|
16
|
+
# the License.
|
17
|
+
#++
|
18
|
+
|
19
|
+
#
|
20
|
+
# Abstract base class for all panels, which are widgets that can contain other
|
21
|
+
# widgets.
|
22
|
+
#
|
23
|
+
class Panel < Widget
|
24
|
+
|
25
|
+
def add(w)
|
26
|
+
raise "This panel does not support no-arg add()"
|
27
|
+
end
|
28
|
+
|
29
|
+
def clear
|
30
|
+
raise
|
31
|
+
end
|
32
|
+
|
33
|
+
def each
|
34
|
+
raise
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# This method must be called as part of the add method of any panel. It
|
39
|
+
# ensures that the Widget's parent is set properly, and that it is removed
|
40
|
+
# from any existing parent widget. It also attaches the child widget's
|
41
|
+
# DOM element to its new container, ensuring that this process occurs in the
|
42
|
+
# right order.
|
43
|
+
#
|
44
|
+
# w:: the widget to be adopted
|
45
|
+
# container:: the element within which it will be contained
|
46
|
+
#
|
47
|
+
def adopt(w, container)
|
48
|
+
# Remove the widget from its current parent, if any.
|
49
|
+
w.removeFromParent
|
50
|
+
|
51
|
+
# Attach it at the DOM and GWT levels.
|
52
|
+
if container
|
53
|
+
DOM.appendChild(container, w.getElement)
|
54
|
+
end
|
55
|
+
|
56
|
+
w.setParent(self)
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# This method must be called whenever a Widget is removed. It ensures that
|
61
|
+
# the Widget's parent is cleared.
|
62
|
+
#
|
63
|
+
# w:: the widget to be disowned
|
64
|
+
#
|
65
|
+
def disown(w)
|
66
|
+
# Only disown it if it's actually contained in this panel.
|
67
|
+
raise "w is not a child of this panel" if w.getParent != self
|
68
|
+
|
69
|
+
# Remove it at the DOM and GWT levels.
|
70
|
+
elem = w.getElement
|
71
|
+
w.setParent(nil)
|
72
|
+
DOM.removeChild(DOM.getParent(elem), elem)
|
73
|
+
end
|
74
|
+
|
75
|
+
def onAttach
|
76
|
+
super()
|
77
|
+
|
78
|
+
# Ensure that all child widgets are attached.
|
79
|
+
#FIXME
|
80
|
+
each {|child| child.onAttach}
|
81
|
+
end
|
82
|
+
|
83
|
+
def onDetach
|
84
|
+
super()
|
85
|
+
|
86
|
+
# Ensure that all child widgets are detached.
|
87
|
+
each {|child| child.onDetach}
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
data/src/rwt/UIObject.rb
ADDED
@@ -0,0 +1,495 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007 by Michael Neumann (mneumann@ntecs.de)
|
3
|
+
#
|
4
|
+
# Copyright 2007 Google Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
7
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
8
|
+
# the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
+
# License for the specific language governing permissions and limitations under
|
16
|
+
# the License.
|
17
|
+
#++
|
18
|
+
|
19
|
+
#
|
20
|
+
# The superclass for all user-interface objects. It simply wraps a DOM element,
|
21
|
+
# and cannot receive events. Most interesting user-interface classes derive
|
22
|
+
# from +Widget+.
|
23
|
+
#
|
24
|
+
# == Styling With CSS
|
25
|
+
#
|
26
|
+
# All +UIObject+ objects can be styled using CSS. Style names that
|
27
|
+
# are specified programmatically in Ruby source are implicitly associated with
|
28
|
+
# CSS style rules. In terms of HTML and CSS, a RWT style name is the element's
|
29
|
+
# CSS "class". By convention, RWT style names are of the form
|
30
|
+
# <tt>[project]-[widget]</tt>.
|
31
|
+
#
|
32
|
+
# For example, the +Button+ widget has the style name
|
33
|
+
# <tt>rwt-Button</tt>, meaning that within the +Button+
|
34
|
+
# constructor, the following call occurs:
|
35
|
+
#
|
36
|
+
# setStyleName("rwt-Button")
|
37
|
+
#
|
38
|
+
# A corresponding CSS style rule can then be written as follows:
|
39
|
+
#
|
40
|
+
# // Example of how you might choose to style a Button widget
|
41
|
+
# .rwt-Button {
|
42
|
+
# background-color: yellow;
|
43
|
+
# color: black;
|
44
|
+
# font-size: 24pt;
|
45
|
+
# }
|
46
|
+
#
|
47
|
+
# Note the dot prefix in the CSS style rule. This syntax is called a CSS
|
48
|
+
# class selector.
|
49
|
+
#
|
50
|
+
# == Style Name Specifics
|
51
|
+
#
|
52
|
+
# Every +UIObject+ has a <i>primary style name</i> that
|
53
|
+
# identifies the key CSS style rule that should always be applied to it. Use
|
54
|
+
# #setStyleName to specify an object's primary style name. In
|
55
|
+
# most cases, the primary style name is set in a widget's constructor and never
|
56
|
+
# changes again during execution. In the case that no primary style name is
|
57
|
+
# specified, it defaults to <tt>rwt-nostyle</tt>.
|
58
|
+
#
|
59
|
+
# More complex styling behavior can be achieved by manipulating an object's
|
60
|
+
# <i>secondary style names</i>. Secondary style names can be added and removed
|
61
|
+
# using #addStyleName and #removeStyleName.
|
62
|
+
# The purpose of secondary style names is to associate a variety of CSS style
|
63
|
+
# rules over time as an object progresses through different visual states.
|
64
|
+
#
|
65
|
+
# There is an important special formulation of secondary style names called
|
66
|
+
# <i>dependent style names</i>. A dependent style name is a secondary style
|
67
|
+
# name prefixed with the primary style name of the widget itself. See
|
68
|
+
# #addStyleName for details.
|
69
|
+
#
|
70
|
+
class UIObject
|
71
|
+
|
72
|
+
STYLE_EMPTY = "rwt-nostyle"
|
73
|
+
|
74
|
+
#-------------------------------------------------------------------
|
75
|
+
# Style-name related
|
76
|
+
#-------------------------------------------------------------------
|
77
|
+
|
78
|
+
#
|
79
|
+
# Gets the primary style name associated with the object.
|
80
|
+
#
|
81
|
+
# return:: the object's primary style name
|
82
|
+
#
|
83
|
+
# See #setStyleName, #addStyleName, #removeStyleName.
|
84
|
+
#
|
85
|
+
def getStyleName
|
86
|
+
styleNameHelper(MODE_GET)
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# Sets the object's primary style name and updates all dependent style names.
|
91
|
+
#
|
92
|
+
# style:: the new primary style name
|
93
|
+
#
|
94
|
+
# See #addStyleName, #removeStyleName
|
95
|
+
#
|
96
|
+
def setStyleName(style)
|
97
|
+
styleNameHelper(MODE_SET, style)
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Adds a secondary or dependent style name to this object. A secondary style
|
102
|
+
# name is an additional style name that is, in HTML/CSS terms, included as a
|
103
|
+
# space-separated token in the value of the CSS +class+ attribute for this
|
104
|
+
# object's root element.
|
105
|
+
#
|
106
|
+
# The most important use for this method is to add a special kind of
|
107
|
+
# secondary style name called a <i>dependent style name</i>. To add a
|
108
|
+
# dependent style name, prefix the 'style' argument with the result of
|
109
|
+
# +getStyleName+. For example, suppose the primary style name is
|
110
|
+
# <tt>rwt-TextBox</tt>. If the following method is called as
|
111
|
+
# <tt>obj.setReadOnly(true)</tt>:
|
112
|
+
#
|
113
|
+
# def setReadOnly(readOnly=true)
|
114
|
+
# # Create a dependent style name.
|
115
|
+
# readOnlyStyle = getStyleName() + "-readonly"
|
116
|
+
#
|
117
|
+
# @isReadOnlyMode = readOnly
|
118
|
+
# if readOnly
|
119
|
+
# addStyleName(readOnlyStyle)
|
120
|
+
# else
|
121
|
+
# removeStyleName(readOnlyStyle)
|
122
|
+
# end
|
123
|
+
# end
|
124
|
+
#
|
125
|
+
# then both of the CSS style rules below will be applied:
|
126
|
+
#
|
127
|
+
# // This rule is based on the primary style name and is always active.
|
128
|
+
# .rwt-TextBox {
|
129
|
+
# font-size: 12pt;
|
130
|
+
# }
|
131
|
+
#
|
132
|
+
# // This rule is based on a dependent style name that is only active
|
133
|
+
# // when the widget has called addStyleName(getStyleName() + "-readonly").
|
134
|
+
# .gwt-TextBox-readonly {
|
135
|
+
# background-color: lightgrey;
|
136
|
+
# border: none;
|
137
|
+
# }
|
138
|
+
#
|
139
|
+
# Dependent style names are powerful because they are automatically updated
|
140
|
+
# whenever the primary style name changes. Continuing with the example above,
|
141
|
+
# if the primary style name changed due to the following call:
|
142
|
+
#
|
143
|
+
# setStyleName("my-TextThingy")
|
144
|
+
#
|
145
|
+
# then the object would be re-associated with style rules below rather than
|
146
|
+
# those above:
|
147
|
+
#
|
148
|
+
# .my-TextThingy {
|
149
|
+
# font-size: 12pt;
|
150
|
+
# }
|
151
|
+
#
|
152
|
+
# .my-TextThingy-readonly {
|
153
|
+
# background-color: lightgrey;
|
154
|
+
# border: none;
|
155
|
+
# }
|
156
|
+
#
|
157
|
+
# Secondary style names that are not dependent style names are not
|
158
|
+
# automatically updated when the primary style name changes.
|
159
|
+
#
|
160
|
+
# style:: the secondary style name to be added
|
161
|
+
#
|
162
|
+
# See UIObject, #removeStyleName
|
163
|
+
#
|
164
|
+
def addStyleName(style)
|
165
|
+
styleNameHelper(MODE_ADD, style)
|
166
|
+
end
|
167
|
+
|
168
|
+
#
|
169
|
+
# Removes a secondary style name.
|
170
|
+
#
|
171
|
+
# style:: the secondary style name to be removed
|
172
|
+
#
|
173
|
+
# See #addStyleName.
|
174
|
+
#
|
175
|
+
def removeStyleName(style)
|
176
|
+
styleNameHelper(MODE_REM, style)
|
177
|
+
end
|
178
|
+
|
179
|
+
#
|
180
|
+
# Template method that returns the element to which style names will be
|
181
|
+
# applied. By default it returns the root element, but this method may be
|
182
|
+
# overridden to apply styles to a child element.
|
183
|
+
#
|
184
|
+
# return:: the element to which style names will be applied
|
185
|
+
#
|
186
|
+
def getStyleElement
|
187
|
+
return @element
|
188
|
+
end
|
189
|
+
|
190
|
+
protected :getStyleElement
|
191
|
+
|
192
|
+
#
|
193
|
+
# Constants used in +mode+ parameter of +styleNameHelper+ method.
|
194
|
+
#
|
195
|
+
MODE_GET = 0
|
196
|
+
MODE_SET = 1
|
197
|
+
MODE_ADD = 2
|
198
|
+
MODE_REM = 3
|
199
|
+
|
200
|
+
#
|
201
|
+
# Implement set/get/add/remove of style names.
|
202
|
+
#
|
203
|
+
def styleNameHelper(mode, style=nil)
|
204
|
+
unless elem = getStyleElement()
|
205
|
+
raise "Null widget handle!"
|
206
|
+
end
|
207
|
+
|
208
|
+
className = DOM.getProperty(elem, "className").strip
|
209
|
+
|
210
|
+
# Ensure a primary style name
|
211
|
+
if className.empty?
|
212
|
+
className = STYLE_EMPTY
|
213
|
+
DOM.setProperty(elem, "className", className)
|
214
|
+
end
|
215
|
+
|
216
|
+
if mode != MODE_GET
|
217
|
+
# Style names cannot contain leading or trailing whitespace, and cannot
|
218
|
+
# legally be empty.
|
219
|
+
style = style.strip
|
220
|
+
raise "Style names cannot be empty" if style.empty?
|
221
|
+
end
|
222
|
+
|
223
|
+
arr = className.split(" ")
|
224
|
+
|
225
|
+
# The primary style name is always the first token of the full CSS class name.
|
226
|
+
primary = arr.first
|
227
|
+
|
228
|
+
return primary if mode == MODE_GET
|
229
|
+
raise "Cannot remove primary style name" if mode == MODE_REM and primary == style
|
230
|
+
|
231
|
+
newClassName = []
|
232
|
+
|
233
|
+
`var e, s;
|
234
|
+
for (var i=0; i<#<arr>.length; i++)
|
235
|
+
{
|
236
|
+
e = #<arr>[i];
|
237
|
+
if (e == '') continue;
|
238
|
+
|
239
|
+
if (#<mode> == #<MODE_SET>)
|
240
|
+
{
|
241
|
+
// set primary name -> update all dependent style names
|
242
|
+
if (e.indexOf(#<primary>) != 0)
|
243
|
+
{
|
244
|
+
// +e+ doesnt start with the old primary style name
|
245
|
+
// -> we dont touch it and keep it!
|
246
|
+
s = e;
|
247
|
+
}
|
248
|
+
else
|
249
|
+
{
|
250
|
+
// replace +primary+ with +style+
|
251
|
+
s = #<style> + e.substring(#<primary>.length);
|
252
|
+
}
|
253
|
+
}
|
254
|
+
else /* MODE_ADD or MODE_REM */
|
255
|
+
{
|
256
|
+
// remove the style. in case of MODE_ADD, we add it back later!
|
257
|
+
s = (e == #<style>) ? null : e;
|
258
|
+
}
|
259
|
+
|
260
|
+
if (s) #<newClassName>.push(s);
|
261
|
+
}
|
262
|
+
|
263
|
+
if (#<mode> == #<MODE_ADD>)
|
264
|
+
{
|
265
|
+
#<newClassName>.push(#<style>);
|
266
|
+
}
|
267
|
+
|
268
|
+
#<newClassName> = #<newClassName>.join(" ");`
|
269
|
+
|
270
|
+
DOM.setProperty(elem, "className", newClassName)
|
271
|
+
end
|
272
|
+
|
273
|
+
private :styleNameHelper
|
274
|
+
|
275
|
+
#-------------------------------------------------------------------
|
276
|
+
# Position/Size related
|
277
|
+
#-------------------------------------------------------------------
|
278
|
+
|
279
|
+
#
|
280
|
+
# Gets the object's absolute left position in pixels, as measured from the
|
281
|
+
# browser window's client area.
|
282
|
+
#
|
283
|
+
# return:: the object's absolute left position
|
284
|
+
#
|
285
|
+
def getAbsoluteLeft
|
286
|
+
DOM.getAbsoluteLeft(@element)
|
287
|
+
end
|
288
|
+
|
289
|
+
#
|
290
|
+
# Gets the object's absolute top position in pixels, as measured from the
|
291
|
+
# browser window's client area.
|
292
|
+
#
|
293
|
+
# return:: the object's absolute top position
|
294
|
+
#
|
295
|
+
def getAbsoluteTop
|
296
|
+
DOM.getAbsoluteTop(@element)
|
297
|
+
end
|
298
|
+
|
299
|
+
#
|
300
|
+
# Gets the object's offset height in pixels. This is the total height of the
|
301
|
+
# object, including decorations such as border, margin, and padding.
|
302
|
+
#
|
303
|
+
# return:: the object's offset height
|
304
|
+
#
|
305
|
+
def getOffsetHeight
|
306
|
+
DOM.getPropertyInt(@element, "offsetHeight")
|
307
|
+
end
|
308
|
+
|
309
|
+
#
|
310
|
+
# Gets the object's offset width in pixels. This is the total width of the
|
311
|
+
# object, including decorations such as border, margin, and padding.
|
312
|
+
#
|
313
|
+
# return:: the object's offset width
|
314
|
+
#
|
315
|
+
def getOffsetWidth
|
316
|
+
DOM.getPropertyInt(@element, "offsetWidth")
|
317
|
+
end
|
318
|
+
|
319
|
+
#
|
320
|
+
# Sets the object's height. This height does not include decorations such as
|
321
|
+
# border, margin, and padding.
|
322
|
+
#
|
323
|
+
# height:: the object's new height, in CSS units (e.g. "10px", "1em")
|
324
|
+
#
|
325
|
+
def setHeight(height)
|
326
|
+
# This exists to deal with an inconsistency in IE's implementation where
|
327
|
+
# it won't accept negative numbers in length measurements
|
328
|
+
# FIXME: assert extractLengthValue(height.trim().toLowerCase()) >= 0 : "CSS heights should not be negative";
|
329
|
+
|
330
|
+
DOM.setStyleAttribute(@element, "height", height)
|
331
|
+
end
|
332
|
+
|
333
|
+
#
|
334
|
+
# Sets the object's width. This width does not include decorations such as
|
335
|
+
# border, margin, and padding.
|
336
|
+
#
|
337
|
+
# width:: the object's new width, in CSS units (e.g. "10px", "1em")
|
338
|
+
#
|
339
|
+
def setWidth(width)
|
340
|
+
# This exists to deal with an inconsistency in IE's implementation where
|
341
|
+
# it won't accept negative numbers in length measurements
|
342
|
+
# FIXME: assert extractLengthValue(width.trim().toLowerCase()) >= 0 : "CSS widths should not be negative";
|
343
|
+
|
344
|
+
DOM.setStyleAttribute(@element, "width", width)
|
345
|
+
end
|
346
|
+
|
347
|
+
#
|
348
|
+
# Sets the object's size, in pixels, not including decorations such as
|
349
|
+
# border, margin, and padding.
|
350
|
+
#
|
351
|
+
# width:: the object's new width, in pixels
|
352
|
+
# height:: the object's new height, in pixels
|
353
|
+
#
|
354
|
+
def setPixelSize(width, height)
|
355
|
+
setWidth(width + "px") # if width >= 0
|
356
|
+
setHeight(height + "px") # if height >= 0
|
357
|
+
end
|
358
|
+
|
359
|
+
#
|
360
|
+
# Sets the object's size. This size does not include decorations such as
|
361
|
+
# border, margin, and padding.
|
362
|
+
#
|
363
|
+
# width:: the object's new width, in CSS units (e.g. "10px", "1em")
|
364
|
+
# height:: the object's new height, in CSS units (e.g. "10px", "1em")
|
365
|
+
#
|
366
|
+
def setSize(width, height)
|
367
|
+
setWidth(width)
|
368
|
+
setHeight(height)
|
369
|
+
end
|
370
|
+
|
371
|
+
#-------------------------------------------------------------------
|
372
|
+
# Event related
|
373
|
+
#-------------------------------------------------------------------
|
374
|
+
|
375
|
+
#
|
376
|
+
# Adds a set of events to be sunk by this object. Note that only
|
377
|
+
# widgets (+Widget+) may actually receive events, but can receive events
|
378
|
+
# from all objects contained within them.
|
379
|
+
#
|
380
|
+
# eventBitsToAdd:: a bitfield representing the set of events to be added
|
381
|
+
# to this element's event set
|
382
|
+
#
|
383
|
+
# See +Event+.
|
384
|
+
#
|
385
|
+
def sinkEvents(eventBitsToAdd)
|
386
|
+
DOM.sinkEvents(@element, eventBitsToAdd | DOM.getEventsSunk(@element))
|
387
|
+
end
|
388
|
+
|
389
|
+
#
|
390
|
+
# Removes a set of events from this object's event list.
|
391
|
+
#
|
392
|
+
# eventBitsToRemove:: a bitfield representing the set of events to be
|
393
|
+
# removed from this element's event set
|
394
|
+
#
|
395
|
+
# See #sinkEvents and +Event+.
|
396
|
+
#
|
397
|
+
def unsinkEvents(eventBitsToRemove)
|
398
|
+
DOM.sinkEvents(@element, DOM.getEventsSunk(@element) & (~eventBitsToRemove))
|
399
|
+
end
|
400
|
+
|
401
|
+
#-------------------------------------------------------------------
|
402
|
+
# Element access
|
403
|
+
#-------------------------------------------------------------------
|
404
|
+
|
405
|
+
#
|
406
|
+
# Gets a handle to the object's underlying DOM element.
|
407
|
+
#
|
408
|
+
# return:: the object's browser element
|
409
|
+
#
|
410
|
+
def getElement
|
411
|
+
@element
|
412
|
+
end
|
413
|
+
|
414
|
+
#
|
415
|
+
# Sets this object's browser element. UIObject subclasses must call this
|
416
|
+
# method before attempting to call any other methods.
|
417
|
+
#
|
418
|
+
# If the browser element has already been set, then the current element's
|
419
|
+
# position is located in the DOM and removed. The new element is added into
|
420
|
+
# the previous element's position.
|
421
|
+
#
|
422
|
+
# elem:: the object's new element
|
423
|
+
#
|
424
|
+
def setElement(elem)
|
425
|
+
if @element
|
426
|
+
# replace element in its parent with elem.
|
427
|
+
DOM.replace(@element, elem)
|
428
|
+
end
|
429
|
+
|
430
|
+
@element = elem
|
431
|
+
|
432
|
+
# We do not actually force the creation of a primary style name here.
|
433
|
+
# Instead, we do it lazily -- when it is aboslutely required --
|
434
|
+
# in getStyleName(), addStyleName(), and removeStyleName().
|
435
|
+
end
|
436
|
+
|
437
|
+
#-------------------------------------------------------------------
|
438
|
+
# Misc
|
439
|
+
#-------------------------------------------------------------------
|
440
|
+
|
441
|
+
#
|
442
|
+
# Gets the title associated with this object. The title is the 'tool-tip'
|
443
|
+
# displayed to users when they hover over the object.
|
444
|
+
#
|
445
|
+
# return:: the object's title
|
446
|
+
#
|
447
|
+
def getTitle
|
448
|
+
DOM.getProperty(@element, "title")
|
449
|
+
end
|
450
|
+
|
451
|
+
#
|
452
|
+
# Sets the title associated with this object. The title is the 'tool-tip'
|
453
|
+
# displayed to users when they hover over the object.
|
454
|
+
#
|
455
|
+
# To remove a title, pass +nil+ as argument.
|
456
|
+
#
|
457
|
+
# title:: the object's new title
|
458
|
+
#
|
459
|
+
def setTitle(title)
|
460
|
+
if title
|
461
|
+
DOM.setAttribute(@element, "title", title)
|
462
|
+
else
|
463
|
+
DOM.removeAttribute(@element, "title")
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
#
|
468
|
+
# Determines whether or not this object is visible.
|
469
|
+
#
|
470
|
+
# return:: +true+ if the object is visible
|
471
|
+
#
|
472
|
+
def isVisible
|
473
|
+
DOM.isVisible(@element)
|
474
|
+
end
|
475
|
+
|
476
|
+
#
|
477
|
+
# Sets whether this object is visible.
|
478
|
+
#
|
479
|
+
# visible:: +true+ to show the object, +false+ to hide it
|
480
|
+
#
|
481
|
+
def setVisible(visible=true)
|
482
|
+
DOM.setVisible(@element, visible)
|
483
|
+
end
|
484
|
+
|
485
|
+
#
|
486
|
+
# This method is overridden so that any object can be viewed in the debugger
|
487
|
+
# as an HTML snippet.
|
488
|
+
#
|
489
|
+
# return:: a string representation of the object
|
490
|
+
#
|
491
|
+
def to_s
|
492
|
+
@element ? DOM.to_s(@element) : "(null handle)"
|
493
|
+
end
|
494
|
+
|
495
|
+
end # class UIObject
|