cuca 0.01

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.
Files changed (52) hide show
  1. data/application_skeleton/README +21 -0
  2. data/application_skeleton/app/_controllers/application.rb +7 -0
  3. data/application_skeleton/app/_layouts/simple.rb +19 -0
  4. data/application_skeleton/app/_widgets/sourcecode.rb +21 -0
  5. data/application_skeleton/app/_widgets/test.rb +23 -0
  6. data/application_skeleton/app/demo.rb +64 -0
  7. data/application_skeleton/app/index.rb +39 -0
  8. data/application_skeleton/app/user/__default_username/index.rb +7 -0
  9. data/application_skeleton/conf/environment.rb +16 -0
  10. data/application_skeleton/log/access.log +1 -0
  11. data/application_skeleton/log/error.log +1 -0
  12. data/application_skeleton/log/messages +1 -0
  13. data/application_skeleton/public/css/style.css +27 -0
  14. data/application_skeleton/public/dispatch.cgi +31 -0
  15. data/application_skeleton/public/dispatch.fcgi +36 -0
  16. data/application_skeleton/public/img/cuca-seagull.png +0 -0
  17. data/application_skeleton/scripts/console +5 -0
  18. data/application_skeleton/scripts/console.rb +5 -0
  19. data/application_skeleton/scripts/server-lighttpd-fcgi.rb +116 -0
  20. data/application_skeleton/scripts/server-lighttpd.rb +109 -0
  21. data/application_skeleton/scripts/server-webrick.rb +26 -0
  22. data/application_skeleton/scripts/test.rb +8 -0
  23. data/application_skeleton/tests/widgets/link.rb +22 -0
  24. data/bin/cuca +43 -0
  25. data/lib/cuca/app.rb +317 -0
  26. data/lib/cuca/cgi_emu.rb +67 -0
  27. data/lib/cuca/cgi_fix.rb +58 -0
  28. data/lib/cuca/const.rb +3 -0
  29. data/lib/cuca/controller.rb +240 -0
  30. data/lib/cuca/generator/markaby.rb +80 -0
  31. data/lib/cuca/generator/view.rb +121 -0
  32. data/lib/cuca/layout.rb +62 -0
  33. data/lib/cuca/mimetypes.rb +89 -0
  34. data/lib/cuca/session.rb +143 -0
  35. data/lib/cuca/sessionflash.rb +56 -0
  36. data/lib/cuca/sessionpage.rb +41 -0
  37. data/lib/cuca/stdlib/arform.rb +208 -0
  38. data/lib/cuca/stdlib/arview.rb +16 -0
  39. data/lib/cuca/stdlib/form.rb +137 -0
  40. data/lib/cuca/stdlib/formerrors.rb +20 -0
  41. data/lib/cuca/stdlib/link.rb +37 -0
  42. data/lib/cuca/stdlib/list.rb +3 -0
  43. data/lib/cuca/stdlib/listwidget/dblist.rb +122 -0
  44. data/lib/cuca/stdlib/listwidget/list.rb +189 -0
  45. data/lib/cuca/stdlib/listwidget/querydef.rb +167 -0
  46. data/lib/cuca/stdlib/listwidget/staticdatalist.rb +79 -0
  47. data/lib/cuca/stdlib/slink.rb +30 -0
  48. data/lib/cuca/test/helpers.rb +42 -0
  49. data/lib/cuca/urlmap.rb +267 -0
  50. data/lib/cuca/widget.rb +212 -0
  51. data/lib/cuca.rb +68 -0
  52. metadata +141 -0
@@ -0,0 +1,208 @@
1
+ module Cuca::Stdlib
2
+
3
+ require 'form'
4
+ require 'cuca/generator/markaby'
5
+
6
+ # == Form's for ActiveRecord
7
+ # AR Form can work just by providing one model of ActiveRecord.
8
+ # Likly that you want to overwrite the form method to
9
+ # run a custom layout. You can use the fe* methods to
10
+ # build form elements for the model columns
11
+ #
12
+ # = Example:
13
+ #
14
+ # ARForm('user_edit', User.find_by_username('bones'),
15
+ # :disable_on_update => ['username', 'created'])
16
+ #
17
+ class ARFormWidget < FormWidget
18
+
19
+ include Cuca::Generator::Markaby
20
+
21
+ # valid options
22
+ # * :disabled_on_create => ['field_name_1', 'field_name_2', ..]
23
+ # switch off fields on new records
24
+ # * :diabled_on_update => ['field_name_1', 'field_name_2', ..]
25
+ # switch off fields on existing records
26
+ def output(form_name, model, options = {})
27
+ @model = model
28
+ @disabled_on_update = options[:disabled_on_update] || []
29
+ @disabled_on_create = options[:disabled_on_create] || []
30
+ @hidden_on_update = options[:hidden_on_update] || []
31
+ @hidden_on_create = options[:hidden_on_create] || []
32
+ super(form_name, options[:post_to])
33
+ end
34
+
35
+ def on_submit
36
+ controller.send(@form_name+'_submit', @model) unless controller.nil?
37
+ end
38
+
39
+ def validate
40
+ form if @_content.empty? # password fields might write hints to the validator...
41
+ @form_erros = {}
42
+ p = request_parameters.dup
43
+ p.delete(@submit_name)
44
+
45
+ # don't save empty passwords!!
46
+ $stderr.puts "Before validate: #{@password_fields.inspect}"
47
+ @password_fields ||= []
48
+ @password_fields.each do |pwf|
49
+ $stderr.puts "PWS: #{pwf} - #{p[pwf]}"
50
+ p.delete(pwf) if p[pwf].chomp.empty?
51
+ $stderr.puts "PWS: #{p.inspect}"
52
+ end
53
+
54
+ $stderr.puts "ARFORM Validate #{p.inspect}"
55
+ @model.attributes = p
56
+
57
+ return true if @model.valid?
58
+
59
+ @model.errors.each do |k,v|
60
+ @form_errors[k] = v
61
+ end
62
+ end
63
+
64
+ # to make a 2 digit string out a number
65
+ private
66
+ def twodig(n)
67
+ n.to_s.length == 1 ? "0"+n.to_s : n.to_s
68
+ end
69
+
70
+ def field_enable?(fname)
71
+ if @model.new_record? then
72
+ return @disabled_on_create.include?(fname) ? false : true
73
+ else
74
+ return @disabled_on_update.include?(fname) ? false : true
75
+ end
76
+ end
77
+ def field_hidden?(fname)
78
+ if @model.new_record? then
79
+ return @hidden_on_create.include?(fname) ? true : false
80
+ else
81
+ return @hidden_on_update.include?(fname) ? true : false
82
+ end
83
+ end
84
+
85
+
86
+ private
87
+ def fe_text(name, value,enabled)
88
+ "<input type='text' name='#{name}' value='#{value}' #{'disabled' unless enabled}>"
89
+ end
90
+
91
+ # the fe-password is special: will never contain a value and will not save the
92
+ # password if nothing was typed into the field
93
+ private
94
+ def fe_password(name,enabled)
95
+ @password_fields ||= []
96
+ @password_fields << name
97
+ r = "<input type='password' name='#{name}' #{'disabled' unless enabled}>"
98
+ if !@model.new_record? then
99
+ r << "<br><small>Leave empty to keep current password</small>"
100
+ end
101
+ return r
102
+ end
103
+
104
+ # this is to build a select box, example:
105
+ # fe_select('gender', [['f', 'female'],['m','Male']], true) or
106
+ # fe_select('gender', ['f','m'], true)
107
+ private
108
+ def fe_select(name, options, enabled)
109
+ r = "<select name='#{name}' #{'disabled' unless enabled}>\n"
110
+ options.each do |o|
111
+ ov = o.instance_of?(Array) ? o[0] : o
112
+ sel = ''
113
+ sel = ' selected' if @model.send(name.intern) == ov
114
+ if o.instance_of?(Array) then
115
+ r+="<option value='#{o[0]}'#{sel}>#{o[1]}</option>\n"
116
+ else
117
+ r+="<option value='#{o}'#{sel}>#{o}</option>\n"
118
+ end
119
+ end
120
+ r+="</option>\n"
121
+ end
122
+
123
+
124
+ def fe_datetime(name, v,enabled)
125
+ v = Time.now unless v
126
+ r = <<-EOS
127
+ <input type='text' name='#{name}' id='i_#{name}' value='#{v.year}/#{twodig(v.month)}/#{twodig(v.day)} #{v.hour}:#{v.min}' #{'disabled' unless enabled}>
128
+ EOS
129
+ if enabled then
130
+ r << <<-EOS
131
+ <input type='submit' id='s_#{name}' value='...'>
132
+ <script type="text/javascript">
133
+ Calendar.setup({
134
+ inputField : "i_#{name}", // id of the input field
135
+ ifFormat : "%Y/%m/%d %H:%M", // format of the input field
136
+ showsTime : true, // will display a time selector
137
+ button : "s_#{name}", // trigger for the calendar (button ID)
138
+ singleClick : true, // double-click mode
139
+ step : 1 // show all years in drop-down boxes (instead of every other year as default)
140
+ });
141
+ </script>
142
+ </input>
143
+ EOS
144
+ end
145
+ return r
146
+ end
147
+
148
+ def fe_bool(name,v,enabled)
149
+ r = ''
150
+ r << "<select name='#{name}' #{'disabled' unless enabled}>\n"
151
+ r << "<option #{"selected" if v} value='t'>true</option>\n"
152
+ r << "<option #{"selected" if !v} value='f'>false</option>\n"
153
+ r << "</select>\n"
154
+ end
155
+
156
+ def fe_int(name,v,enabled)
157
+ "<input type='text' name='#{name}' value='#{v}' #{'disabled' unless enabled} size=5>"
158
+ end
159
+
160
+ def fe(type, name, value='')
161
+ return '' if field_hidden?(name)
162
+ enabled = field_enable?(name)
163
+ r = ""
164
+ case(type)
165
+ when :string
166
+ r << fe_text(name,value,enabled)
167
+ when :boolean
168
+ r << fe_bool(name,value,enabled)
169
+ when :integer
170
+ r << fe_int(name,value,enabled)
171
+ when :datetime
172
+ r << fe_datetime(name,value,enabled)
173
+ when :password
174
+ r << fe_password(name, enabled)
175
+ end
176
+ return r
177
+ end
178
+
179
+ # build a form element for column name
180
+ def fe_for(column_name, hint='')
181
+ col = @model.column_for_attribute(column_name)
182
+ fe(col.type, col.name, @model.send(column_name.intern))
183
+ end
184
+
185
+
186
+ # you might want to replace this method
187
+ public
188
+ def form
189
+ r = mabtext { FormErrors(@form_errors) }
190
+ r << "<form action='#{@post_to}' method='POST'>\n"
191
+ r << "<table>"
192
+ @model.class.columns.each do |col|
193
+ k = col.name
194
+ v = @model.send(k.intern) # this allows us to overwrite accessors
195
+ r << "<tr><td>#{k}</td><td>#{fe(col.type,k,v)}</td></tr>"
196
+ end
197
+ r << "<tr><td><br/></td></tr>"
198
+ r << "<tr><td></td><td><input type='submit' value=#{@model.new_record? ? 'Save' : 'Update'} name='#{@submit_name}'></td></tr>"
199
+ r << "</table>\n</form>\n"
200
+ @_content = r
201
+ end
202
+
203
+
204
+ end
205
+
206
+
207
+
208
+ end
@@ -0,0 +1,16 @@
1
+
2
+ # This is a small widget to display an ActiveRecord Record
3
+ class ARViewWidget < Cuca::Widget
4
+
5
+ def output(model, headline='')
6
+ @model = model
7
+
8
+ r = "<table>"
9
+ @model.class.columns.each do |col|
10
+ r << "<tr><td>#{col.name}</td><td>#{@model.send(col.name.intern)}</td></tr>"
11
+ end
12
+ r << "</table>"
13
+ @_content = r
14
+ end
15
+
16
+ end
@@ -0,0 +1,137 @@
1
+ #
2
+ # == Cuca Standard Widget Library
3
+ # This namespace should contain a standard widget library.
4
+ #
5
+ # <b>Warning: The widgets you find here are fairly untested and might not work!!</b>
6
+ # Any request and patches - Welcome
7
+ # module Cuca::Stdlib
8
+
9
+ # == FormWidget
10
+ #
11
+ # To implement a form inherit this class and overwrite:
12
+ #
13
+ # * form - generate your form (as if it was the output method of a widget)
14
+ # - Use @form_name for your html form name
15
+ # - Use @submit_name for your submit button
16
+ # * validate - to validate a posted form
17
+ # - write @form_errors['element_name'] on errors (to handle them with FormErrors Widget)
18
+ # * setup - Define initial values for your form
19
+ #
20
+ # A form will call {form_name}_submit(result) on the CONTROLLER if the form was submitted
21
+ # and validation passed.
22
+ # If you don't want this, overwrite on_submit
23
+ #
24
+ # A form will use instance variables for form values
25
+ class FormWidget < Cuca::Widget
26
+
27
+ def posted?
28
+ return (request_method == 'POST' && !params[@submit_name].nil?)
29
+ end
30
+
31
+ # get from params and set instance variables
32
+ def load_variables
33
+ $stderr.puts "\n\nLoad Variables: #{$cgi.params.inspect}\n\n"
34
+ params.each_pair { |k,v| instance_variable_set('@'+k, v) ; $stderr.puts "Form: Setting #{k} - #{v}" }
35
+ end
36
+
37
+ # get from params and return them as hash
38
+ def get_variables
39
+ r = {}
40
+ params.each_pair { |k,v| r[k] = v }
41
+ return r
42
+ end
43
+
44
+ # Overwrite this method to setup initial values
45
+ # This method will not be called if the form get submitted.
46
+ def setup
47
+ end
48
+
49
+
50
+ # Create your form by overwriting this demo
51
+ # Name your submit button @submit_name, so the form can detect if it
52
+ # is submitted or not.
53
+ def form
54
+ end
55
+
56
+ # Overwrite this method with your validation code
57
+ # @form_errors hash with error messages
58
+ def validate
59
+ end
60
+
61
+ # If form is validated we call on_submit. Default behaviour is to call
62
+ # {form_name}_submit(result) on the CONTROLLER.
63
+ def on_submit
64
+ controller.send(@form_name+'_submit', get_variables) unless controller.nil?
65
+ end
66
+
67
+ def output(form_name, post_to = nil)
68
+ @form_name = form_name
69
+ @post_to = post_to || cgi.path_info
70
+ @submit_name = 'submit_'+@form_name
71
+ @form_errors = {}
72
+
73
+ if posted? then
74
+ load_variables
75
+ validate
76
+ if @form_errors.empty? then
77
+ clear # submitted forms should not have any content that might have been generated
78
+ return on_submit
79
+ else
80
+ form
81
+ end
82
+ else
83
+ setup
84
+ form
85
+ end
86
+ end
87
+ end
88
+
89
+
90
+
91
+ require 'cuca/generator/markaby'
92
+
93
+ class TestFormWidget < FormWidget
94
+
95
+ include Cuca::Generator::Markaby
96
+
97
+ def setup
98
+ @demo_input = "enter something"
99
+ end
100
+
101
+ def make_tips
102
+ @form_errors.each_pair do |k,v|
103
+ hints[:tips] ||= []
104
+ hints[:tips] << { :id => k, :title => "Error in form", :text => v}
105
+ end
106
+ end
107
+
108
+
109
+ def validate
110
+ # validate form return true/false
111
+ if @demo_input != 'demo' then
112
+ @form_errors['demo_input'] = "I said please enter 'demo' but you entered #{@demo_input}"
113
+ end
114
+ make_tips
115
+ true
116
+ end
117
+
118
+ def form
119
+ mab {
120
+
121
+ FormErrors(@form_errors)
122
+
123
+ form( :action=>@post_to, :method=>'post') { # :name=>@form_name,
124
+ text "This is a demo form, overwrite 'form' method. Enter 'demo'"
125
+ br
126
+ E('demo_input', true) { input(:type => 'text', :value => @demo_input, :name=>'demo_input'); text @error_text }
127
+ br
128
+ br
129
+ input(:type => 'submit', :value => 'save', :name => @submit_name)
130
+ }
131
+ }
132
+ end
133
+
134
+ end
135
+
136
+
137
+ # end
@@ -0,0 +1,20 @@
1
+ require 'cuca/generator/markaby'
2
+
3
+ # this widget you can use within a form to display all form errors
4
+ class FormErrorsWidget < Cuca::Widget
5
+
6
+ include Cuca::Generator::Markaby
7
+
8
+ def output(form_errors, title = nil)
9
+ return if form_errors.empty?
10
+ mab {
11
+ b title ? title : "Form contains errors"
12
+ ul {
13
+ form_errors.each_pair { |name, value|
14
+ li { b {name}; text " - #{value}" }
15
+ }
16
+ }
17
+ }
18
+ end
19
+
20
+ end
@@ -0,0 +1,37 @@
1
+ require 'cuca/generator/markaby'
2
+
3
+
4
+ # A markaby link - Please use with care!! it's slow! Better to use SLinkWidget.
5
+ class LinkWidget < Cuca::Widget
6
+
7
+ include Cuca::Generator::Markaby
8
+
9
+ private
10
+ def build_href(target, params)
11
+ r = target
12
+
13
+ r=r+"?" unless params.empty?
14
+
15
+ params.each_key do |key|
16
+ r = r + '&' unless r[r.size-1].chr == '?'
17
+ r = "#{r}#{key}=#{params[key]}"
18
+ end
19
+ return r
20
+ end
21
+
22
+ # public
23
+ # def output(target, params = {}, tag_attrib = {}, &block)
24
+ #
25
+ # end
26
+
27
+
28
+ public
29
+ def output(target, params = {}, tag_attrib = {}, &block)
30
+ @attribs = tag_attrib
31
+ @attribs[:href] = build_href(target, params)
32
+ @block = block
33
+ mab {
34
+ a(@attribs) { text capture(&block) }
35
+ }
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ require 'cuca/stdlib/listwidget/list'
2
+ require 'cuca/stdlib/listwidget/dblist'
3
+ require 'cuca/stdlib/listwidget/staticdatalist'
@@ -0,0 +1,122 @@
1
+ require 'cuca/stdlib/listwidget/list'
2
+ require 'active_record'
3
+
4
+ # List with Active Record model as data source
5
+ #
6
+ # DBList('dblistname', User, :columns => [ { :id => 'id', :query => 'user.id', :display=>'ID' },
7
+ # { :id => 'name', :display=>'Name', :searchable=>false } ])
8
+ #
9
+ # Options:
10
+ # :joins => ActiveRecord find :joins options.
11
+ #
12
+ # :columns: Columns possible flags:
13
+ # :id => [required] name. Likly this is the database column name
14
+ # :query => [optional] how to query the id (eg: users.name) . If false then treated as virtual column
15
+ # :display => [optional] title for the column
16
+ # :searchable => [optional] true/false if this column can be searched (default autodetect)
17
+ # :sortable = => [optional] true/false if columns can be sorted (default autodetect)
18
+ # DBLIST specific is only :query
19
+ class DBListWidget < BaseList
20
+ def columns
21
+ # $stderr.puts " Getting Columns: #{@columns}"
22
+ @columns
23
+ end
24
+
25
+ # returns :query field by :id (only :id is defined in the QueryDef)
26
+ def wc_query_field(field_id)
27
+ @columns.each do |c|
28
+ if c[:id] == field_id then
29
+ return c[:query]
30
+ end
31
+ end
32
+ field_id
33
+ end
34
+
35
+ def where_clause(query_def)
36
+ res = []
37
+ query_def.filters.each_pair do |k,v|
38
+ next if (v.nil? || v == '')
39
+ if @model_class.columns_hash.include?(k) && @model_class.columns_hash[k].number? then
40
+ res << "#{wc_query_field(k)} = #{v}"
41
+ else
42
+ res << "#{wc_query_field(k)} LIKE '%#{v}%'"
43
+ end
44
+ end
45
+ wc = "true"
46
+ res.collect { |e| "(#{e})" }.each { |c| wc+=" AND #{c}" }
47
+ wc+= " AND #{@extra_conditions}" if @extra_conditions != ''
48
+ # $stderr.puts "WHERE clause is #{wc}"
49
+ return wc
50
+ end
51
+
52
+ # transform a active record result to an [[]]- array
53
+ def normalize_result(ar_res)
54
+ res = []
55
+ ar_res.each do |r|
56
+ c = []
57
+ columns.each do |col|
58
+ # fixme: this doesn't catch join table results!!!
59
+ if @model_class.column_methods_hash[col[:id].intern] then
60
+ c << r.send(col[:id].to_sym)
61
+ else
62
+ c << ''
63
+ end
64
+ end
65
+ res << c
66
+ end
67
+ res
68
+ end
69
+
70
+ def query(query_def)
71
+ findstuff = {:conditions => where_clause(query_def) }
72
+ findstuff[:order] = query_def.order_by unless (query_def.order_by.nil? || query_def.order_by == '')
73
+ findstuff[:offset] = query_def.range.first
74
+ findstuff[:limit] = query_def.range.last-query_def.range.first+1
75
+ findstuff[:joins] = @joins || nil
76
+ sel = @columns.collect do |c|
77
+ ret = c.has_key?(:query) ? "#{c[:query]} as #{c[:id]}" : c[:id]
78
+ ret = nil if c[:query] == false
79
+ ret
80
+ end
81
+ findstuff[:select] = sel.compact.join(',')
82
+ # $stderr.puts "Find-Stuff: #{findstuff.inspect}"
83
+ @data = @model_class.find(:all, findstuff)
84
+ @data = normalize_result(@data)
85
+ @total_rows= @model_class.count(:conditions => where_clause(query_def), :joins => @joins)
86
+ # $stderr.puts "Query: #{@data.inspect} - #{query_def.order_by.inspect}"
87
+ end
88
+
89
+ def setup
90
+ super
91
+ end
92
+
93
+
94
+ # this will fix/add searchable/sortable and query flag
95
+ def fixup_columns
96
+ @columns.each_index do |idx|
97
+
98
+ if @columns[idx][:searchable].nil? then
99
+ @columns[idx][:searchable] = @model_class.column_methods_hash[@columns[idx][:id].intern] ? true : false
100
+ end
101
+ @columns[idx][:query] = @columns[idx][:id] if @columns[idx][:query].nil?
102
+
103
+ if @columns[idx][:sortable].nil? then
104
+ @columns[idx][:sortable] = @columns[idx][:query] == false ? false : true
105
+ end
106
+
107
+ end
108
+ end
109
+
110
+ def output(list_name, model_class = nil, data_setup = {})
111
+ @columns = data_setup[:columns] || []
112
+ @extra_conditions = data_setup[:conditons] || ""
113
+ @joins = data_setup[:joins] || ""
114
+ @model_class = model_class || nil
115
+ setup
116
+ fixup_columns
117
+ # $stderr.puts @columns.inspect
118
+ @columns.freeze
119
+ @extra_conditions.freeze
120
+ super(list_name)
121
+ end
122
+ end