superchris-rubyjs 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|