pakyow-presenter 1.0.0.rc2 → 1.0.0.rc3

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