ydim-html 1.0.1

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