cuca 0.01

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