express_templates 0.3.6 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/lib/core_extensions/proc.rb +1 -5
  3. data/lib/express_templates/compiler.rb +10 -9
  4. data/lib/express_templates/components.rb +1 -1
  5. data/lib/express_templates/components/capabilities/adoptable.rb +20 -0
  6. data/lib/express_templates/components/capabilities/building.rb +6 -0
  7. data/lib/express_templates/components/capabilities/parenting.rb +7 -2
  8. data/lib/express_templates/components/capabilities/templating.rb +1 -1
  9. data/lib/express_templates/components/for_each.rb +2 -0
  10. data/lib/express_templates/components/form_rails_support.rb +4 -1
  11. data/lib/express_templates/components/forms.rb +15 -0
  12. data/lib/express_templates/components/forms/basic_fields.rb +53 -0
  13. data/lib/express_templates/components/forms/checkbox.rb +37 -0
  14. data/lib/express_templates/components/forms/express_form.rb +66 -0
  15. data/lib/express_templates/components/forms/form_component.rb +60 -0
  16. data/lib/express_templates/components/forms/option_support.rb +43 -0
  17. data/lib/express_templates/components/forms/radio.rb +84 -0
  18. data/lib/express_templates/components/forms/select.rb +61 -0
  19. data/lib/express_templates/components/forms/submit.rb +26 -0
  20. data/lib/express_templates/components/null_wrap.rb +33 -1
  21. data/lib/express_templates/expander.rb +1 -0
  22. data/lib/express_templates/version.rb +1 -1
  23. data/test/components/container_test.rb +2 -0
  24. data/test/components/forms/basic_fields_test.rb +52 -0
  25. data/test/components/forms/checkbox_test.rb +44 -0
  26. data/test/components/forms/express_form_test.rb +120 -0
  27. data/test/components/forms/radio_test.rb +91 -0
  28. data/test/components/forms/select_test.rb +75 -0
  29. data/test/components/forms/submit_test.rb +12 -0
  30. data/test/components/iterating_test.rb +18 -0
  31. data/test/components/null_wrap_test.rb +28 -0
  32. data/test/components/table_for_test.rb +6 -6
  33. data/test/dummy/log/test.log +13758 -0
  34. data/test/markup/tag_test.rb +1 -1
  35. metadata +26 -5
  36. data/lib/express_templates/components/form_for.rb +0 -469
  37. data/test/components/form_for_test.rb +0 -246
@@ -134,7 +134,7 @@ class TagTest < ActiveSupport::TestCase
134
134
  test "markup is indented" do
135
135
  ExpressTemplates::Markup::Tag.formatted do
136
136
  code = ExpressTemplates.compile &-> {ul { li { "*"*36 }}}
137
- assert_equal "<ul>\n <li>#{"*"*36}</li>\n</ul>\n", eval(code)
137
+ assert_equal "\n<ul>\n <li>#{"*"*36}</li>\n</ul>\n", eval(code)
138
138
  end
139
139
  end
140
140
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: express_templates
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.6
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steven Talcott Smith
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-04-07 00:00:00.000000000 Z
12
+ date: 2015-05-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -155,6 +155,7 @@ files:
155
155
  - lib/express_templates/compiler.rb
156
156
  - lib/express_templates/components.rb
157
157
  - lib/express_templates/components/base.rb
158
+ - lib/express_templates/components/capabilities/adoptable.rb
158
159
  - lib/express_templates/components/capabilities/building.rb
159
160
  - lib/express_templates/components/capabilities/conditionality.rb
160
161
  - lib/express_templates/components/capabilities/configurable.rb
@@ -167,8 +168,16 @@ files:
167
168
  - lib/express_templates/components/container.rb
168
169
  - lib/express_templates/components/content_for.rb
169
170
  - lib/express_templates/components/for_each.rb
170
- - lib/express_templates/components/form_for.rb
171
171
  - lib/express_templates/components/form_rails_support.rb
172
+ - lib/express_templates/components/forms.rb
173
+ - lib/express_templates/components/forms/basic_fields.rb
174
+ - lib/express_templates/components/forms/checkbox.rb
175
+ - lib/express_templates/components/forms/express_form.rb
176
+ - lib/express_templates/components/forms/form_component.rb
177
+ - lib/express_templates/components/forms/option_support.rb
178
+ - lib/express_templates/components/forms/radio.rb
179
+ - lib/express_templates/components/forms/select.rb
180
+ - lib/express_templates/components/forms/submit.rb
172
181
  - lib/express_templates/components/null_wrap.rb
173
182
  - lib/express_templates/components/row.rb
174
183
  - lib/express_templates/components/table_for.rb
@@ -194,8 +203,14 @@ files:
194
203
  - test/components/configurable_test.rb
195
204
  - test/components/container_test.rb
196
205
  - test/components/content_for_test.rb
197
- - test/components/form_for_test.rb
206
+ - test/components/forms/basic_fields_test.rb
207
+ - test/components/forms/checkbox_test.rb
208
+ - test/components/forms/express_form_test.rb
209
+ - test/components/forms/radio_test.rb
210
+ - test/components/forms/select_test.rb
211
+ - test/components/forms/submit_test.rb
198
212
  - test/components/iterating_test.rb
213
+ - test/components/null_wrap_test.rb
199
214
  - test/components/row_test.rb
200
215
  - test/components/table_for_test.rb
201
216
  - test/components/tree_for_test.rb
@@ -292,8 +307,14 @@ test_files:
292
307
  - test/components/configurable_test.rb
293
308
  - test/components/container_test.rb
294
309
  - test/components/content_for_test.rb
295
- - test/components/form_for_test.rb
310
+ - test/components/forms/basic_fields_test.rb
311
+ - test/components/forms/checkbox_test.rb
312
+ - test/components/forms/express_form_test.rb
313
+ - test/components/forms/radio_test.rb
314
+ - test/components/forms/select_test.rb
315
+ - test/components/forms/submit_test.rb
296
316
  - test/components/iterating_test.rb
317
+ - test/components/null_wrap_test.rb
297
318
  - test/components/row_test.rb
298
319
  - test/components/table_for_test.rb
299
320
  - test/components/tree_for_test.rb
@@ -1,469 +0,0 @@
1
- module ExpressTemplates
2
- module Components
3
- #
4
- # Create an html <tt>form</tt> for a model object.
5
- #
6
- # Example:
7
- #
8
- # ````
9
- # form_for(:people) do |f|
10
- # f.text_field :name
11
- # f.email_field :email
12
- # f.phone_field :phone, wrapper_class: 'field phone'
13
- # f.submit 'Save'
14
- # end
15
- # ````
16
- #
17
- # This assumes that @people variable will exist in the
18
- # view and that it will be a collection whose members respond to :name, :email etc.
19
- #
20
- # This will result in markup like the following:
21
- #
22
- # ````
23
- # <form action="/people" method="post">
24
- # <div style="display:none">
25
- # <input name="utf8" type="hidden" value="✓">
26
- # <input type="hidden" name="_method" value="post">
27
- # <input type="hidden" name="authenticity_token" value="5ZDztTe1N4tc03QSjmMdSVqAw==">
28
- # </div>
29
- #
30
- # <div>
31
- # <label for="person_name">Name</label>
32
- # <input type="text" name="person[name]" id="person_name" />
33
- # </div>
34
- #
35
- # <div>
36
- # <label for="person_email">Email</label>
37
- # <input type="email" name="person[email]" id="person_email" />
38
- # </div>
39
- #
40
- # <div class="field phone">
41
- # <label for="person_phone">Phone</label>
42
- # <input type="tel" name="person[phone]" id="person_phone" />
43
- # </div>
44
- #
45
- # <div>
46
- # <input type="submit" name="commit" value="Save" />
47
- # </div>
48
- # </form>
49
- # ````
50
- #
51
- # As seen above, each field is accompanied by a label and is wrapped by a div.
52
- # The div can be further styled by adding css classes to it via the `wrapper_class` option.
53
- #
54
- # Example:
55
- #
56
- # ````
57
- # form_for(:posts) do
58
- # f.text_field :title, wrapped_class: 'string optional'
59
- # end
60
- #
61
- # Will result to generating HTML like so:
62
- #
63
- # ````
64
- # ...
65
- # <div class='string optional'>
66
- # <label for='post_title'>Title</label>
67
- # <input type="text" name="post[title]" id="post_title" />
68
- # </div>
69
- # ...
70
- # ````
71
- #
72
- # In addition to this, label text can also be customized using the `label` option:
73
- #
74
- # ````
75
- # f.email_field :email_address, label: 'Your Email'
76
- # ````
77
- #
78
- # Compiles to;
79
- # ````
80
- # <label for='user_email'>Your Email</label>
81
- # <input type='email' name='user[email]' id='user_email' />
82
- # ````
83
- class FormFor < Base
84
- include Capabilities::Configurable
85
- include Capabilities::Building
86
-
87
- def initialize(*args)
88
- # TODO: need a better way to select the form options
89
- if @form_options = args.find { |x| x.is_a?(Hash) }
90
- @_method = @form_options.delete :method
91
- end
92
-
93
- super(*args)
94
- _process_args!(args) # from Configurable
95
- yield(self) if block_given?
96
- end
97
-
98
- attr :fields
99
-
100
- # Express Templates uses Rails' form helpers to generate the fields with labels
101
- #
102
- # Example:
103
- #
104
- # ````
105
- # form_for(:people) do |f|
106
- # f.phone_field :phone
107
- # end
108
- # ````
109
- #
110
- # This will precompile as
111
- #
112
- # ````
113
- # ...
114
- # phone_field_tag :phone, @people.phone, {}
115
- # ...
116
- # ````
117
- #
118
- # You can also add html options to the form (add classes, id, etc)
119
- #
120
- # ````
121
- # form_for(:people, html_options: {class: 'edit_form', id: 'people_form'}) do |f|
122
- # f.phone_field :phone
123
- # end
124
- # ````
125
- #
126
- # # <form action='/people' method='post' id='people_form' class='edit_form'>
127
- #
128
- # Fields can also have custom classes via the `class` option:
129
- #
130
- # Example:
131
- #
132
- # ````
133
- # f.url_field :website_url, class: 'url-string'
134
- # ````
135
- #
136
- # Compiles to:
137
- #
138
- # ````
139
- # <input type='url' name='post[website_url]' id='post_website_url' class='url-string' />
140
- # ````
141
- #
142
- # You can also add in the basic options supported by the
143
- # phone_field_tag [here](http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-phone_field_tag)
144
- #
145
- # This applies to all the other '_field_tags' listed
146
- # [here](http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html)
147
- #
148
- #
149
- # = Fields
150
- # ````
151
- # f.text_field :name
152
- # # <div>
153
- # # <label for="person_name">Name</label>
154
- # # <input type="text" name="person[name]" id="person_name" />
155
- # # </div>
156
- #
157
- # f.text_field :name, label: 'post title'
158
- # # <div>
159
- # # <label for="person_name">Post Title</label>
160
- # # <input type="text" name="person[name]" id="person_name" />
161
- # # </div>
162
- #
163
- # f.text_field :name, class: 'string'
164
- # # <div>
165
- # # <label for="person_name">Name</label>
166
- # # <input type="text" name="person[name]" class='string' id="person_name" />
167
- # # </div>
168
- #
169
- # f.text_field :name, wrapper_class: 'field input'
170
- # # <div class="field input">
171
- # # <label for="person_name">Name</label>
172
- # # <input type="text" name="person[name]" id="person_name" />
173
- # # </div>
174
- #
175
- # ````
176
- %w(email phone text password color date datetime
177
- datetime_local hidden number range
178
- search telephone time url week).each do |type|
179
- define_method("#{type}_field") do |name, options={}|
180
- @fields ||= []
181
- @fields << Field.new(name, options, type.to_sym)
182
- end
183
- end
184
-
185
- # ==== Examples
186
- # f.select :gender, ['Male', 'Female'], selected: 'Male'
187
- # # <div>
188
- # # <label for="person_gender">Gender</label>
189
- # # <select id="person_gender" name="person[gender]">
190
- # # <option selected="selected" value="Male">Male</option>
191
- # # <option selected="selected" value="Female">Female</option>
192
- # # </select>
193
- # # </div>
194
- # f.select :name, options_from_collection_for_select(@people, "id", "name")
195
- # # <div>
196
- # # <label for="person_name">Name</label>
197
- # # <select id="people_name" name="people[name]"><option value="1">David</option></select>
198
- # # </div>
199
- #
200
- def select(name, select_options, options = {})
201
- @fields ||= []
202
- @fields << Select.new(name, options.merge!(select_options: select_options))
203
- end
204
-
205
- # ==== Examples
206
- # f.radio :card, [[1, 'One'], [2, 'Two']], :first, :last
207
- # # <div>
208
- # # <label class="radio" for="user_age_1"><input type="radio" value="1" name="user[age]" id="user_age_1">One</label>
209
- # # <label class="radio" for="user_age_2"><input type="radio" value="2" name="user[age]" id="user_age_2">Two</label>
210
- # # </div>
211
- #
212
- # f.radio :enable_something, :boolean
213
- # # <div>
214
- # # <label class="radio"><input type="radio" value="1" name="user[age]" id="user_age_1">One</label>
215
- # # <label class="radio"><input type="radio" value="2" name="user[age]" id="user_age_2">Two</label>
216
- # # </div>
217
- def radio(name, collection, value_method = :first, text_method = :last, options = {})
218
- @fields ||= []
219
- if collection == :boolean
220
- collection = [[true, 'True'], [false, 'False']]
221
- end
222
- @fields << Radio.new(name, options.merge!(collection: collection, value_method: value_method, text_method: text_method))
223
- end
224
-
225
- # ==== Examples
226
- # f.checkbox :age, [[1, 'One'], [2, 'Two']], :first, :last
227
- # # <div>
228
- # # <label class="checkbox">
229
- # # <input type="checkbox" value="1" name="user[age][]" id="user_age_1">
230
- # # "One"
231
- # # </label>
232
- # # <label class="checkbox">
233
- # # <input type="checkbox" value="2" name="user[age][]" id="user_age_2">
234
- # # "Two"
235
- # # </label>
236
- # # </div>
237
- #
238
- def checkbox(name, collection, value_method, text_method, options = {})
239
- @fields ||= []
240
- @fields << Checkbox.new(name, options.merge!(collection: collection, value_method: value_method, text_method: text_method))
241
- end
242
-
243
- # ==== Examples
244
- # f.text_area :name
245
- # # <div>
246
- # # <label for="user_name">Name</label>
247
- # # <textarea name="user[name]" id="user_name" >
248
- # # </div>
249
- # f.text_area :name, label: 'post title'
250
- # # <div>
251
- # # <label for="user_name">Post Title</label>
252
- # # <textarea name="user[name]" id="user_name" >
253
- # # </div>
254
- # f.text_area :name, wrapper_class: 'field input'
255
- # # <div class="field input">
256
- # # <label for="user_name">Name</label>
257
- # # <textarea name="user[name]" id="user_name" >
258
- # # </div>
259
- # f.text_area :name, class: 'string'
260
- # # <div>
261
- # # <label for="user_name>Name</label>
262
- # # <textarea name="user[name] id="user_name" class="string" >
263
- # # </div>
264
- #
265
- def text_area(name, options = {})
266
- @fields ||= []
267
- @fields << TextArea.new(name, options)
268
- end
269
-
270
- # ==== Examples
271
- # f.submit "Save Changes"
272
- # # <div>
273
- # # <input type="submit" name="commit" value="Save Changes" />
274
- # # </div>
275
- #
276
- def submit(name = 'Submit Changes', options = {})
277
- @fields ||=[]
278
- @fields << Field.new(name, options, :submit)
279
- end
280
-
281
- # You can add extra actions to a form instead of just submit
282
- # ==== Examples
283
- # f.actions({submit: ['Save', {class: 'submit primary'}], cancel: ['Cancel it', class: 'cancel secondary']})
284
- # # <div>
285
- # # <input type="submit" name="submit primary" value: "Save" />
286
- # # <a href="#" onclick="return false;" class="cancel secondary">Cancel it</a>
287
- # # </div>
288
- #
289
- # You can also add extra wrapper div classes for more customization
290
- # ==== Examples
291
- # f.actions({submit: ['Save', {class: 'submit primary'}], cancel: ['Cancel it', class: 'cancel secondary']}, wrapper_class: 'form-group')
292
- # # <div class='form-group'>
293
- # # <input type="submit" name="submit primary" value: "Save" />
294
- # # <a href="#" onclick="return false;" class="cancel secondary">Cancel it</a>
295
- # # </div>
296
- def actions(extra_actions, options)
297
- @fields ||= []
298
- @fields << Actions.new(extra_actions, options)
299
- end
300
-
301
- emits -> {
302
- form(form_args) {
303
- form_rails_support form_method
304
- fields.each do |field|
305
- field_name = field.name
306
- field_type = field.type.to_s
307
- resource_field_name = "#{resource_name.singularize}[#{field_name}]"
308
- label_name = "#{resource_name.singularize}_#{field_name}"
309
- field_label = field.label || field_name.to_s.titleize
310
-
311
- div(class: field.wrapper_class) {
312
- if field_type == 'select'
313
- label_tag(label_name, field_label)
314
- select_tag(resource_field_name, field.options_html, field.options)
315
- elsif field_type == 'radio'
316
- label_tag(label_name, field_label)
317
- collection_radio_buttons(my[:id], field_name, field.collection,
318
- field.value_method, field.text_method, field.options) do |b|
319
- b.label(class: 'radio') { b.radio_button + b.text }
320
- end
321
- elsif field_type == 'checkbox'
322
- label_tag(label_name, field_label)
323
- collection_check_boxes(my[:id], field_name, field.collection,
324
- field.value_method, field.text_method, field.options) do |b|
325
- b.label(class: 'checkbox') { b.check_box + b.text }
326
- end
327
- elsif field_type == 'submit'
328
- submit_tag(field_name, field.options)
329
- elsif field_type == 'actions'
330
- field.extra_actions.each do |action|
331
- action_type = action.first
332
- action_options = action.last
333
-
334
- if action_type == :submit
335
- submit_tag(action_options.first, action_options.last)
336
- elsif action_type == :cancel
337
- default_opts = {href: '#', onclick: 'return false;'}.merge!(action_options.last)
338
- a(default_opts) { action_options.first }
339
- end
340
- end
341
- else
342
- label_tag(label_name, field_label) unless field_type == 'hidden'
343
- args = [resource_field_name, "{{@#{resource_name.singularize}.#{field_name}}}", field.options]
344
- tag_string = if field_type == 'text_area'
345
- 'text_area_tag'
346
- else
347
- "#{field_type}_field_tag"
348
- end
349
-
350
- self.send(tag_string.to_sym, *args)
351
- end
352
- }
353
- end
354
- }
355
- }
356
-
357
- def wrap_for_stack_trace(body)
358
- "ExpressTemplates::Components::FormFor.render_in(self) {\n#{body}\n}"
359
- end
360
-
361
- def compile
362
- wrap_for_stack_trace(lookup(:markup))
363
- end
364
-
365
- private
366
-
367
- def form_method
368
- if @_method == :put
369
- :patch
370
- else
371
- @form_options.present? ? @form_options[:method] : :post
372
- end
373
- end
374
-
375
- def _action(resource_name)
376
- base_url = %Q(/#{resource_name.pluralize})
377
- if form_method == :patch
378
- %Q(#{base_url}/{{@#{resource_name}.id}})
379
- else
380
- base_url
381
- end
382
- end
383
-
384
- def form_args
385
- default_args = {action: _action(resource_name), method: :post}
386
-
387
- if @form_options.nil?
388
- default_args
389
- else
390
- if html_options = @form_options.delete(:html_options)
391
- @form_options.merge!(html_options)
392
- end
393
- default_args.merge!(@form_options)
394
- end
395
- end
396
-
397
- def resource_name
398
- my[:id].to_s
399
- end
400
-
401
- class Field
402
- attr :name, :options, :label, :type, :wrapper_class
403
- def initialize(name, options = {}, type=:text)
404
- @name = name
405
- @options = options
406
- @label = @options.delete(:label)
407
- @wrapper_class = @options.delete(:wrapper_class)
408
- @type = type
409
- end
410
- end
411
-
412
- class TextArea < Field
413
- def initialize(name, options={})
414
- super(name, options, :text_area)
415
- end
416
- end
417
-
418
- class Radio < Field
419
- attr :collection, :value_method, :text_method
420
- def initialize(name, options = {})
421
- @collection = options.delete :collection
422
- @value_method = options.delete :value_method
423
- @text_method = options.delete :text_method
424
- super(name, options, :radio)
425
- end
426
- end
427
-
428
- class Checkbox < Radio
429
- def initialize(name, options = {})
430
- super(name, options)
431
- @type = :checkbox
432
- end
433
- end
434
-
435
- class Select < Field
436
- attr :choices
437
- def initialize(name, options = {})
438
- @choices = options.delete :select_options
439
- @selected = options.delete :selected
440
- super(name, options, :select)
441
- end
442
-
443
- def options_html
444
- choice_string = ""
445
- if @choices.is_a?(String)
446
- choice_string = @choices
447
- else
448
- @choices.map do |choice|
449
- selected_string = (@selected != nil && choice == @selected) ? 'selected=selected' : nil
450
- choice_string << "<option #{selected_string}>#{choice}</option>"
451
- end
452
- "{{'#{choice_string}'.html_safe}}"
453
- end
454
- end
455
- end
456
-
457
- # need to fix this some day (actions doesn't need to inherit from field)
458
- class Actions < Field
459
- attr :extra_actions
460
- def initialize(extra_actions, options = {})
461
- @name = ''
462
- @label = ''
463
- @extra_actions = extra_actions
464
- super(@name, options, :actions)
465
- end
466
- end
467
- end
468
- end
469
- end