pakyow-presenter 1.0.0.rc2 → 1.0.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pakyow/{presenter/actions → actions/presenter}/auto_render.rb +2 -2
  3. data/lib/pakyow/plugin/helpers/rendering.rb +15 -2
  4. data/lib/pakyow/presenter.rb +1 -1
  5. data/lib/pakyow/presenter/attributes.rb +8 -0
  6. data/lib/pakyow/presenter/attributes/attribute.rb +0 -1
  7. data/lib/pakyow/presenter/attributes/boolean.rb +0 -1
  8. data/lib/pakyow/presenter/behavior/error_rendering.rb +1 -0
  9. data/lib/pakyow/presenter/behavior/initializing.rb +1 -1
  10. data/lib/pakyow/presenter/behavior/modes.rb +1 -0
  11. data/lib/pakyow/presenter/binder.rb +2 -0
  12. data/lib/pakyow/presenter/binding_parts.rb +1 -0
  13. data/lib/pakyow/presenter/component.rb +1 -4
  14. data/lib/pakyow/presenter/composers/component.rb +1 -0
  15. data/lib/pakyow/presenter/composers/view.rb +1 -0
  16. data/lib/pakyow/presenter/errors.rb +2 -2
  17. data/lib/pakyow/presenter/framework.rb +22 -25
  18. data/lib/pakyow/presenter/presenter.rb +5 -0
  19. data/lib/pakyow/presenter/presenters/endpoint.rb +3 -3
  20. data/lib/pakyow/presenter/presenters/form.rb +5 -5
  21. data/lib/pakyow/presenter/processor.rb +42 -38
  22. data/lib/pakyow/presenter/renderer.rb +6 -1
  23. data/lib/pakyow/presenter/renderer/behavior/cleanup_prototype_nodes.rb +23 -0
  24. data/lib/pakyow/presenter/renderer/behavior/cleanup_unbound_bindings.rb +37 -0
  25. data/lib/pakyow/presenter/renderer/behavior/create_template_nodes.rb +29 -0
  26. data/lib/pakyow/presenter/renderer/behavior/insert_prototype_bar.rb +103 -0
  27. data/lib/pakyow/presenter/renderer/behavior/install_authenticity.rb +44 -0
  28. data/lib/pakyow/presenter/renderer/behavior/place_in_mode.rb +58 -0
  29. data/lib/pakyow/presenter/renderer/behavior/render_components.rb +281 -0
  30. data/lib/pakyow/presenter/renderer/behavior/set_page_title.rb +37 -0
  31. data/lib/pakyow/presenter/renderer/behavior/setup_endpoints.rb +64 -0
  32. data/lib/pakyow/presenter/renderer/behavior/setup_forms.rb +176 -0
  33. data/lib/pakyow/presenter/significant_nodes.rb +2 -2
  34. data/lib/pakyow/presenter/templates.rb +24 -15
  35. data/lib/pakyow/presenter/versioned_view.rb +1 -0
  36. data/lib/pakyow/presenter/view.rb +11 -9
  37. data/lib/pakyow/presenter/views/form.rb +39 -35
  38. data/lib/pakyow/presenter/views/layout.rb +20 -18
  39. data/lib/pakyow/presenter/views/page.rb +47 -45
  40. data/lib/pakyow/presenter/views/partial.rb +17 -15
  41. data/lib/string_doc.rb +3 -1
  42. data/lib/string_doc/attributes.rb +1 -0
  43. data/lib/string_doc/meta_attributes.rb +1 -0
  44. data/lib/string_doc/meta_node.rb +1 -0
  45. data/lib/string_doc/node.rb +1 -0
  46. metadata +19 -20
  47. data/lib/pakyow/presenter/presentable_error.rb +0 -19
  48. data/lib/pakyow/presenter/rendering/actions/cleanup_prototype_nodes.rb +0 -21
  49. data/lib/pakyow/presenter/rendering/actions/cleanup_unbound_bindings.rb +0 -35
  50. data/lib/pakyow/presenter/rendering/actions/create_template_nodes.rb +0 -27
  51. data/lib/pakyow/presenter/rendering/actions/insert_prototype_bar.rb +0 -101
  52. data/lib/pakyow/presenter/rendering/actions/install_authenticity.rb +0 -42
  53. data/lib/pakyow/presenter/rendering/actions/place_in_mode.rb +0 -56
  54. data/lib/pakyow/presenter/rendering/actions/render_components.rb +0 -279
  55. data/lib/pakyow/presenter/rendering/actions/set_page_title.rb +0 -35
  56. data/lib/pakyow/presenter/rendering/actions/setup_endpoints.rb +0 -62
  57. data/lib/pakyow/presenter/rendering/actions/setup_forms.rb +0 -174
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/support/extension"
4
+
5
+ module Pakyow
6
+ module Presenter
7
+ class Renderer
8
+ module Behavior
9
+ module SetPageTitle
10
+ extend Support::Extension
11
+
12
+ apply_extension do
13
+ attach do |presenter|
14
+ presenter.render node: -> {
15
+ if title_value = info(:title)
16
+ title.object.set_label(:title_template, title_value); title
17
+ end
18
+ } do
19
+ self.html = html_safe(
20
+ Support::StringBuilder.new(object.label(:title_template), html_safe: true) { |object_value|
21
+ if respond_to?(object_value)
22
+ send(object_value, :title) || send(object_value)
23
+ elsif @presentables.key?(object_value)
24
+ @presentables[object_value]
25
+ else
26
+ nil
27
+ end
28
+ }.build
29
+ )
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/support/extension"
4
+
5
+ require "pakyow/presenter/presenters/endpoint"
6
+
7
+ module Pakyow
8
+ module Presenter
9
+ class Renderer
10
+ module Behavior
11
+ module SetupEndpoints
12
+ extend Support::Extension
13
+
14
+ apply_extension do
15
+ build do |view, app:|
16
+ view.object.find_significant_nodes(:endpoint, descend: true).each do |node|
17
+ if endpoint = app.endpoints.find(name: node.label(:endpoint))
18
+ node.set_label(:endpoint_object, endpoint)
19
+ node.set_label(:endpoint_params, {})
20
+ end
21
+ end
22
+ end
23
+
24
+ attach do |presenter|
25
+ if Pakyow.env?(:prototype)
26
+ presenter.render node: -> {
27
+ object.find_significant_nodes(:endpoint, descend: true).map { |node|
28
+ View.from_object(node)
29
+ }
30
+ }, priority: :low do
31
+ setup
32
+ end
33
+ else
34
+ # Setup non-binding endpoints (binding endpoints are setup dynamically in presenter).
35
+ #
36
+ presenter.render node: -> {
37
+ nodes = []
38
+ nodes << object if object.is_a?(StringDoc::Node) && object.significant?(:endpoint)
39
+ nodes.concat(object.find_significant_nodes(:endpoint))
40
+ nodes.select { |node|
41
+ node.labeled?(:endpoint_object)
42
+ }.map { |node|
43
+ View.from_object(node)
44
+ }
45
+ }, priority: :low do
46
+ case self
47
+ when Presenters::Form
48
+ Presenters::Endpoint.new(__getobj__).setup
49
+ when Presenters::Endpoint
50
+ setup
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ expose do |connection|
57
+ connection.set(:__endpoint, connection.endpoint)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/support/extension"
4
+ require "pakyow/support/message_verifier"
5
+ require "pakyow/support/safe_string"
6
+
7
+ require "pakyow/presenter/presenters/form"
8
+
9
+ module Pakyow
10
+ module Presenter
11
+ class Renderer
12
+ module Behavior
13
+ module SetupForms
14
+ extend Support::Extension
15
+
16
+ apply_extension do
17
+ build do |view, app:|
18
+ forms = view.forms
19
+ if !view.object.is_a?(StringDoc) && view.object.significant?(:form)
20
+ forms << view
21
+ end
22
+
23
+ forms.each do |form|
24
+ # Allows app renders to set metadata values on forms.
25
+ #
26
+ form.object.set_label(:form, {})
27
+
28
+ # Set the form id.
29
+ #
30
+ form_id = SecureRandom.hex(24)
31
+ form.object.label(:form)[:id] = form_id
32
+ form.object.set_label(Presenters::Form::ID_LABEL, form_id)
33
+
34
+ # Set the form binding.
35
+ #
36
+ form.object.label(:form)[:binding] = form.object.label(:channeled_binding)
37
+
38
+ # Setup field names.
39
+ #
40
+ form.object.children.each_significant_node(:binding) do |binding_node|
41
+ if Pakyow::Presenter::Views::Form::FIELD_TAGS.include?(binding_node.tagname)
42
+ if binding_node.attributes[:name].to_s.empty?
43
+ binding_node.attributes[:name] = "#{form.object.label(:binding)}[#{binding_node.label(:binding)}]"
44
+ end
45
+
46
+ if binding_node.tagname == "select" && binding_node.attributes[:multiple]
47
+ Presenters::Form.pluralize_field_name(binding_node)
48
+ end
49
+ end
50
+ end
51
+
52
+ # Connect labels.
53
+ #
54
+ form.object.children.each_significant_node(:label) do |label_node|
55
+ if label_node.attributes[:for] && input = form.find(*label_node.attributes[:for].to_s.split("."))
56
+ Presenters::Form.connect_input_to_label(input, label_node)
57
+ end
58
+ end
59
+
60
+ form.prepend(
61
+ Support::SafeStringHelpers.html_safe(
62
+ "<input type=\"hidden\" name=\"pw-http-method\">"
63
+ )
64
+ )
65
+
66
+ form.prepend(
67
+ Support::SafeStringHelpers.html_safe(
68
+ "<input type=\"hidden\" name=\"pw-form\">"
69
+ )
70
+ )
71
+
72
+ if app.config.presenter.embed_authenticity_token
73
+ form.prepend(
74
+ Support::SafeStringHelpers.html_safe(
75
+ "<input type=\"hidden\" name=\"#{app.config.security.csrf.param}\">"
76
+ )
77
+ )
78
+ end
79
+ end
80
+ end
81
+
82
+ attach do |presenter, app:|
83
+ presenter.render node: -> {
84
+ forms = self.forms
85
+ if !object.is_a?(StringDoc) && object.significant?(:form)
86
+ forms << self
87
+ end
88
+
89
+ forms
90
+ } do
91
+ unless setup?
92
+ if object = object_for_form
93
+ if app.class.includes_framework?(:data) && object.is_a?(Data::Proxy)
94
+ object = object.one
95
+ end
96
+ end
97
+
98
+ if !object.nil?
99
+ if labeled?(:endpoint)
100
+ setup(object)
101
+ else
102
+ if object.key?(:id)
103
+ update(object)
104
+ else
105
+ create(object)
106
+ end
107
+ end
108
+ elsif labeled?(:binding)
109
+ case presentables[:__endpoint_name]
110
+ when :edit
111
+ update(
112
+ __endpoint.params.each_with_object({}) { |(key, _), passed_params|
113
+ key = key.to_sym
114
+ passed_params[key] = __params[key]
115
+ }
116
+ )
117
+ else
118
+ create
119
+ end
120
+ end
121
+ end
122
+
123
+ view.object.label(:form)[:origin] = presentables[:__origin]
124
+
125
+ node = view.object.each_significant_node(:field).find { |field_node|
126
+ field_node.attributes[:name] == "pw-form"
127
+ }
128
+
129
+ unless node.nil?
130
+ node.attributes[:value] = presentables[:__verifier].sign(
131
+ label(:form).to_json
132
+ )
133
+ end
134
+ end
135
+
136
+ presenter.render node: -> {
137
+ stringified_param = app.config.security.csrf.param.to_s
138
+ node = object.each_significant_node(:field, descend: true).find { |field_node|
139
+ field_node.attributes[:name] == stringified_param
140
+ }
141
+
142
+ unless node.nil?
143
+ View.from_object(node)
144
+ end
145
+ } do
146
+ attributes[:value] = presentables[:__verifier].sign(Support::MessageVerifier.key)
147
+ end
148
+
149
+ presenter.render node: -> {
150
+ object.each_significant_node(:method_override, descend: true).map { |node|
151
+ View.from_object(node)
152
+ }
153
+ } do
154
+ remove if attributes[:value].empty?
155
+ end
156
+ end
157
+
158
+ expose do |connection|
159
+ connection.set(:__params, connection.params)
160
+ connection.set(:__endpoint, connection.endpoint)
161
+ connection.set(:__verifier, connection.verifier)
162
+
163
+ origin = if connection.set?(:__form)
164
+ connection.get(:__form)[:origin]
165
+ else
166
+ connection.fullpath
167
+ end
168
+
169
+ connection.set(:__origin, origin)
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
@@ -188,7 +188,7 @@ module Pakyow
188
188
 
189
189
  def self.decorate(node)
190
190
  node.set_label(:presenter_type, Presenters::Form)
191
- node.set_label(:view_type, Form)
191
+ node.set_label(:view_type, Views::Form)
192
192
  end
193
193
  end
194
194
 
@@ -224,7 +224,7 @@ module Pakyow
224
224
  StringDoc.significant :method_override, self
225
225
 
226
226
  def self.significant?(node)
227
- node.is_a?(Oga::XML::Element) && node.name == INPUT_TAG && node.attribute(:name).to_s == "_method"
227
+ node.is_a?(Oga::XML::Element) && node.name == INPUT_TAG && node.attribute(:name).to_s == "pw-http-method"
228
228
  end
229
229
  end
230
230
 
@@ -9,7 +9,7 @@ module Pakyow
9
9
  using Support::DeepDup
10
10
  using Support::Refinements::String::Normalization
11
11
 
12
- attr_reader :name, :path, :layouts, :pages, :includes, :config
12
+ attr_reader :name, :path, :processor, :layouts, :pages, :includes, :config
13
13
 
14
14
  DEFAULT_LAYOUTS_PATH = "layouts"
15
15
  DEFAULT_PARTIALS_PATH = "includes"
@@ -109,8 +109,9 @@ module Pakyow
109
109
  @layouts = if File.exist?(layouts_path)
110
110
  layouts_path.children.each_with_object({}) { |file, layouts|
111
111
  next unless template?(file)
112
- layout = load_view_of_type_at_path(Layout, file)
113
- layouts[layout.name] = layout
112
+ if layout = load_view_of_type_at_path(Views::Layout, file)
113
+ layouts[layout.name] = layout
114
+ end
114
115
  }
115
116
  else
116
117
  {}
@@ -121,8 +122,9 @@ module Pakyow
121
122
  @includes = if File.exist?(partials_path)
122
123
  partials_path.children.each_with_object({}) { |file, partials|
123
124
  next unless template?(file)
124
- partial = load_view_of_type_at_path(Partial, file, normalize_path(file))
125
- partials[partial.name] = partial
125
+ if partial = load_view_of_type_at_path(Views::Partial, file, normalize_path(file))
126
+ partials[partial.name] = partial
127
+ end
126
128
  }
127
129
  else
128
130
  {}
@@ -140,7 +142,7 @@ module Pakyow
140
142
 
141
143
  begin
142
144
  if page = page_at_path(path)
143
- @info[File.join(@config[:prefix], normalize_path(path, pages_path))] = {
145
+ @info[String.normalize_path(File.join(@config[:prefix], normalize_path(path, pages_path)))] = {
144
146
  page: page,
145
147
  layout: layout_with_name(page.info(:layout)),
146
148
  partials: @includes.merge(partials_at_path(path))
@@ -168,7 +170,7 @@ module Pakyow
168
170
  index_page_at_path(path)
169
171
  end
170
172
  else
171
- load_view_of_type_at_path(Page, path, normalize_path(path))
173
+ load_view_of_type_at_path(Views::Page, path, normalize_path(path))
172
174
  end
173
175
  end
174
176
 
@@ -208,21 +210,28 @@ module Pakyow
208
210
  parent_path.children.select { |child|
209
211
  child.basename.to_s.start_with?("_")
210
212
  }.each_with_object(partials) { |child, child_partials|
211
- partial = load_view_of_type_at_path(Partial, child, normalize_path(child))
212
- child_partials[partial.name] ||= partial
213
+ if partial = load_view_of_type_at_path(Views::Partial, child, normalize_path(child))
214
+ child_partials[partial.name] ||= partial
215
+ end
213
216
  }
214
217
  }
215
218
  end
216
219
 
217
220
  def load_view_of_type_at_path(type, path, logical_path = nil)
218
- content = File.read(path)
219
- info, content = FrontMatterParser.parse_and_scrub(content)
221
+ extension = File.extname(path)
220
222
 
221
- if @processor
222
- content = @processor.process(content, File.extname(path).delete(".").to_sym)
223
- end
223
+ if extension.end_with?(".html") || @processor&.process?(extension)
224
+ content = File.read(path)
225
+ info, content = FrontMatterParser.parse_and_scrub(content)
224
226
 
225
- type.load(path, info: info, content: content, logical_path: logical_path)
227
+ if @processor
228
+ content = @processor.process(content, extension.delete(".").to_sym)
229
+ end
230
+
231
+ type.load(path, info: info, content: content, logical_path: logical_path)
232
+ else
233
+ nil
234
+ end
226
235
  end
227
236
  end
228
237
  end
@@ -27,6 +27,7 @@ module Pakyow
27
27
  determine_working_version
28
28
  end
29
29
 
30
+ # @api private
30
31
  def soft_copy
31
32
  instance = self.class.allocate
32
33
 
@@ -43,6 +43,7 @@ module Pakyow
43
43
  instance
44
44
  end
45
45
 
46
+ # @api private
46
47
  def from_view_or_string(view_or_string)
47
48
  case view_or_string
48
49
  when View, VersionedView
@@ -62,18 +63,15 @@ module Pakyow
62
63
 
63
64
  def_delegators :@object, :type, :text, :html, :label, :labeled?
64
65
 
65
- # The object responsible for parsing, manipulating, and rendering
66
- # the underlying HTML document for the view.
66
+ # The object responsible for transforming and rendering the underlying document or node.
67
67
  #
68
- attr_reader :object
68
+ # @api private
69
+ attr_accessor :object
69
70
 
70
71
  # The logical path to the view template.
71
72
  #
72
73
  attr_reader :logical_path
73
74
 
74
- # @api private
75
- attr_writer :object
76
-
77
75
  # Creates a view with +html+.
78
76
  #
79
77
  def initialize(html, info: {}, logical_path: nil)
@@ -100,6 +98,7 @@ module Pakyow
100
98
  end
101
99
  end
102
100
 
101
+ # @api private
103
102
  def soft_copy
104
103
  instance = self.class.allocate
105
104
 
@@ -148,6 +147,7 @@ module Pakyow
148
147
 
149
148
  # Finds all view bindings by name, returning an array of {View} objects.
150
149
  #
150
+ # @api private
151
151
  def find_all(named)
152
152
  each_binding(named).map { |node|
153
153
  View.from_object(node)
@@ -158,7 +158,7 @@ module Pakyow
158
158
  #
159
159
  def form(name)
160
160
  @object.each_significant_node(:form) do |form_node|
161
- return Form.from_object(form_node) if form_node.label(:binding) == name
161
+ return Views::Form.from_object(form_node) if form_node.label(:binding) == name
162
162
  end
163
163
 
164
164
  nil
@@ -166,9 +166,10 @@ module Pakyow
166
166
 
167
167
  # Returns all forms.
168
168
  #
169
+ # @api private
169
170
  def forms
170
171
  @object.each_significant_node(:form, descend: true).map { |node|
171
- Form.from_object(node)
172
+ Views::Form.from_object(node)
172
173
  }
173
174
  end
174
175
 
@@ -185,6 +186,7 @@ module Pakyow
185
186
 
186
187
  # Returns all components.
187
188
  #
189
+ # @api private
188
190
  def components(renderable: false)
189
191
  @object.each_significant_node_without_descending_into_type(:component, descend: true).select { |node|
190
192
  !renderable || node.label(:components).any? { |component| component[:renderable] }
@@ -567,7 +569,7 @@ module Pakyow
567
569
  }
568
570
  end
569
571
 
570
- protected
572
+ private
571
573
 
572
574
  def bind_value_to_node(value, node)
573
575
  tag = node.tagname