express_templates 0.3.6 → 0.4.0

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