aurita-gui 0.1.0

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/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