pakyow-presenter 0.10.2 → 0.11.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.
- checksums.yaml +4 -4
- data/pakyow-presenter/CHANGELOG.md +16 -0
- data/pakyow-presenter/lib/pakyow-presenter.rb +1 -11
- data/pakyow-presenter/lib/pakyow/presenter.rb +8 -0
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/attributes.rb +21 -14
- data/pakyow-presenter/lib/pakyow/presenter/base.rb +38 -0
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/binder.rb +19 -6
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/binder_set.rb +18 -21
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/binding_eval.rb +14 -0
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/config/presenter.rb +12 -6
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/container.rb +0 -0
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/doc_helpers.rb +0 -0
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/exceptions.rb +0 -0
- data/pakyow-presenter/lib/pakyow/presenter/ext/app.rb +33 -0
- data/pakyow-presenter/lib/pakyow/presenter/ext/call_context.rb +28 -0
- data/pakyow-presenter/lib/pakyow/presenter/helpers.rb +46 -0
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/page.rb +0 -0
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/partial.rb +0 -0
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/presenter.rb +14 -9
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/string_doc.rb +35 -9
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/string_doc_parser.rb +41 -30
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/string_doc_renderer.rb +0 -0
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/template.rb +0 -0
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/view.rb +79 -36
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/view_collection.rb +10 -4
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/view_composer.rb +43 -3
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/view_context.rb +12 -8
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/view_store.rb +3 -1
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/view_store_loader.rb +0 -0
- data/pakyow-presenter/lib/{presenter → pakyow/presenter}/view_version.rb +19 -3
- data/pakyow-presenter/lib/pakyow/views/errors/404.erb +26 -0
- data/pakyow-presenter/lib/pakyow/views/errors/500.erb +23 -0
- metadata +39 -38
- data/pakyow-presenter/lib/presenter/base.rb +0 -27
- data/pakyow-presenter/lib/presenter/ext/app.rb +0 -63
- data/pakyow-presenter/lib/presenter/helpers.rb +0 -40
- data/pakyow-presenter/lib/views/errors/404.html +0 -5
- data/pakyow-presenter/lib/views/errors/500.html +0 -0
File without changes
|
File without changes
|
@@ -18,7 +18,11 @@ module Pakyow
|
|
18
18
|
return contents
|
19
19
|
end
|
20
20
|
|
21
|
-
|
21
|
+
processed = processor.call(contents)
|
22
|
+
|
23
|
+
# reprocess html content unless we just did that
|
24
|
+
return processed if format == :html
|
25
|
+
process(processed, :html)
|
22
26
|
end
|
23
27
|
end
|
24
28
|
|
@@ -33,11 +37,15 @@ module Pakyow
|
|
33
37
|
}
|
34
38
|
|
35
39
|
Pakyow::App.after(:route) {
|
36
|
-
if
|
37
|
-
@found
|
38
|
-
@context.response.body = [@presenter.content]
|
40
|
+
if Config.presenter.require_route && !found?
|
41
|
+
@found
|
39
42
|
else
|
40
|
-
@
|
43
|
+
if @presenter.presented?
|
44
|
+
@found = true
|
45
|
+
@context.response.body = [@presenter.content]
|
46
|
+
else
|
47
|
+
@found = false unless found?
|
48
|
+
end
|
41
49
|
end
|
42
50
|
}
|
43
51
|
|
@@ -163,10 +171,7 @@ module Pakyow
|
|
163
171
|
end
|
164
172
|
|
165
173
|
def compose_at(path, opts = {}, &block)
|
166
|
-
composer = ViewComposer.from_path(store, path, opts, &block)
|
167
|
-
return composer unless opts.empty? || block_given?
|
168
|
-
|
169
|
-
@composer = composer
|
174
|
+
@composer = ViewComposer.from_path(store, path, opts, &block)
|
170
175
|
end
|
171
176
|
|
172
177
|
def has_path?
|
@@ -51,6 +51,10 @@ module Pakyow
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
def attribute?(name)
|
55
|
+
attributes.key?(name.to_sym)
|
56
|
+
end
|
57
|
+
|
54
58
|
def set_attribute(name, value)
|
55
59
|
return if attributes.nil?
|
56
60
|
attributes[name.to_sym] = value
|
@@ -65,9 +69,24 @@ module Pakyow
|
|
65
69
|
attributes.delete(name.to_sym)
|
66
70
|
end
|
67
71
|
|
72
|
+
def has_attribute?(name)
|
73
|
+
attributes.key?(name)
|
74
|
+
end
|
75
|
+
|
68
76
|
def remove
|
69
77
|
@structure.delete_if { |n| n.equal?(node) }
|
70
|
-
|
78
|
+
|
79
|
+
if @node.nil?
|
80
|
+
@node = ['', {}, [['', {}, []]]]
|
81
|
+
else
|
82
|
+
@node[0] = ''
|
83
|
+
@node[1] = {}
|
84
|
+
@node[2][0][0] = ''
|
85
|
+
@node[2][0][1] = {}
|
86
|
+
@node[2][0][2] = []
|
87
|
+
@node[2].slice!(1..-1)
|
88
|
+
end
|
89
|
+
|
71
90
|
@removed = true
|
72
91
|
end
|
73
92
|
|
@@ -184,6 +203,7 @@ module Pakyow
|
|
184
203
|
end
|
185
204
|
|
186
205
|
def to_html
|
206
|
+
StringDocRenderer.render((@node && !@removed) ? [@node] : @structure)
|
187
207
|
StringDocRenderer.render(@node ? [@node] : @structure)
|
188
208
|
end
|
189
209
|
alias :to_s :to_html
|
@@ -195,7 +215,7 @@ module Pakyow
|
|
195
215
|
end
|
196
216
|
|
197
217
|
def node
|
198
|
-
return @structure if @structure.empty?
|
218
|
+
return @structure if @structure.empty? && !@removed
|
199
219
|
return @node || @structure[0]
|
200
220
|
end
|
201
221
|
|
@@ -241,12 +261,8 @@ module Pakyow
|
|
241
261
|
node[1]
|
242
262
|
end
|
243
263
|
|
244
|
-
def has_attribute?(name)
|
245
|
-
attributes.key?(name)
|
246
|
-
end
|
247
|
-
|
248
264
|
def children
|
249
|
-
if @structure.empty?
|
265
|
+
if @structure.empty? && !@removed
|
250
266
|
@structure
|
251
267
|
else
|
252
268
|
node[2][0][2]
|
@@ -267,7 +283,7 @@ module Pakyow
|
|
267
283
|
def find_partials(structure, primary_structure = @structure, partials = {})
|
268
284
|
structure.inject(partials) { |s, e|
|
269
285
|
if e[1].has_key?(:partial)
|
270
|
-
s[e[1][:partial]]
|
286
|
+
(s[e[1][:partial]] ||= []) << StringDoc.from_structure(primary_structure, node: e)
|
271
287
|
end
|
272
288
|
find_partials(e[2], e[2], s)
|
273
289
|
s
|
@@ -308,10 +324,20 @@ module Pakyow
|
|
308
324
|
|
309
325
|
def find_node_props(node, primary_structure = @structure, props = [])
|
310
326
|
if node[1].has_key?(:'data-prop')
|
311
|
-
|
327
|
+
prop = {
|
312
328
|
doc: StringDoc.from_structure(primary_structure, node: node),
|
313
329
|
prop: node[1][:'data-prop'].to_sym,
|
330
|
+
parts: {},
|
314
331
|
}
|
332
|
+
|
333
|
+
if node[1].has_key?(:'data-parts')
|
334
|
+
prop[:parts][:include] = node[1][:'data-parts'].split(/\s+/).map(&:to_sym)
|
335
|
+
end
|
336
|
+
|
337
|
+
if node[1].has_key?(:'data-parts-exclude')
|
338
|
+
prop[:parts][:exclude] = node[1][:'data-parts-exclude'].split(/\s+/).map(&:to_sym)
|
339
|
+
end
|
340
|
+
props << prop
|
315
341
|
end
|
316
342
|
|
317
343
|
unless node[1].has_key?(:'data-scope')
|
@@ -3,6 +3,7 @@ module Pakyow
|
|
3
3
|
class StringDocParser
|
4
4
|
PARTIAL_REGEX = /<!--\s*@include\s*([a-zA-Z0-9\-_]*)\s*-->/
|
5
5
|
CONTAINER_REGEX = /@container( ([a-zA-Z0-9\-_]*))*/
|
6
|
+
SIGNIFICANT = [:scope?, :prop?, :container?, :partial?, :option?, :component?]
|
6
7
|
|
7
8
|
def initialize(html)
|
8
9
|
@html = html
|
@@ -20,45 +21,51 @@ module Pakyow
|
|
20
21
|
def parse(doc)
|
21
22
|
structure = []
|
22
23
|
|
23
|
-
|
24
|
+
unless doc.is_a?(Oga::XML::Element) || !doc.respond_to?(:doctype) || doc.doctype.nil?
|
24
25
|
structure << ['<!DOCTYPE html>', {}, []]
|
25
26
|
end
|
26
27
|
|
27
28
|
breadth_first(doc) do |node, queue|
|
28
29
|
if node == doc
|
29
|
-
queue.concat(node.children)
|
30
|
+
queue.concat(node.children.to_a)
|
30
31
|
next
|
31
32
|
end
|
32
33
|
|
33
|
-
children = node.children.reject {|n| n.is_a?(
|
34
|
-
|
34
|
+
children = node.children.reject {|n| n.is_a?(Oga::XML::Text)}
|
35
|
+
|
36
|
+
if node.is_a?(Oga::XML::Element)
|
37
|
+
attributes = node.attributes
|
38
|
+
else
|
39
|
+
attributes = []
|
40
|
+
end
|
41
|
+
|
35
42
|
if !structure.empty? && children.empty? && !significant?(node)
|
36
|
-
structure << [node.
|
43
|
+
structure << [node.to_xml, {}, []]
|
37
44
|
else
|
38
45
|
if significant?(node)
|
39
|
-
if
|
46
|
+
if container?(node)
|
47
|
+
match = node.text.strip.match(CONTAINER_REGEX)
|
48
|
+
name = (match[2] || :default).to_sym
|
49
|
+
structure << [node.to_xml, { container: name }, []]
|
50
|
+
elsif partial?(node)
|
51
|
+
next unless match = node.to_xml.strip.match(PARTIAL_REGEX)
|
52
|
+
name = match[1].to_sym
|
53
|
+
structure << [node.to_xml, { partial: name }, []]
|
54
|
+
else
|
40
55
|
attr_structure = attributes.inject({}) do |attrs, attr|
|
41
|
-
attrs[attr
|
56
|
+
attrs[attr.name.to_sym] = attr.value
|
42
57
|
attrs
|
43
58
|
end
|
44
59
|
|
45
60
|
closing = [['>', {}, parse(node)]]
|
46
61
|
closing << ["</#{node.name}>", {}, []] unless self_closing?(node.name)
|
47
62
|
structure << ["<#{node.name} ", attr_structure, closing]
|
48
|
-
elsif container?(node)
|
49
|
-
match = node.text.strip.match(CONTAINER_REGEX)
|
50
|
-
name = (match[2] || :default).to_sym
|
51
|
-
structure << [node.to_html, { container: name }, []]
|
52
|
-
elsif partial?(node)
|
53
|
-
next unless match = node.to_html.strip.match(PARTIAL_REGEX)
|
54
|
-
name = match[1].to_sym
|
55
|
-
structure << [node.to_html, { partial: name }, []]
|
56
63
|
end
|
57
64
|
else
|
58
|
-
if node.is_a?(
|
59
|
-
structure << [node.
|
65
|
+
if node.is_a?(Oga::XML::Text) || node.is_a?(Oga::XML::Comment)
|
66
|
+
structure << [node.to_xml, {}, []]
|
60
67
|
else
|
61
|
-
attr_s = attributes.inject('') { |s, a| s << " #{a
|
68
|
+
attr_s = attributes.inject('') { |s, a| s << " #{a.name}=\"#{a.value}\""; s }
|
62
69
|
closing = [['>', {}, parse(node)]]
|
63
70
|
closing << ['</' + node.name + '>', {}, []] unless self_closing?(node.name)
|
64
71
|
structure << ['<' + node.name + attr_s, {}, closing]
|
@@ -71,37 +78,45 @@ module Pakyow
|
|
71
78
|
end
|
72
79
|
|
73
80
|
def significant?(node)
|
74
|
-
|
81
|
+
SIGNIFICANT.each do |method|
|
82
|
+
return true if send(method, node)
|
83
|
+
end
|
84
|
+
|
85
|
+
false
|
75
86
|
end
|
76
87
|
|
77
88
|
def scope?(node)
|
78
|
-
return false unless node
|
89
|
+
return false unless node.is_a?(Oga::XML::Element)
|
90
|
+
return false unless node.attribute('data-scope')
|
79
91
|
return true
|
80
92
|
end
|
81
93
|
|
82
94
|
def prop?(node)
|
83
|
-
return false unless node
|
95
|
+
return false unless node.is_a?(Oga::XML::Element)
|
96
|
+
return false unless node.attribute('data-prop')
|
84
97
|
return true
|
85
98
|
end
|
86
99
|
|
87
100
|
def container?(node)
|
88
|
-
return false unless node.is_a?(
|
101
|
+
return false unless node.is_a?(Oga::XML::Comment)
|
89
102
|
return false unless node.text.strip.match(CONTAINER_REGEX)
|
90
103
|
return true
|
91
104
|
end
|
92
105
|
|
93
106
|
def partial?(node)
|
94
|
-
return false unless node.is_a?(
|
95
|
-
return false unless node.
|
107
|
+
return false unless node.is_a?(Oga::XML::Comment)
|
108
|
+
return false unless node.to_xml.strip.match(PARTIAL_REGEX)
|
96
109
|
return true
|
97
110
|
end
|
98
111
|
|
99
112
|
def option?(node)
|
113
|
+
return false unless node.is_a?(Oga::XML::Element)
|
100
114
|
node.name == 'option'
|
101
115
|
end
|
102
116
|
|
103
117
|
def component?(node)
|
104
|
-
return false unless node
|
118
|
+
return false unless node.is_a?(Oga::XML::Element)
|
119
|
+
return false unless node.attribute('data-ui')
|
105
120
|
return true
|
106
121
|
end
|
107
122
|
|
@@ -116,11 +131,7 @@ module Pakyow
|
|
116
131
|
end
|
117
132
|
|
118
133
|
def doc_from_string(string)
|
119
|
-
|
120
|
-
Nokogiri::HTML::Document.parse(string)
|
121
|
-
else
|
122
|
-
Nokogiri::HTML.fragment(string)
|
123
|
-
end
|
134
|
+
Oga.parse_html(string)
|
124
135
|
end
|
125
136
|
|
126
137
|
SELF_CLOSING = %w[area base basefont br hr input img link meta]
|
File without changes
|
File without changes
|
@@ -43,7 +43,6 @@ module Pakyow
|
|
43
43
|
# Creates a view from a doc.
|
44
44
|
#
|
45
45
|
# @see StringDoc
|
46
|
-
# @see NokogiriDoc
|
47
46
|
#
|
48
47
|
def self.from_doc(doc)
|
49
48
|
view = new
|
@@ -289,21 +288,31 @@ module Pakyow
|
|
289
288
|
end
|
290
289
|
|
291
290
|
def includes(partial_map)
|
292
|
-
|
291
|
+
doc_partials = @doc.partials
|
293
292
|
partial_map = partial_map.dup
|
294
293
|
|
295
294
|
# mixin all the partials
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
295
|
+
doc_partials.each do |partial_name, partial_docs|
|
296
|
+
partials = Array.ensure(partial_map[partial_name])
|
297
|
+
|
298
|
+
partial_docs.each_with_index do |partial_doc, i|
|
299
|
+
replacement = partials[i]
|
300
|
+
next if replacement.nil?
|
301
|
+
|
302
|
+
if replacement.is_a?(ViewCollection)
|
303
|
+
partial_doc.replace(replacement.views.first.doc.dup)
|
304
|
+
partials = replacement.views
|
305
|
+
else
|
306
|
+
partial_doc.replace(replacement.doc)
|
307
|
+
end
|
308
|
+
end
|
300
309
|
end
|
301
310
|
|
302
311
|
# refind the partials
|
303
|
-
|
312
|
+
doc_partials = @doc.partials
|
304
313
|
|
305
314
|
# if mixed in partials included partials, we want to run includes again with a new map
|
306
|
-
if
|
315
|
+
if doc_partials.count > 0 && (partial_map.keys - doc_partials.keys).count < partial_map.keys.count
|
307
316
|
includes(partial_map)
|
308
317
|
end
|
309
318
|
|
@@ -324,8 +333,29 @@ module Pakyow
|
|
324
333
|
attrs.send(:'data-ui').value
|
325
334
|
end
|
326
335
|
|
336
|
+
# Convenience method for parity with Presenter::ViewCollection.
|
337
|
+
#
|
338
|
+
def length
|
339
|
+
1
|
340
|
+
end
|
341
|
+
|
342
|
+
# Convenience method for parity with Presenter::ViewCollection.
|
343
|
+
#
|
344
|
+
def first
|
345
|
+
self
|
346
|
+
end
|
347
|
+
|
327
348
|
private
|
328
349
|
|
350
|
+
def adjust_value_parts(value, parts)
|
351
|
+
return value unless value.is_a?(Hash)
|
352
|
+
|
353
|
+
parts_to_keep = parts.fetch(:include, value.keys)
|
354
|
+
parts_to_keep -= parts.fetch(:exclude, [])
|
355
|
+
|
356
|
+
value.keep_if { |part, _| parts_to_keep.include?(part) }
|
357
|
+
end
|
358
|
+
|
329
359
|
def bind_data_to_scope(data, scope_info, bindings, ctx)
|
330
360
|
return unless data
|
331
361
|
return unless scope_info
|
@@ -335,8 +365,9 @@ module Pakyow
|
|
335
365
|
|
336
366
|
scope_info[:props].each do |prop_info|
|
337
367
|
catch(:unbound) do
|
338
|
-
prop
|
339
|
-
doc
|
368
|
+
prop = prop_info[:prop]
|
369
|
+
doc = prop_info[:doc]
|
370
|
+
parts = prop_info[:parts]
|
340
371
|
|
341
372
|
if DocHelpers.form_field?(doc.tagname)
|
342
373
|
set_form_field_name(doc, scope, prop)
|
@@ -344,6 +375,7 @@ module Pakyow
|
|
344
375
|
|
345
376
|
if data_has_prop?(data, prop) || Binder.instance.has_scoped_prop?(scope, prop, bindings)
|
346
377
|
value = Binder.instance.value_for_scoped_prop(scope, prop, data, bindings, ctx)
|
378
|
+
value = adjust_value_parts(value, parts)
|
347
379
|
|
348
380
|
if DocHelpers.form_field?(doc.tagname)
|
349
381
|
bind_to_form_field(doc, scope, prop, value, data, ctx)
|
@@ -423,30 +455,38 @@ module Pakyow
|
|
423
455
|
options = Binder.instance.options_for_scoped_prop(scope, prop, bindable, ctx)
|
424
456
|
return if options.nil?
|
425
457
|
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
458
|
+
nodes = Oga::XML::Document.new
|
459
|
+
|
460
|
+
until options.length == 0
|
461
|
+
catch :optgroup do
|
462
|
+
o = options.first
|
463
|
+
|
464
|
+
# an array containing value/content
|
465
|
+
if o.is_a?(Array)
|
466
|
+
node = Oga::XML::Element.new(name: 'option')
|
467
|
+
node.inner_text = o[1].to_s
|
468
|
+
node.set('value', o[0].to_s)
|
469
|
+
nodes.children << node
|
470
|
+
options.shift
|
471
|
+
else # likely an object (e.g. string); start a group
|
472
|
+
node_group = Oga::XML::Element.new(name: 'optgroup')
|
473
|
+
node_group.set('label', o.to_s)
|
474
|
+
nodes.children << node_group
|
431
475
|
|
432
|
-
|
433
|
-
|
434
|
-
|
476
|
+
options.shift
|
477
|
+
|
478
|
+
options[0..-1].each_with_index { |o2,i2|
|
479
|
+
# starting a new group
|
480
|
+
throw :optgroup unless o2.is_a?(Array)
|
481
|
+
|
482
|
+
h.option o2[1].to_s, value: o2[0].to_s
|
483
|
+
|
484
|
+
node = Oga::XML::Element.new(name: 'option')
|
485
|
+
node.inner_text = o2[1].to_s
|
486
|
+
node.set('value', o2[0].to_s)
|
487
|
+
node_group.children << node
|
435
488
|
options.shift
|
436
|
-
|
437
|
-
else
|
438
|
-
h.optgroup(label: o) {
|
439
|
-
options.shift
|
440
|
-
|
441
|
-
options[0..-1].each_with_index { |o2,i2|
|
442
|
-
# starting a new group
|
443
|
-
throw :optgroup unless o2.is_a?(Array)
|
444
|
-
|
445
|
-
h.option o2[1], value: o2[0]
|
446
|
-
options.shift
|
447
|
-
}
|
448
|
-
}
|
449
|
-
end
|
489
|
+
}
|
450
490
|
end
|
451
491
|
end
|
452
492
|
end
|
@@ -455,7 +495,7 @@ module Pakyow
|
|
455
495
|
doc.clear
|
456
496
|
|
457
497
|
# add generated options
|
458
|
-
doc.append(
|
498
|
+
doc.append(nodes.to_xml)
|
459
499
|
end
|
460
500
|
|
461
501
|
def select_option_with_value(doc, value)
|
@@ -483,12 +523,15 @@ module Pakyow
|
|
483
523
|
attrs = Attributes.new(doc)
|
484
524
|
|
485
525
|
if v.respond_to?(:to_proc)
|
486
|
-
|
487
|
-
v.to_proc.call(
|
526
|
+
attribute = attrs.send(attr)
|
527
|
+
ret = v.to_proc.call(attribute)
|
528
|
+
value = ret.respond_to?(:value) ? ret.value : ret
|
529
|
+
|
530
|
+
attrs.send("#{attr}=", value)
|
488
531
|
elsif v.nil?
|
489
532
|
doc.remove_attribute(attr)
|
490
533
|
else
|
491
|
-
attrs.send(
|
534
|
+
attrs.send("#{attr}=", v)
|
492
535
|
end
|
493
536
|
end
|
494
537
|
end
|