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
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "pakyow/error"
4
-
5
- module Pakyow
6
- class Error
7
- def [](key)
8
- if respond_to?(key)
9
- public_send(key)
10
- else
11
- nil
12
- end
13
- end
14
-
15
- def include?(key)
16
- respond_to?(key)
17
- end
18
- end
19
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "pakyow/support/extension"
4
-
5
- module Pakyow
6
- module Presenter
7
- module Actions
8
- module CleanupPrototypeNodes
9
- extend Support::Extension
10
-
11
- apply_extension do
12
- build do |view|
13
- unless Pakyow.env?(:prototype)
14
- view.object.each_significant_node(:prototype, descend: true).map(&:itself).each(&:remove)
15
- end
16
- end
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "pakyow/support/extension"
4
-
5
- module Pakyow
6
- module Presenter
7
- module Actions
8
- module CleanupUnboundBindings
9
- extend Support::Extension
10
-
11
- apply_extension do
12
- attach do |presenter|
13
- unless Pakyow.env?(:prototype)
14
- # Cleanup unbound bindings. We don't do this in prototype mode because it's important
15
- # for the prototype to be complete, showing everything to the designer.
16
- #
17
- presenter.render node: -> {
18
- object.find_significant_nodes(:binding, descend: true).map { |node|
19
- View.from_object(node)
20
- }
21
- }, priority: :low do
22
- # We check that the node is still labeled as a binding in case the node was replaced
23
- # during a previous transformation with a node that isn't a binding.
24
- #
25
- unless !view.object.labeled?(:binding) || view.object.labeled?(:bound) || view.object.labeled?(:failed) || view.object.label(:version) == :empty
26
- remove
27
- end
28
- end
29
- end
30
- end
31
- end
32
- end
33
- end
34
- end
35
- end
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "pakyow/support/extension"
4
-
5
- module Pakyow
6
- module Presenter
7
- module Actions
8
- module CreateTemplateNodes
9
- extend Support::Extension
10
-
11
- apply_extension do
12
- build do |view|
13
- unless Pakyow.env?(:prototype)
14
- view.each_binding_scope(descend: true) do |node_with_binding|
15
- attributes = node_with_binding.attributes.attributes_hash.each_with_object({}) do |(attribute, value), acc|
16
- acc[attribute] = value if attribute.to_s.start_with?("data")
17
- end
18
-
19
- node_with_binding.after("<script type=\"text/template\"#{StringDoc::Attributes.new(attributes).to_s}>#{node_with_binding.render}</script>")
20
- end
21
- end
22
- end
23
- end
24
- end
25
- end
26
- end
27
- end
@@ -1,101 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "pakyow/support/extension"
4
-
5
- module Pakyow
6
- module Presenter
7
- module Actions
8
- module InsertPrototypeBar
9
- extend Support::Extension
10
-
11
- apply_extension do
12
- attach do |presenter|
13
- if Pakyow.env?(:prototype)
14
- presenter.render node: -> {
15
- if body = object.find_first_significant_node(:body)
16
- View.from_object(body)
17
- end
18
- } do
19
- view.object.append_html <<~HTML
20
- <style>
21
- .pw-prototype {
22
- font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
23
- display:flex;
24
- align-items: center;
25
- position: fixed;
26
- z-index: 1000;
27
- right: 0;
28
- bottom: 0;
29
- background: #156eed;
30
- color: #fff;
31
- font-size: 11px;
32
- line-height: 11px;
33
- font-weight: 500;
34
- border-top-left-radius: 1px;
35
- padding-left: 5px;
36
- }
37
-
38
- .pw-prototype-tag {
39
- background: #ff8b6c;
40
- color: #fff;
41
- text-transform: uppercase;
42
- font-size: 10px;
43
- line-height: 12px;
44
- font-weight: 600;
45
- padding: 5px 5px 4px 5px;
46
- margin-left: 10px;
47
- }
48
- </style>
49
-
50
- <div class="pw-prototype">
51
- #{InsertPrototypeBar.ui_modes_html(view, __modes || [:default])}
52
-
53
- <div class="pw-prototype-tag">
54
- Prototype
55
- </div>
56
- </div>
57
- HTML
58
- end
59
- end
60
- end
61
-
62
- expose do |connection|
63
- if Pakyow.env?(:prototype)
64
- connection.set(:__modes, connection.params[:modes])
65
- end
66
- end
67
- end
68
-
69
- # @api private
70
- def self.ui_modes_html(view, current_modes)
71
- current_modes = current_modes.map(&:to_sym)
72
-
73
- modes = view.object.each_significant_node(:mode).map { |node|
74
- node.label(:mode)
75
- }
76
-
77
- modes.unshift(
78
- (view.info(:mode) || :default).to_sym
79
- ).uniq!
80
-
81
- options = modes.map { |each_mode|
82
- selected = if current_modes.include?(each_mode)
83
- " selected=\"selected\""
84
- else
85
- ""
86
- end
87
-
88
- nice_mode = Support.inflector.humanize(Support.inflector.underscore(each_mode))
89
- "<option value=\"#{each_mode}\"#{selected}>#{nice_mode}</option>"
90
- }.join
91
-
92
- <<~HTML
93
- UI Mode: <select onchange="document.location = window.location.pathname + '?modes[]=' + this.value " style="-webkit-appearance: none; -moz-appearance: none; -ms-appearance: none; -o-appearance: none; appearance: none; font-size: 11px; font-weight: 500; line-height: 20px; background: none; border: none; color: #fff; outline: none; margin: 0; margin-left: 5px;">
94
- #{options}
95
- </select>
96
- HTML
97
- end
98
- end
99
- end
100
- end
101
- end
@@ -1,42 +0,0 @@
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
- module Pakyow
8
- module Presenter
9
- module Actions
10
- module InstallAuthenticity
11
- extend Support::Extension
12
-
13
- apply_extension do
14
- build do |view, app:|
15
- if app.config.presenter.embed_authenticity_token && head = view.head
16
- head.append(Support::SafeStringHelpers.html_safe("<meta name=\"pw-authenticity-token\">"))
17
- head.append(Support::SafeStringHelpers.html_safe("<meta name=\"pw-authenticity-param\" content=\"#{app.config.security.csrf.param}\">"))
18
- end
19
- end
20
-
21
- attach do |presenter|
22
- presenter.render node: -> {
23
- node = object.each_significant_node(:meta).find { |meta_node|
24
- meta_node.attributes[:name] == "pw-authenticity-token"
25
- }
26
-
27
- unless node.nil?
28
- View.from_object(node)
29
- end
30
- } do
31
- attributes[:content] = @presentables[:__verifier].sign(Support::MessageVerifier.key)
32
- end
33
- end
34
-
35
- expose do |connection|
36
- connection.set(:__verifier, connection.verifier)
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "pakyow/support/extension"
4
-
5
- module Pakyow
6
- module Presenter
7
- module Actions
8
- module PlaceInMode
9
- extend Support::Extension
10
-
11
- apply_extension do
12
- build do |view, modes:|
13
- unless Pakyow.env?(:prototype)
14
- PlaceInMode.perform(view, modes)
15
- end
16
- end
17
-
18
- attach do |presenter|
19
- if Pakyow.env?(:prototype)
20
- presenter.render node: -> {
21
- object.find_significant_nodes(:mode, descend: true).map { |node|
22
- View.from_object(node)
23
- }
24
- } do
25
- PlaceInMode.perform(view, __modes)
26
- end
27
- end
28
- end
29
-
30
- expose do |connection|
31
- if Pakyow.env?(:prototype)
32
- connection.set(:__modes, connection.params[:modes] || [:default])
33
- end
34
- end
35
- end
36
-
37
- # @api private
38
- def self.perform(view, modes)
39
- if modes.length == 1 && modes.first.to_sym == :default
40
- modes = view.info(:modes) || modes
41
- end
42
-
43
- modes.map!(&:to_sym)
44
-
45
- if view.object.is_a?(StringDoc::Node) && view.object.significant?(:mode) && !modes.include?(view.object.label(:mode))
46
- view.remove
47
- else
48
- view.object.each_significant_node(:mode, descend: true).select { |node|
49
- !modes.include?(node.label(:mode))
50
- }.each(&:remove)
51
- end
52
- end
53
- end
54
- end
55
- end
56
- end
@@ -1,279 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "pakyow/support/extension"
4
-
5
- require "pakyow/presenter/composers/component"
6
-
7
- module Pakyow
8
- module Presenter
9
- module Actions
10
- module RenderComponents
11
- extend Support::Extension
12
-
13
- apply_extension do
14
- build do |view, app:, composer:, modes:|
15
- unless Pakyow.env?(:prototype)
16
- initial_path = case composer
17
- when Composers::Component
18
- composer.component_path
19
- else
20
- []
21
- end
22
-
23
- component_view = case composer
24
- when Composers::Component
25
- composer.class.follow_path(composer.component_path, view)
26
- else
27
- view
28
- end
29
-
30
- RenderComponents.initialize_renderable_components(
31
- component_view, app: app, composer: composer, modes: modes, path: initial_path
32
- )
33
- end
34
- end
35
-
36
- expose do |connection|
37
- # Prevent state from leaking from the component to the rest of the app.
38
- #
39
- component_connection = connection.dup
40
-
41
- # Expose the component connection for performing from each component.
42
- #
43
- connection.set(:__component_connection, component_connection)
44
- end
45
- end
46
-
47
- # @api private
48
- def self.initialize_renderable_components(view, app:, composer:, modes:, path: [])
49
- view.components.each_with_index do |component_view, i|
50
- current_path = path.dup
51
- current_path << i
52
-
53
- # If view will be rendered from the app, look for the component on the app.
54
- #
55
- component_state = if app.is_a?(Plugin) && app.parent.view?(composer.view_path)
56
- app.parent.state(:component)
57
- else
58
- app.state(:component)
59
- end
60
-
61
- components = component_view.object.label(:components).each_with_object([]) { |component_label, arr|
62
- component_class = component_state.find { |component|
63
- component.__object_name.name == component_label[:name]
64
- }
65
-
66
- if component_class
67
- # Turn the component into a renderable component. Once an instance is attached on the
68
- # backend, the component will not be traversed by renders from its parent instead being
69
- # rendered by its own renderer instance.
70
- #
71
- # We don't want the same restriction for non-renderable components because a change to
72
- # the view should not affect how things work on the backend.
73
- #
74
- component_label[:renderable] = true
75
-
76
- arr << {
77
- class: component_class,
78
- config: component_label[:config]
79
- }
80
- end
81
- }
82
-
83
- if components.any?
84
- # Since one or more attached components is renderable, we no longer want to descend.
85
- #
86
- component_view.object.set_label(:descend, false)
87
-
88
- # Define the render function that calls the component and renders it at render time.
89
- #
90
- component_render = app.isolated(:Presenter).send(:render_proc, component_view) { |node, _context, string|
91
- presentable_component_connection = presentables[:__component_connection]
92
- component_connection = presentable_component_connection.dup
93
-
94
- components.each do |component|
95
- presentables.each do |key, value|
96
- if key.to_s.start_with?("__")
97
- component_connection.set(key, value)
98
- end
99
- end
100
-
101
- # If the component was defined in an app but being called inside a plugin, set the app to the app instead of the plugin.
102
- #
103
- if component_connection.app.is_a?(Plugin) && component[:class].ancestors.include?(component_connection.app.parent.isolated(:Component))
104
- component_connection = component_connection.class.from_connection(component_connection, :@app => component_connection.app.parent)
105
- end
106
-
107
- component_instance = component[:class].new(
108
- connection: component_connection,
109
- config: component[:config]
110
- )
111
-
112
- # Call the component.
113
- #
114
- component_instance.perform
115
- end
116
-
117
- # Build a compound component presenter.
118
- #
119
- component_presenter = if components.length > 1
120
- RenderComponents.find_compound_presenter(
121
- app, components.map { |c| c[:class] }
122
- )
123
- else
124
- components.first[:class].__presenter_class
125
- end
126
-
127
- # Setup the renderer for the component.
128
- #
129
- renderer = app.isolated(:Renderer).new(
130
- app: app,
131
- presentables: component_connection.values,
132
- presenter_class: component_presenter,
133
- composer: Composers::Component.new(
134
- composer.view_path, current_path, app: app, labels: node.labels
135
- ),
136
- modes: modes
137
- )
138
-
139
- # Render to the main buffer.
140
- #
141
- renderer.perform(string)
142
-
143
- # Return nil so nothing else gets written.
144
- #
145
- nil
146
- }
147
-
148
- # Attach the above render function to the render node.
149
- #
150
- component_view.object.transform do |node, context, string|
151
- component_render.call(node, context, string); nil
152
- end
153
- else
154
- initialize_renderable_components(
155
- component_view, app: app, composer: composer, modes: modes, path: current_path
156
- )
157
- end
158
- end
159
- end
160
-
161
- # @api private
162
- def self.find_renderable_components(view, components = [])
163
- view.components.each do |component_view|
164
- find_renderable_components(component_view, components)
165
-
166
- if component_view.object.label(:components).any? { |c| c[:renderable] }
167
- components << component_view
168
- end
169
- end
170
-
171
- components
172
- end
173
-
174
- # @api private
175
- def self.wrap_block(block, context_class)
176
- Proc.new do
177
- @app.presenter_for_context(
178
- context_class.__presenter_class, self
179
- ).instance_eval(&block)
180
- end
181
- end
182
-
183
- # @api private
184
- def self.find_compound_presenter(app, component_classes)
185
- compound_name = component_classes.map { |component_class|
186
- component_class.__object_name.name.to_s
187
- }.join("_")
188
-
189
- object_name = Support::ObjectName.namespace(
190
- app.class.__object_name.namespace.parts[0], :components, compound_name, :presenter
191
- )
192
-
193
- if const_defined?(object_name.constant)
194
- const_get(object_name.constant)
195
- else
196
- nil
197
- end
198
- end
199
-
200
- # @api private
201
- #
202
- def self.find_or_build_compound_presenter(app, component_classes)
203
- compound_name = component_classes.map { |component_class|
204
- component_class.__object_name.name.to_s
205
- }.join("_")
206
-
207
- object_name = Support::ObjectName.namespace(
208
- app.class.__object_name.namespace.parts[0], :components, compound_name, :presenter
209
- )
210
-
211
- if const_defined?(object_name.constant)
212
- const_get(object_name.constant)
213
- else
214
- component_presenter = Class.new(app.isolated(:Presenter))
215
- Support::ObjectMaker.define_const_for_object_with_name(component_presenter, object_name)
216
-
217
- component_classes.each do |component_class|
218
- # Copy unique attached renders.
219
- #
220
- component_class.__presenter_class.__attached_renders.each_with_index do |attached_render, i|
221
- component_presenter.__attached_renders.insert(i, {
222
- binding_path: attached_render[:binding_path],
223
- channel: attached_render[:channel],
224
- node: attached_render[:node],
225
- priority: attached_render[:priority],
226
- block: wrap_block(attached_render[:block], component_class),
227
- })
228
- end
229
-
230
- # Copy unique global options.
231
- #
232
- component_class.__presenter_class.__global_options.each do |form_binding, field_binding_values|
233
- field_binding_values.each do |field_binding, field_binding_value|
234
- component_presenter.options_for(
235
- form_binding,
236
- field_binding,
237
- field_binding_value[:options],
238
- &wrap_block(field_binding_value[:block], component_class)
239
- )
240
- end
241
- end
242
-
243
- # Copy unique presentation logic.
244
- #
245
- component_class.__presenter_class.__presentation_logic.each do |binding_name, logic_arr|
246
- unless component_presenter.__presentation_logic.include?(binding_name)
247
- component_presenter.__presentation_logic[binding_name] = []
248
- end
249
-
250
- logic_arr.each_with_index do |logic, i|
251
- component_presenter.__presentation_logic[binding_name].insert(i, {
252
- block: wrap_block(logic[:block], component_class),
253
- channel: logic[:channel]
254
- })
255
- end
256
- end
257
-
258
- # Copy unique versioning logic.
259
- #
260
- component_class.__presenter_class.__versioning_logic.each do |binding_name, logic_arr|
261
- unless component_presenter.__versioning_logic.include?(binding_name)
262
- component_presenter.__versioning_logic[binding_name] = []
263
- end
264
-
265
- logic_arr.each_with_index do |logic, i|
266
- component_presenter.__versioning_logic[binding_name].insert(i, {
267
- block: wrap_block(logic[:block], component_class)
268
- })
269
- end
270
- end
271
- end
272
-
273
- component_presenter
274
- end
275
- end
276
- end
277
- end
278
- end
279
- end