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