ydim-html 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.travis.yml +29 -0
  4. data/Gemfile +12 -0
  5. data/History.txt +11 -0
  6. data/LICENSE.txt +339 -0
  7. data/Manifest.txt +47 -0
  8. data/Rakefile +21 -0
  9. data/bin/ydim-htmld +38 -0
  10. data/doc/favicon.ico +0 -0
  11. data/doc/index.rbx +16 -0
  12. data/doc/resources/javascript/dojo.js +5940 -0
  13. data/doc/resources/javascript/iframe_history.html +53 -0
  14. data/doc/resources/javascript/ydim.js +67 -0
  15. data/doc/resources/ydim/ydim.css +113 -0
  16. data/lib/ydim/html.rb +10 -0
  17. data/lib/ydim/html/config.rb +37 -0
  18. data/lib/ydim/html/state/ajax_values.rb +17 -0
  19. data/lib/ydim/html/state/autoinvoice.rb +94 -0
  20. data/lib/ydim/html/state/confirm.rb +16 -0
  21. data/lib/ydim/html/state/debitor.rb +82 -0
  22. data/lib/ydim/html/state/debitors.rb +24 -0
  23. data/lib/ydim/html/state/global.rb +100 -0
  24. data/lib/ydim/html/state/global_predefine.rb +14 -0
  25. data/lib/ydim/html/state/init.rb +21 -0
  26. data/lib/ydim/html/state/invoice.rb +180 -0
  27. data/lib/ydim/html/state/invoices.rb +70 -0
  28. data/lib/ydim/html/state/pdf.rb +17 -0
  29. data/lib/ydim/html/util/lookandfeel.rb +133 -0
  30. data/lib/ydim/html/util/server.rb +37 -0
  31. data/lib/ydim/html/util/session.rb +29 -0
  32. data/lib/ydim/html/util/validator.rb +63 -0
  33. data/lib/ydim/html/version.rb +7 -0
  34. data/lib/ydim/html/view/ajax_values.rb +27 -0
  35. data/lib/ydim/html/view/autoinvoice.rb +80 -0
  36. data/lib/ydim/html/view/autoinvoices.rb +42 -0
  37. data/lib/ydim/html/view/confirm.rb +28 -0
  38. data/lib/ydim/html/view/debitor.rb +118 -0
  39. data/lib/ydim/html/view/debitors.rb +45 -0
  40. data/lib/ydim/html/view/htmlgrid.rb +104 -0
  41. data/lib/ydim/html/view/init.rb +30 -0
  42. data/lib/ydim/html/view/invoice.rb +218 -0
  43. data/lib/ydim/html/view/invoices.rb +159 -0
  44. data/lib/ydim/html/view/navigation.rb +29 -0
  45. data/lib/ydim/html/view/pdf.rb +24 -0
  46. data/lib/ydim/html/view/template.rb +71 -0
  47. data/readme.md +28 -0
  48. data/spec/smoketest_spec.rb +234 -0
  49. data/spec/spec_helper.rb +117 -0
  50. data/spec/stub/http_server.rb +157 -0
  51. data/test/selenium.rb +1690 -0
  52. data/test/selenium/selenium-server.jar +0 -0
  53. data/test/selenium/test_autoinvoice.rb +319 -0
  54. data/test/selenium/test_debitor.rb +344 -0
  55. data/test/selenium/test_debitors.rb +47 -0
  56. data/test/selenium/test_init.rb +105 -0
  57. data/test/selenium/test_invoice.rb +296 -0
  58. data/test/selenium/test_invoices.rb +176 -0
  59. data/test/selenium/unit.rb +125 -0
  60. data/test/stub/http_server.rb +141 -0
  61. data/test/suite.rb +15 -0
  62. data/ydim-html.gemspec +36 -0
  63. metadata +302 -0
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ # HtmlGrid -- ydim -- 13.01.2006 -- hwyss@ywesee.com
4
+
5
+ require 'htmlgrid/component'
6
+ require 'htmlgrid/composite'
7
+ require 'htmlgrid/errormessage'
8
+ require 'htmlgrid/form'
9
+ require 'htmlgrid/input'
10
+ require 'htmlgrid/inputtext'
11
+ require 'htmlgrid/list'
12
+ require 'htmlgrid/pass'
13
+
14
+ module HtmlGrid
15
+ class Component
16
+ HTTP_HEADERS = {
17
+ "Cache-Control" => "no-cache, max-age=3600, must-revalidate",
18
+ 'Content-Type' => 'text/html; charset=UTF-8',
19
+ }
20
+ class << self
21
+ def escaped(*names)
22
+ names.each { |name|
23
+ define_method(name) { |model|
24
+ number_format escape(model.send(name))
25
+ }
26
+ }
27
+ end
28
+ def links(event, *names)
29
+ names.each { |name|
30
+ define_method(name) { |model|
31
+ link = HtmlGrid::Link.new(name, model, @session, self)
32
+ args = {:unique_id => model.unique_id}
33
+ link.href = @lookandfeel._event_url(event, args)
34
+ link.value = model.send(name)
35
+ link
36
+ }
37
+ }
38
+ end
39
+ end
40
+ def escape(value)
41
+ CGI.escape(format(value))
42
+ end
43
+ def format(value)
44
+ case value
45
+ when Float
46
+ sprintf("%1.#{self.precision}f", value)
47
+ else
48
+ value.to_s
49
+ end
50
+ end
51
+ def number_format(string)
52
+ string.reverse.gsub(/\d{3}(?=\d)(?!\d*\.)/) do |match|
53
+ match << "'"
54
+ end.reverse
55
+ end
56
+ def precision
57
+ mdl = @session.state.model
58
+ if(mdl.respond_to?(:precision))
59
+ mdl.precision
60
+ else
61
+ 2
62
+ end
63
+ end
64
+ end
65
+ class Composite
66
+ LEGACY_INTERFACE = false
67
+ end
68
+ class Form
69
+ include HtmlGrid::ErrorMessage
70
+ DEFAULT_CLASS = HtmlGrid::InputText
71
+ LABELS = true
72
+ def init
73
+ super
74
+ error_message
75
+ end
76
+ end
77
+ class InputText
78
+ CSS_CLASS = 'large'
79
+ end
80
+ class List
81
+ STRIPED_BG = false
82
+ def List.ajax_inputs(*keys)
83
+ keys.each { |key|
84
+ define_method(key) { |model|
85
+ name = "#{key}[#{model.index}]"
86
+ input = HtmlGrid::InputText.new(name, model, @session, self)
87
+ input.value = format(model.send(key))
88
+ input.css_id = name
89
+ args = [
90
+ :unique_id, @session.state.model.unique_id,
91
+ :index, model.index,
92
+ key, nil,
93
+ ]
94
+ url = @lookandfeel.event_url(:ajax_item, args)
95
+ input.set_attribute('onChange', "reload_data('#{url}' + sbsm_encode(this.value))")
96
+ input
97
+ }
98
+ }
99
+ end
100
+ end
101
+ class Pass
102
+ CSS_CLASS = 'large'
103
+ end
104
+ end
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ # Html::View::Init -- ydim -- 12.01.2006 -- hwyss@ywesee.com
4
+
5
+ require 'ydim/html/view/template'
6
+ require 'htmlgrid/pass'
7
+ require 'htmlgrid/inputtext'
8
+
9
+ module YDIM
10
+ module Html
11
+ module View
12
+ class InitForm < HtmlGrid::Form
13
+ COMPONENTS = {
14
+ [0,0] => :email,
15
+ [0,1] => :pass,
16
+ [1,2] => :submit,
17
+ }
18
+ EVENT = :login
19
+ SYMBOL_MAP = {
20
+ :email => HtmlGrid::InputText,
21
+ :pass => HtmlGrid::Pass,
22
+ }
23
+ end
24
+ class Init < Template
25
+ CONTENT = InitForm
26
+ FOOT = nil
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ # Html::View::Invoice -- ydim -- 16.01.2006 -- hwyss@ywesee.com
4
+
5
+ require 'ydim/html/view/template'
6
+ require 'htmlgrid/form'
7
+ require 'htmlgrid/inputcheckbox'
8
+ require 'htmlgrid/inputdate'
9
+ require 'htmlgrid/errormessage'
10
+ require 'htmlgrid/select'
11
+ require 'htmlgrid/textarea'
12
+
13
+ module YDIM
14
+ module Html
15
+ module View
16
+ class SpanValue < HtmlGrid::Value
17
+ def init
18
+ super
19
+ @attributes.store('id', @name)
20
+ end
21
+ def to_html(context)
22
+ context.span(@attributes) { number_format escape(@value) }
23
+ end
24
+ end
25
+ class ItemList < HtmlGrid::List
26
+ COMPONENTS = {
27
+ [0,0] => :time,
28
+ [1,0] => :text,
29
+ [2,0] => :quantity,
30
+ [3,0] => :unit,
31
+ [4,0] => :price,
32
+ [5,0] => :total_netto,
33
+ [6,0] => :delete,
34
+ }
35
+ CSS_ID = 'items'
36
+ CSS_MAP = {
37
+ [0,0] => 'standard-width',
38
+ [5,0] => 'right',
39
+ }
40
+ COMPONENT_CSS_MAP = {
41
+ [1,0] => 'extralarge',
42
+ [2,0] => 'small',
43
+ [3,0] => 'medium',
44
+ [4,0] => 'medium',
45
+ }
46
+ DEFAULT_CLASS = HtmlGrid::InputText
47
+ SORT_DEFAULT = nil
48
+ ajax_inputs :text, :quantity, :unit, :price
49
+ def compose_footer(offset)
50
+ link = HtmlGrid::Button.new(:create_item, @model, @session, self)
51
+ args = { :unique_id => @session.state.model.unique_id }
52
+ url = @lookandfeel.event_url(:ajax_create_item, args)
53
+ link.set_attribute('onClick', "reload_list('items', '#{url}');")
54
+ @grid.add(link, *offset)
55
+ end
56
+ def delete(model)
57
+ link = HtmlGrid::Link.new(:delete, model, @session, self)
58
+ args = {
59
+ :unique_id => @session.state.model.unique_id,
60
+ :index => model.index,
61
+ }
62
+ url = @lookandfeel.event_url(:ajax_delete_item, args)
63
+ link.href = "javascript: reload_list('items', '#{url}')"
64
+ link
65
+ end
66
+ def time(model)
67
+ if(time = model.time)
68
+ @lookandfeel.format_time(model.time)
69
+ end
70
+ end
71
+ def total_netto(model)
72
+ val = SpanValue.new(:total_netto, model, @session, self)
73
+ val.css_id = "total_netto#{model.index}"
74
+ val
75
+ end
76
+ end
77
+ class InvoiceTotalComposite < HtmlGrid::Composite
78
+ COMPONENTS = {
79
+ [0,0] => :total_netto,
80
+ [0,1] => :vat,
81
+ [0,2] => :total_brutto,
82
+ }
83
+ CSS_ID = 'total'
84
+ CSS_MAP = {
85
+ [1,0,1,3] => 'right',
86
+ }
87
+ DEFAULT_CLASS = SpanValue
88
+ LABELS = true
89
+ end
90
+ class InvoiceInnerComposite < HtmlGrid::Composite
91
+ include HtmlGrid::ErrorMessage
92
+ links :debitor, :name, :email
93
+ COMPONENTS = {
94
+ [0,0] => :unique_id,
95
+ [0,1,0] => :debitor_name,
96
+ [1,1,1] => 'dash',
97
+ [1,1,2] => :debitor_email,
98
+ [0,2] => :description,
99
+ [0,3] => :date,
100
+ [1,3] => :payment_period,
101
+ [0,4] => :currency,
102
+ [0,5] => :precision,
103
+ [0,6] => :suppress_vat,
104
+ }
105
+ COMPONENT_CSS_MAP = {
106
+ [0,2] => 'extralarge',
107
+ [0,5] => 'small',
108
+ }
109
+ DEFAULT_CLASS = HtmlGrid::Value
110
+ LABELS = true
111
+ SYMBOL_MAP = {
112
+ :date => HtmlGrid::InputDate,
113
+ :description => HtmlGrid::InputText,
114
+ :invoice_interval => HtmlGrid::Select,
115
+ :reminder_subject => HtmlGrid::InputText,
116
+ }
117
+ def init
118
+ super
119
+ error_message
120
+ end
121
+ def currency(model)
122
+ select = HtmlGrid::Select.new(:currency, model, @session, self)
123
+ if(model.unique_id)
124
+ select.set_attribute('onChange', "reload_form('invoice', 'ajax_invoice');")
125
+ end
126
+ select
127
+ end
128
+ def debitor_email(model)
129
+ email(model.debitor)
130
+ end
131
+ def debitor_name(model)
132
+ link = name(model.debitor)
133
+ link.label = true
134
+ link
135
+ end
136
+ def payment_period(model)
137
+ @lookandfeel.lookup(:payment_period, model.payment_period.to_i)
138
+ end
139
+ def precision(model)
140
+ input = HtmlGrid::InputText.new(:precision, model, @session, self)
141
+ if(model.unique_id)
142
+ input.set_attribute('onChange', "reload_form('invoice', 'ajax_invoice');")
143
+ end
144
+ input
145
+ end
146
+ def suppress_vat(model)
147
+ input = HtmlGrid::InputCheckbox.new(:suppress_vat, model, @session, self)
148
+ if(model.unique_id)
149
+ input.set_attribute('onClick', "reload_form('invoice', 'ajax_invoice');")
150
+ end
151
+ input
152
+ end
153
+ end
154
+ class InvoiceComposite < HtmlGrid::DivComposite
155
+ include HtmlGrid::FormMethods
156
+ FORM_ID = 'invoice'
157
+ COMPONENTS = {
158
+ [0,0] => InvoiceInnerComposite,
159
+ [0,1] => :items,
160
+ [0,2] => InvoiceTotalComposite,
161
+ [0,3] => :submit,
162
+ [1,3] => :pdf,
163
+ [2,3] => :send_invoice,
164
+ }
165
+ CSS_MAP = {
166
+ 3 => 'padded'
167
+ }
168
+ EVENT = :update
169
+ def init
170
+ if(@model.unique_id.nil?)
171
+ @components = {
172
+ [0,0] => components[[0,0]],
173
+ [0,1] => :submit,
174
+ }
175
+ @css_map = { 1 => 'padded' }
176
+ elsif(@model.items.empty?)
177
+ @components = {
178
+ [0,0] => components[[0,0]],
179
+ [0,1] => :items,
180
+ [0,2] => :submit,
181
+ }
182
+ @css_map = { 2 => 'padded' }
183
+ end
184
+ super
185
+ end
186
+ def hidden_fields(context)
187
+ super << context.hidden('unique_id', @model.unique_id)
188
+ end
189
+ def items(model)
190
+ ItemList.new(model.items, @session, self)
191
+ end
192
+ def pdf(model)
193
+ button = HtmlGrid::Button.new(:pdf, model, @session, self)
194
+ url = @lookandfeel._event_url(:pdf, {:unique_id => model.unique_id})
195
+ button.set_attribute('onClick', "document.location.href='#{url}'")
196
+ button
197
+ end
198
+ def send_invoice(model)
199
+ button(:send_invoice, model)
200
+ end
201
+ def button(key, model)
202
+ button = HtmlGrid::Button.new(key, model, @session, self)
203
+ url = @lookandfeel._event_url(key, {:unique_id => model.unique_id})
204
+ button.set_attribute('onClick',
205
+ "this.form.event.value='#{key}'; this.form.submit()")
206
+ button
207
+ end
208
+ end
209
+ class Invoice < Template
210
+ CONTENT = InvoiceComposite
211
+ def init
212
+ css_map[1] = @model.status
213
+ super
214
+ end
215
+ end
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ # Html::View::Invoices -- ydim -- 13.01.2006 -- hwyss@ywesee.com
4
+
5
+ require 'htmlgrid/list'
6
+ require 'ydim/html/view/template'
7
+
8
+ module YDIM
9
+ module Html
10
+ module View
11
+ class InvoiceList < HtmlGrid::List
12
+ COMPONENTS = {
13
+ [0,0] => :unique_id,
14
+ [1,0] => :name,
15
+ [2,0] => :email,
16
+ [3,0] => :description,
17
+ [4,0] => :formatted_date,
18
+ [5,0] => :toggle_payment_received,
19
+ [6,0] => :total_netto,
20
+ [7,0] => :total_brutto,
21
+ [8,0] => :currency,
22
+ [9,0] => :send_invoice,
23
+ [10,0] => :pdf,
24
+ [11,0] => :toggle_deleted,
25
+ }
26
+ CSS_ID = 'invoices'
27
+ CSS_MAP = {
28
+ [6,0,2] => 'right',
29
+ }
30
+ SORT_DEFAULT = nil
31
+ class << self
32
+ def debitor_links(*names)
33
+ names.each { |name|
34
+ define_method(name) { |model|
35
+ link = HtmlGrid::Link.new(name, model, @session, self)
36
+ link.href = @lookandfeel._event_url(:debitor,
37
+ {:unique_id => model.debitor_id})
38
+ str = model.send("debitor_#{name}").to_s
39
+ if(str.length > 30)
40
+ str = str[0,27] << '...'
41
+ end
42
+ link.value = str
43
+ link
44
+ }
45
+ }
46
+ end
47
+ def toggle(name, on, off)
48
+ define_method("toggle_#{name}") { |model|
49
+ current = model.send(name)
50
+ key = current ? off : on
51
+ link = HtmlGrid::Link.new(key, model, @session, self)
52
+ args = {
53
+ :unique_id => model.unique_id,
54
+ name => !current,
55
+ }
56
+ url = @lookandfeel._event_url("ajax_#{css_id}", args)
57
+ link.href = "javascript: reload_list('#{css_id}', '#{url}')"
58
+ link
59
+ }
60
+ end
61
+ end
62
+ links :invoice, :date, :unique_id, :description
63
+ debitor_links :name, :email
64
+ escaped :total_netto, :total_brutto
65
+ toggle :deleted, :toggle_deleted, :toggle_recovered
66
+ toggle :payment_received, :toggle_paid, :toggle_unpaid
67
+ def row_css(model, bg_flag)
68
+ [super, model.status].compact.join(' ')
69
+ end
70
+ def compose_footer(offset)
71
+ garbage = false
72
+ netto = 0.0
73
+ brutto = 0.0
74
+ total = @model.each { |invoice|
75
+ garbage = true if(invoice.deleted)
76
+ netto += invoice.total_netto
77
+ brutto += invoice.total_brutto
78
+ }
79
+ if(garbage)
80
+ button = HtmlGrid::Button.new(:collect_garbage, @model, @session, self)
81
+ url = @lookandfeel._event_url(:ajax_collect_garbage)
82
+ button.set_attribute('onClick', "reload_list('invoices', '#{url}');")
83
+ @grid.add(button, *offset)
84
+ @grid.set_colspan(*offset)
85
+ else
86
+ label = HtmlGrid::LabelText.new(:total, @model, @session, self)
87
+ lpos = column_position(:name, offset)
88
+ @grid.add(label, *lpos)
89
+ @grid.set_colspan(*lpos.push(2))
90
+ total(:total_netto, netto, offset)
91
+ total(:total_brutto, brutto, offset)
92
+ lpos = column_position(:currency, offset)
93
+ @grid.add(Html.config.currency, *lpos)
94
+ end
95
+ end
96
+ def total(key, total, offset)
97
+ tpos = column_position(key, offset)
98
+ @grid.add(number_format(format(total)), *tpos)
99
+ @grid.add_attribute('class', 'right total', *tpos)
100
+ end
101
+ def column_position(key, offset)
102
+ pos = components.key(key)
103
+ [pos.at(0) + offset.at(0), pos.at(1) + offset.at(1)]
104
+ end
105
+ def formatted_date(model)
106
+ if(date = model.date)
107
+ link = date(model)
108
+ link.value = @lookandfeel.format_date(date)
109
+ link
110
+ end
111
+ end
112
+ def pdf(model)
113
+ link = HtmlGrid::Link.new(:pdf, model, @session, self)
114
+ link.href = @lookandfeel._event_url(:pdf, {:unique_id => model.unique_id})
115
+ link
116
+ end
117
+ def send_invoice(model)
118
+ if(model.status == 'is_due')
119
+ link = HtmlGrid::Link.new(:send_invoice, model, @session, self)
120
+ link.href = @lookandfeel._event_url(:send_invoice,
121
+ {:unique_id => model.unique_id})
122
+ link
123
+ end
124
+ end
125
+ end
126
+ class InvoicesSubnavigation < HtmlGrid::DivComposite
127
+ def InvoicesSubnavigation.status_links(*names)
128
+ names.each { |name|
129
+ define_method(name) { |model|
130
+ link = HtmlGrid::Link.new(name, model, @session, self)
131
+ url = @lookandfeel._event_url(:ajax_status, {:status => name })
132
+ link.href = "javascript:reload_list('invoices', '#{url}');"
133
+ link
134
+ }
135
+ }
136
+ end
137
+ status_links :is_open, :is_paid, :is_due, :is_trash
138
+ COMPONENTS = {
139
+ [0,0] => :is_open,
140
+ [1,0] => :is_due,
141
+ [2,0] => :is_paid,
142
+ [3,0] => :is_trash,
143
+ }
144
+ CSS_ID_MAP = ['subnavigation']
145
+ end
146
+ class InvoicesComposite < HtmlGrid::DivComposite
147
+ COMPONENTS = {
148
+ [0,0] => InvoiceList,
149
+ }
150
+ end
151
+ class Invoices < Template
152
+ CONTENT = InvoicesComposite
153
+ def subnavigation(model)
154
+ InvoicesSubnavigation.new(model, @session, self)
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end