aurita-gui 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,7 @@
1
+ === 0.1.0 / 2009-01-07
2
+
3
+ * First commit.
4
+ * Added base classes Element and HTML.
5
+ * Added API for forms.
6
+ * Added API for tables.
7
+
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+
2
+ Copyright (c) 2008-2009 Tobias Fuchs (fuchs@wortundform.de)
3
+ Aurita::GUI is a core module of Aurita, Copyright (c) 2004-2009 Tobias Fuchs (fuchs@wortundform.de)
4
+
5
+ (MIT Licence)
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
8
+ documentation files (the "Software"), to deal in the Software without restriction, including without limitation
9
+ the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
10
+ to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of
13
+ the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
16
+ THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
18
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19
+ DEALINGS IN THE SOFTWARE.
File without changes
@@ -0,0 +1,37 @@
1
+
2
+ require 'rake'
3
+
4
+ spec = Gem::Specification.new { |s|
5
+
6
+ s.name = 'aurita-gui'
7
+ s.rubyforge_project = 'aurita'
8
+ s.summary = 'Dead-simple object-oriented creation of HTML elements, including forms, tables and many more. '
9
+ s.description = <<-EOF
10
+ Aurita::GUI provides an intuitive and flexible API for object-oriented creation
11
+ of primitive and complex HTML elements, such as tables and forms.
12
+ It is a core module of the Aurita application framework, but it can be used
13
+ as stand-alone library in any context (such as rails).
14
+ As there seems to be a lack of ruby form generators, i decided to release this
15
+ part of Aurita in a single gem with no dependencies.
16
+ EOF
17
+ s.version = '0.1.0'
18
+ s.author = 'Tobias Fuchs'
19
+ s.email = 'fuchs@atomnode.net'
20
+ s.date = Time.now
21
+ s.files = '*.rb'
22
+ # s.add_dependency('postgres', '>= 0.1')
23
+ s.files = FileList['*',
24
+ 'lib/*',
25
+ 'lib/aurita-gui/*',
26
+ 'lib/aurita-gui/form/*',
27
+ 'bin/*',
28
+ 'test/*'].to_a
29
+
30
+ s.has_rdoc = true
31
+ s.rdoc_options << '--title' << 'Aurita::GUI' <<
32
+ '--main' << 'Aurita::GUI::HTML' <<
33
+ '--line-numbers'
34
+
35
+ s.homepage = 'http://aurita.wortundform.de/'
36
+
37
+ }
data/lib/aurita-gui.rb ADDED
@@ -0,0 +1,6 @@
1
+
2
+ require('aurita-gui/element')
3
+ require('aurita-gui/html')
4
+ require('aurita-gui/form')
5
+ require('aurita-gui/table')
6
+
@@ -0,0 +1,85 @@
1
+
2
+ require('aurita-gui/element')
3
+
4
+ module Aurita
5
+ module GUI
6
+
7
+ # Specialization of Aurita::GUI::Element, extending
8
+ # it by @icon to display in the button.
9
+ #
10
+ # Usage:
11
+ #
12
+ # b = Button.new(:type => :submit, # default is :button
13
+ # :icon => '/path/to/icon.png', # default is no icon
14
+ # :onclick => 'alert('button clicked'); ") {
15
+ # 'click me'
16
+ # }
17
+ #
18
+ # Change button text:
19
+ #
20
+ # b.content = 'Custom button text'
21
+ #
22
+ # Disable icon again:
23
+ #
24
+ # b.icon = false
25
+ #
26
+ class Button < Element
27
+ attr_accessor :icon
28
+
29
+ def initialize(params, &block)
30
+ params[:tag] = :button
31
+ params[:type] = :button unless params[:type]
32
+ @icon = params[:icon]
33
+ params.delete(:icon)
34
+ super(params, &block)
35
+ end
36
+
37
+ def content
38
+ if @icon then
39
+ return [ HTML.img(:src => @icon), @content ]
40
+ end
41
+ return @content
42
+ end
43
+
44
+ end
45
+
46
+ # Specialization of Aurita::GUI::Element for
47
+ # submit buttons. Set @tag to :input, @type to :submit.
48
+ # Block argument will be used as button label (:value)
49
+ # Example:
50
+ #
51
+ # b = Submit_Button.new(:class => :css_class) { 'click me' }
52
+ #
53
+ class Submit_Button < Element
54
+ def initialize(params, &block)
55
+ params[:tag] = :input
56
+ params[:type] = :submit unless params[:type]
57
+ if block_given? then
58
+ params[:value] = yield
59
+ end
60
+ super(params)
61
+ end
62
+ end
63
+
64
+ # Specialization of Aurita::GUI::Element for
65
+ # submit buttons. Set @tag to :input, @type to :reset.
66
+ # Block argument will be used as button label (:value)
67
+ # Example:
68
+ #
69
+ # b = Reset_Button.new(:class => :css_class) { 'click me' }
70
+ #
71
+ # Note that reset buttons in forms are considered
72
+ # bad style in terms of usability.
73
+ class Reset_Button < Element
74
+ def initialize(params, &block)
75
+ params[:tag] = :input
76
+ params[:type] = :reset unless params[:type]
77
+ if block_given? then
78
+ params[:value] = yield
79
+ end
80
+ super(params)
81
+ end
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,161 @@
1
+
2
+ module Aurita
3
+ module GUI
4
+
5
+ # GUI::Element is the base class for any rendering
6
+ # implementation.
7
+ # It consists of the following members:
8
+ #
9
+ # * @tag: The HTML tag to render.
10
+ # * @attrib: A hash storing tag attributes, like
11
+ # { :href => '/link/to/somewhere' }
12
+ # * @content: Content this element is wrapping.
13
+ # Content can be set in the constructor
14
+ # via parameter :content or using a
15
+ # block or by #content and #content=.
16
+ #
17
+ # Most methods invoked on an Element instance are
18
+ # redirected to return or set a tag attribute.
19
+ # Example:
20
+ #
21
+ # link = Element(:tag => :a) { 'klick me' }
22
+ # link.href = '/link/to/somewhere'
23
+ #
24
+ # Same as
25
+ #
26
+ # link = Element(:tag => :a,
27
+ # :content => 'click me',
28
+ # :href => '/link/to/somewhere')
29
+ #
30
+ # An Element instance can wrap one or more other
31
+ # elements:
32
+ #
33
+ # image_link = Element.new(:tag => :a, :href => '/link/') {
34
+ # Element.new(:tag => :img, :src => '/an_image.png')
35
+ # }
36
+ #
37
+ # In case an element has no content, it will render
38
+ # a self-closing tag, like <img ... />.
39
+ #
40
+ # In most cases you won't use class Element directly,
41
+ # but by using a factory like Aurita::GUI::HTML or
42
+ # by any derived class like Aurita::GUI::Form or
43
+ # Aurita::GUI::Table.
44
+ #
45
+ class Element
46
+
47
+ @@element_count = 0
48
+
49
+ attr_accessor :attrib, :type, :content, :parent, :tag
50
+
51
+ def initialize(params={}, &block)
52
+ @@element_count += 1
53
+ @id = @@element_count
54
+ @parent = params[:parent]
55
+ params.delete(:parent)
56
+
57
+ params[:tag] = :div if params[:tag].nil?
58
+
59
+ if block_given? then
60
+ @content = yield
61
+ else
62
+ @content = params[:content].to_s
63
+ end
64
+ params.delete(:content)
65
+ @tag = params[:tag]
66
+ params.delete(:tag)
67
+ # params[:id] = self.class.to_s.split('::')[-1].downcase + '_' << @@element_count.to_s if params[:id].nil?
68
+ params[:onclick] << ';' unless params[:onclick].nil? or params[:onclick].include?(';')
69
+
70
+ @attrib = params
71
+ # @attrib[:id] = @attrib[:id].to_s
72
+
73
+ end
74
+
75
+ # Return DOM id of this element.
76
+ def dom_id
77
+ @attrib[:id]
78
+ end
79
+ # Set DOM id of this element.
80
+ def dom_id=(value)
81
+ @attrib[:id] = value
82
+ end
83
+
84
+ # Render this element to a string and append another
85
+ # element.
86
+ def +(other)
87
+ return string << other.string if other.kind_of? Element
88
+ return string << other
89
+ end
90
+ alias << +
91
+
92
+ # Redirect methods to setting or retreiving tag
93
+ # attributes.
94
+ def method_missing(meth, value=nil)
95
+ return @attrib[meth] unless value or meth.to_s.include? '='
96
+ @attrib[meth.to_s.gsub('=','').intern] = value
97
+ end
98
+
99
+ # Define explicitly so built-in method #type
100
+ # is not invoked instead
101
+ def type=(type)
102
+ @attrib[:type] = type
103
+ end
104
+ # Alias definition for #dom_id=(value)
105
+ # Define explicitly so built-in method #id
106
+ # is not invoked instead
107
+ def id=(value)
108
+ @attrib[:id] = value
109
+ end
110
+ # Alias definition for #dom_id()
111
+ def id
112
+ @attrib[:id]
113
+ end
114
+
115
+ # Do not redirect random access operators.
116
+ def [](a)
117
+ raise ::Exception.new('Undefined method [] for ' << self.class.to_s)
118
+ end
119
+ # Do not redirect random access operators.
120
+ def []=(a,b)
121
+ raise ::Exception.new('Undefined method []= for ' << self.class.to_s)
122
+ end
123
+
124
+ # Static helper definition for clearing
125
+ # CSS floats.
126
+ def clear_floating
127
+ '<div style="clear: both;" />'
128
+ end
129
+
130
+ # Render this element to a string.
131
+ def string
132
+ attrib_string = ''
133
+ @attrib.each_pair { |name,value|
134
+ if value.instance_of?(Array) then
135
+ value = value.join(' ')
136
+ elsif
137
+ value.instance_of?(TrueClass) then
138
+ value = name
139
+ end
140
+ if !value.nil? then
141
+ value = value.to_s
142
+ attrib_string << name.to_s + '="' << value + '" '
143
+ end
144
+ }
145
+
146
+ if content.to_s != '' then
147
+ '<' << @tag.to_s << ' ' << attrib_string << '>' << "\n" <<
148
+ content.to_s +
149
+ '</' << @tag.to_s << '>' << "\n"
150
+ else
151
+ '<' << @tag.to_s << ' ' << attrib_string << '/>' << "\n"
152
+ end
153
+
154
+ end
155
+ alias to_s string
156
+
157
+ end # class
158
+
159
+ end # module
160
+ end # module
161
+
@@ -0,0 +1,232 @@
1
+
2
+ require('aurita-gui/element')
3
+ require('aurita-gui/html')
4
+ require('aurita-gui/form/form_field')
5
+ require('aurita-gui/form/form_error')
6
+ require('aurita-gui/form/input_field')
7
+ require('aurita-gui/form/hidden_field')
8
+ require('aurita-gui/form/options_field')
9
+ require('aurita-gui/form/select_field')
10
+ require('aurita-gui/form/radio_field')
11
+ require('aurita-gui/form/checkbox_field')
12
+ require('aurita-gui/form/fieldset')
13
+ require('aurita-gui/form/textarea_field')
14
+ require('aurita-gui/form/date_field')
15
+ require('aurita-gui/form/datetime_field')
16
+ require('aurita-gui/form/file_field')
17
+
18
+ module Aurita
19
+ module GUI
20
+
21
+
22
+ class Form_Field_Wrapper < Aurita::GUI::Element
23
+ attr_accessor :field
24
+
25
+ def initialize(field)
26
+ label_params = { :for => field.dom_id }
27
+ label_params[:id] = field.dom_id.to_s + '_label'
28
+ @content = [ HTML.label(label_params) { field.label }, field ]
29
+ params = { :tag => :li,
30
+ :content => @content,
31
+ :id => field.dom_id + '_wrap',
32
+ :class => field.class.to_s.split('::')[-1].downcase + '_wrap form_field' }
33
+ super(params)
34
+ end
35
+
36
+ end
37
+
38
+ class Form < Element
39
+
40
+ attr_accessor :method, :target, :action, :fields, :elements, :element_map
41
+
42
+ # Usage examples:
43
+ #
44
+ # form = Form.new(:method => :put # default: :post
45
+ # :action => '/where/to/send/form/'
46
+ # :onsubmit => "alert('submitting');") {
47
+ # [
48
+ # Input_Field.new(:name => :description, :label => 'Description'),
49
+ # Select_Field.new(:name => :category, :label => 'Select category')
50
+ # ]
51
+ # }
52
+ # textarea = GUI::Textarea.new(:name => :comment, :label => 'Comment')
53
+ # form.add(textarea)
54
+ #
55
+ # In case you want to override the form action (default: /aurita/dispatch),
56
+ # use :action_url:
57
+ #
58
+ # Form.new(:action_url => '/where/to/send/form')
59
+ # or
60
+ # Form.action_url = '/where/to/send/form'
61
+ #
62
+ #
63
+ def initialize(params, &block)
64
+ @action = params[:action]
65
+ @method = params[:method]
66
+ @fields = params[:fields]
67
+ @values = params[:values]
68
+ @method ||= :post
69
+ @fields ||= []
70
+ @elements = []
71
+ @element_map = {}
72
+ @values ||= {}
73
+ @title = false
74
+ if block_given? then
75
+ yield.each { |e| add(e) }
76
+ end
77
+ params.delete(:fields)
78
+ params.delete(:values)
79
+ params[:tag] = 'form'
80
+ params[:content] = content()
81
+ super(params)
82
+ end
83
+
84
+ # Returns field element map.
85
+ # An element map maps field names to elements of
86
+ # this form.
87
+ def attributes
88
+ @element_map
89
+ end
90
+
91
+ # Access form element by index or name (by index if
92
+ # parameter is of type Numeric, by name otherwhise)
93
+ def [](index)
94
+ return @elements[index] if index.kind_of? Numeric
95
+ return @element_map[index.to_s]
96
+ end
97
+
98
+ # Assign / overwrite field element with index form_index.
99
+ def []=(index, form_field)
100
+ @elements[index] = form_field
101
+ @content = false # Invalidate
102
+ end
103
+
104
+ # Delete form field with name field_name from
105
+ # this form.
106
+ def delete(field_name)
107
+ @element_map.delete(field_name.to_s)
108
+ end
109
+
110
+ # Iterate over form field elements.
111
+ # This would add a CSS class to all elements without
112
+ # a value:
113
+ #
114
+ # form.each { |element|
115
+ # element.class = 'missing' unless element.value
116
+ # }
117
+ #
118
+ def each(&block)
119
+ @elements.each(&block)
120
+ end
121
+
122
+ # Add form field element to this form.
123
+ def add(form_field_element)
124
+ if !form_field_element.dom_id then
125
+ form_field_element.dom_id = form_field_element.name.to_s.gsub('.','_')
126
+ end
127
+ @element_map[form_field_element.name.to_s] = form_field_element
128
+ @elements << form_field_element
129
+ @content = false # Invalidate
130
+ end
131
+
132
+ # Set field configuration. Form fields will be
133
+ # rendered in the same order as field names in the
134
+ # parameter array.
135
+ # In case an element's field name is not included
136
+ # in the array, it will not be rendered.
137
+ # Example:
138
+ #
139
+ # form.fields = [ :name, :description, :date ]
140
+ #
141
+ def fields=(attrib_array)
142
+ @fields = attrib_array.flatten.collect { |fieldname| fieldname.to_s }
143
+ @elements.each { |field|
144
+ @element_map[field.name.to_s] = field
145
+ }
146
+ end
147
+ alias set_field_config fields=
148
+
149
+ # Set field values for this form.
150
+ # Expects hash mapping field names to values.
151
+ # Example:
152
+ #
153
+ # form.values = { :name => 'Foo', :description => 'Bar', :date => '20081012' }
154
+ #
155
+ def values=(value_hash={})
156
+ @values = value_hash
157
+ end
158
+ alias set_values values=
159
+
160
+ # Set all elements to readonly rendering mode.
161
+ def readonly!
162
+ @elements.each { |e|
163
+ e.readonly!
164
+ }
165
+ end
166
+
167
+ # Return array of field names currently
168
+ # available for rendering.
169
+ def fields()
170
+ if !@fields || @fields.length == 0 then
171
+ @elements.each { |field|
172
+ @fields << field.name.to_s
173
+ @element_map[field.name.to_s] = field
174
+ }
175
+ end
176
+ return @fields
177
+ end
178
+
179
+ # Return underlying HTML element instance (HTML.ul),
180
+ # without wrapping HTML.form element.
181
+ def content
182
+ # TODO: Provide Fieldset instances
183
+ @content = []
184
+ if @title then
185
+ @content << HTML.h1(:class => :form_title) { @title }
186
+ end
187
+ fields().each { |field|
188
+ element = @element_map[field.to_s]
189
+ if element then
190
+ value = @values[element.name.to_s]
191
+ value ||= @values[element.name.to_s.intern]
192
+ element.value = value if value
193
+ if element.kind_of? Aurita::GUI::Hidden_Field then
194
+ @content << element
195
+ else
196
+ @content << Form_Field_Wrapper.new(element)
197
+ end
198
+ end
199
+ }
200
+ @content = HTML.ul(:class => :form_fields) { @content }
201
+ return @content
202
+ end
203
+
204
+ # Render this form to an HTML.form instance.
205
+ # Wraps result of #content.
206
+ def element
207
+ HTML.form(@params, :content => @content)
208
+ end
209
+
210
+ # Render this form to a string
211
+ def string
212
+ element().to_s
213
+ end
214
+ alias to_s string
215
+
216
+ # Set all form elements to readonly mode.
217
+ def readonly!
218
+ elements.each { |e|
219
+ e.readonly!
220
+ }
221
+ end
222
+ # Set all form elements to editable mode.
223
+ def editable!
224
+ elements.each { |e|
225
+ e.editable!
226
+ }
227
+ end
228
+
229
+ end
230
+
231
+ end
232
+ end