pakyow-presenter 0.11.3 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +5 -5
  2. data/{pakyow-presenter/CHANGELOG.md → CHANGELOG.md} +0 -5
  3. data/LICENSE +4 -0
  4. data/{pakyow-presenter/README.md → README.md} +1 -2
  5. data/lib/pakyow/generators/presenter/presenter_generator.rb +28 -0
  6. data/lib/pakyow/generators/presenter/templates/presenter.rb.tt +2 -0
  7. data/lib/pakyow/plugin/helpers/rendering.rb +19 -0
  8. data/lib/pakyow/presenter/actions/auto_render.rb +15 -0
  9. data/lib/pakyow/presenter/attributes/attribute.rb +22 -0
  10. data/lib/pakyow/presenter/attributes/boolean.rb +24 -0
  11. data/lib/pakyow/presenter/attributes/hash.rb +89 -0
  12. data/lib/pakyow/presenter/attributes/set.rb +61 -0
  13. data/lib/pakyow/presenter/attributes/string.rb +38 -0
  14. data/lib/pakyow/presenter/attributes.rb +126 -0
  15. data/lib/pakyow/presenter/behavior/config.rb +29 -0
  16. data/lib/pakyow/presenter/behavior/error_rendering.rb +124 -0
  17. data/lib/pakyow/presenter/behavior/exposures.rb +29 -0
  18. data/lib/pakyow/presenter/behavior/implicit_rendering.rb +21 -0
  19. data/lib/pakyow/presenter/behavior/initializing.rb +37 -0
  20. data/lib/pakyow/presenter/behavior/modes.rb +117 -0
  21. data/lib/pakyow/presenter/behavior/versions.rb +71 -0
  22. data/lib/pakyow/presenter/behavior/watching.rb +21 -0
  23. data/lib/pakyow/presenter/binder.rb +115 -0
  24. data/lib/pakyow/presenter/binding_parts.rb +64 -0
  25. data/lib/pakyow/presenter/component.rb +74 -0
  26. data/lib/pakyow/presenter/composers/component.rb +78 -0
  27. data/lib/pakyow/presenter/composers/view.rb +73 -0
  28. data/lib/pakyow/presenter/errors.rb +63 -0
  29. data/lib/pakyow/presenter/framework.rb +203 -0
  30. data/lib/pakyow/presenter/front_matter_parser.rb +42 -0
  31. data/lib/pakyow/presenter/helpers/rendering.rb +18 -0
  32. data/lib/pakyow/presenter/presentable.rb +28 -0
  33. data/lib/pakyow/presenter/presentable_error.rb +19 -0
  34. data/lib/pakyow/presenter/presenter.rb +766 -0
  35. data/lib/pakyow/presenter/presenters/endpoint.rb +158 -0
  36. data/lib/pakyow/presenter/presenters/form.rb +522 -0
  37. data/lib/pakyow/presenter/processor.rb +61 -0
  38. data/lib/pakyow/presenter/renderable.rb +28 -0
  39. data/lib/pakyow/presenter/renderer.rb +269 -0
  40. data/lib/pakyow/presenter/rendering/actions/cleanup_prototype_nodes.rb +21 -0
  41. data/lib/pakyow/presenter/rendering/actions/cleanup_unbound_bindings.rb +35 -0
  42. data/lib/pakyow/presenter/rendering/actions/create_template_nodes.rb +27 -0
  43. data/lib/pakyow/presenter/rendering/actions/insert_prototype_bar.rb +101 -0
  44. data/lib/pakyow/presenter/rendering/actions/install_authenticity.rb +42 -0
  45. data/lib/pakyow/presenter/rendering/actions/place_in_mode.rb +56 -0
  46. data/lib/pakyow/presenter/rendering/actions/render_components.rb +279 -0
  47. data/lib/pakyow/presenter/rendering/actions/set_page_title.rb +35 -0
  48. data/lib/pakyow/presenter/rendering/actions/setup_endpoints.rb +62 -0
  49. data/lib/pakyow/presenter/rendering/actions/setup_forms.rb +174 -0
  50. data/lib/pakyow/presenter/significant_nodes.rb +309 -0
  51. data/lib/pakyow/presenter/templates.rb +229 -0
  52. data/lib/pakyow/presenter/versioned_view.rb +209 -0
  53. data/lib/pakyow/presenter/view.rb +586 -0
  54. data/lib/pakyow/presenter/views/form.rb +58 -0
  55. data/lib/pakyow/presenter/views/layout.rb +32 -0
  56. data/lib/pakyow/presenter/views/page.rb +72 -0
  57. data/lib/pakyow/presenter/views/partial.rb +28 -0
  58. data/lib/pakyow/presenter.rb +33 -0
  59. data/lib/pakyow/views/errors/layouts/development_error.html +102 -0
  60. data/lib/pakyow/views/errors/layouts/production_error.html +27 -0
  61. data/lib/pakyow/views/errors/pages/404.html +12 -0
  62. data/lib/pakyow/views/errors/pages/500.html +12 -0
  63. data/lib/pakyow/views/errors/pages/development/500.html +39 -0
  64. data/lib/string_doc/attributes.rb +109 -0
  65. data/lib/string_doc/meta_attributes.rb +48 -0
  66. data/lib/string_doc/meta_node.rb +328 -0
  67. data/lib/string_doc/node.rb +377 -0
  68. data/lib/string_doc.rb +642 -0
  69. metadata +95 -75
  70. data/pakyow-presenter/LICENSE +0 -20
  71. data/pakyow-presenter/lib/pakyow/presenter/attributes.rb +0 -228
  72. data/pakyow-presenter/lib/pakyow/presenter/base.rb +0 -38
  73. data/pakyow-presenter/lib/pakyow/presenter/binder.rb +0 -116
  74. data/pakyow-presenter/lib/pakyow/presenter/binder_set.rb +0 -94
  75. data/pakyow-presenter/lib/pakyow/presenter/binding_eval.rb +0 -37
  76. data/pakyow-presenter/lib/pakyow/presenter/config/presenter.rb +0 -42
  77. data/pakyow-presenter/lib/pakyow/presenter/container.rb +0 -6
  78. data/pakyow-presenter/lib/pakyow/presenter/doc_helpers.rb +0 -17
  79. data/pakyow-presenter/lib/pakyow/presenter/exceptions.rb +0 -11
  80. data/pakyow-presenter/lib/pakyow/presenter/ext/app.rb +0 -33
  81. data/pakyow-presenter/lib/pakyow/presenter/ext/call_context.rb +0 -28
  82. data/pakyow-presenter/lib/pakyow/presenter/helpers.rb +0 -46
  83. data/pakyow-presenter/lib/pakyow/presenter/page.rb +0 -110
  84. data/pakyow-presenter/lib/pakyow/presenter/partial.rb +0 -6
  85. data/pakyow-presenter/lib/pakyow/presenter/presenter.rb +0 -232
  86. data/pakyow-presenter/lib/pakyow/presenter/string_doc.rb +0 -380
  87. data/pakyow-presenter/lib/pakyow/presenter/string_doc_parser.rb +0 -144
  88. data/pakyow-presenter/lib/pakyow/presenter/string_doc_renderer.rb +0 -18
  89. data/pakyow-presenter/lib/pakyow/presenter/template.rb +0 -51
  90. data/pakyow-presenter/lib/pakyow/presenter/view.rb +0 -541
  91. data/pakyow-presenter/lib/pakyow/presenter/view_collection.rb +0 -330
  92. data/pakyow-presenter/lib/pakyow/presenter/view_composer.rb +0 -237
  93. data/pakyow-presenter/lib/pakyow/presenter/view_context.rb +0 -111
  94. data/pakyow-presenter/lib/pakyow/presenter/view_store.rb +0 -262
  95. data/pakyow-presenter/lib/pakyow/presenter/view_store_loader.rb +0 -43
  96. data/pakyow-presenter/lib/pakyow/presenter/view_version.rb +0 -113
  97. data/pakyow-presenter/lib/pakyow/presenter.rb +0 -8
  98. data/pakyow-presenter/lib/pakyow/views/errors/404.erb +0 -26
  99. data/pakyow-presenter/lib/pakyow/views/errors/500.erb +0 -23
  100. data/pakyow-presenter/lib/pakyow-presenter.rb +0 -1
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pakyow
4
+ module Presenter
5
+ class ProcessorCaller
6
+ def initialize(instances)
7
+ @processors = normalize(instances)
8
+ end
9
+
10
+ def process(content, extension)
11
+ processors_for_extension(extension).each do |processor|
12
+ content = processor.process(content)
13
+ end
14
+
15
+ unless extension == :html
16
+ processors_for_extension(:html).each do |processor|
17
+ content = processor.process(content)
18
+ end
19
+ end
20
+
21
+ content
22
+ end
23
+
24
+ def process?(extension)
25
+ @processors.key?(extension.tr(".", "").to_sym)
26
+ end
27
+
28
+ protected
29
+
30
+ def processors_for_extension(extension)
31
+ @processors[extension] || []
32
+ end
33
+
34
+ def normalize(instances)
35
+ instances.each_with_object({}) { |instance, processors|
36
+ instance.extensions.each do |extension|
37
+ (processors[extension] ||= []) << instance
38
+ end
39
+ }
40
+ end
41
+ end
42
+
43
+ class Processor
44
+ extend Support::Makeable
45
+
46
+ class << self
47
+ attr_reader :name, :extensions, :block
48
+
49
+ def make(name, *extensions, **kwargs, &block)
50
+ # name is expected to also be an extension
51
+ extensions.unshift(name).map!(&:to_sym)
52
+ super(name, extensions: extensions, block: block, **kwargs) {}
53
+ end
54
+
55
+ def process(content)
56
+ block.call(content)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/support/extension"
4
+
5
+ module Pakyow
6
+ module Presenter
7
+ # @api private
8
+ module Renderable
9
+ extend Support::Extension
10
+
11
+ prepend_methods do
12
+ def initialize(*args)
13
+ @rendered = false
14
+ super
15
+ end
16
+ end
17
+
18
+ def rendered
19
+ @rendered = true
20
+ halt
21
+ end
22
+
23
+ def rendered?
24
+ @rendered == true
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,269 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pakyow/support/class_state"
4
+ require "pakyow/support/deep_freeze"
5
+ require "pakyow/support/hookable"
6
+
7
+ require "pakyow/support/core_refinements/proc/introspection"
8
+ require "pakyow/support/core_refinements/string/normalization"
9
+
10
+ require "pakyow/presenter/rendering/actions/render_components"
11
+
12
+ require "pakyow/presenter/composers/view"
13
+
14
+ module Pakyow
15
+ module Presenter
16
+ class Renderer
17
+ using Support::DeepFreeze
18
+
19
+ extend Support::ClassState
20
+ class_state :__presenter_views, default: {}, inheritable: true
21
+ class_state :__presenters_by_path, default: {}, inheritable: true
22
+ class_state :__build_fns, default: [], inheritable: true
23
+ class_state :__attach_fns, default: [], inheritable: true
24
+ class_state :__expose_fns, default: [], inheritable: true
25
+
26
+ extend Support::DeepFreeze
27
+ unfreezable :__presenters_by_path, :__presenter_views
28
+
29
+ include Support::Hookable
30
+ events :render
31
+
32
+ # @api private
33
+ attr_reader :app, :presentables, :presenter
34
+
35
+ def initialize(app:, presentables:, presenter_class:, composer:, modes: [:default])
36
+ @app, @presentables, @presenter_class, @composer, @modes = app, presentables, presenter_class, composer, modes
37
+ initialize_presenter
38
+ end
39
+
40
+ def perform(output = String.new)
41
+ performing :render do
42
+ @presenter.to_html(output)
43
+ end
44
+ end
45
+
46
+ def marshal_dump
47
+ {
48
+ app: @app,
49
+ presentables: @presentables.reject { |_, value|
50
+ # Filter out the component connection that we expose for component rendering.
51
+ #
52
+ value.is_a?(@app.isolated(:Connection))
53
+ },
54
+ presenter_class: @presenter_class,
55
+ composer: @composer,
56
+ modes: @modes
57
+ }
58
+ end
59
+
60
+ def marshal_load(state)
61
+ deserialize(state)
62
+ initialize_presenter
63
+ end
64
+
65
+ private
66
+
67
+ def deserialize(state)
68
+ state.each do |key, value|
69
+ instance_variable_set(:"@#{key}", value)
70
+ end
71
+ end
72
+
73
+ def initialize_presenter
74
+ @presenter = @presenter_class.new(
75
+ find_or_build_presenter_view(@app, @composer, @presenter_class, @modes),
76
+ presentables: @presentables, app: @app
77
+ )
78
+ end
79
+
80
+ def find_or_build_presenter_view(app, composer, presenter, modes)
81
+ presenter_view_key = [composer.key, presenter, modes]
82
+
83
+ unless presenter_view = self.class.__presenter_views[presenter_view_key]
84
+ presenter_view = composer.view
85
+
86
+ self.class.build!(presenter_view, app: app, modes: modes, composer: composer)
87
+
88
+ if composer.respond_to?(:post_process)
89
+ presenter_view = composer.post_process(presenter_view)
90
+ end
91
+
92
+ presenter.attach(presenter_view)
93
+ presenter_view.deep_freeze
94
+
95
+ self.class.__presenter_views[presenter_view_key] = presenter_view
96
+ end
97
+
98
+ if composer.respond_to?(:finalize)
99
+ presenter_view = composer.finalize(presenter_view)
100
+ end
101
+
102
+ presenter_view
103
+ end
104
+
105
+ class << self
106
+ using Support::Refinements::Proc::Introspection
107
+ using Support::Refinements::String::Normalization
108
+
109
+ def render(connection, view_path: nil, presenter_path: nil, modes: [:default])
110
+ connection.app.__ui_modes.each do |mode, block|
111
+ if block.call(connection)
112
+ modes << mode
113
+ end
114
+ end
115
+
116
+ view_path = if view_path
117
+ String.normalize_path(view_path)
118
+ else
119
+ connection.get(:__endpoint_path) || connection.path
120
+ end
121
+
122
+ presenter_path = if presenter_path
123
+ String.normalize_path(presenter_path)
124
+ else
125
+ view_path.dup
126
+ end
127
+
128
+ if connection.app.is_a?(Plugin) && connection.app.class.mount_path != "/"
129
+ presenter_path.gsub!(/^#{connection.app.class.mount_path}/, "")
130
+ end
131
+
132
+ presenter = find_presenter(connection.app, presenter_path)
133
+
134
+ expose!(connection)
135
+
136
+ renderer = new(
137
+ app: connection.app,
138
+ presentables: connection.values,
139
+ presenter_class: presenter,
140
+ composer: Composers::View.new(view_path, app: connection.app),
141
+ modes: modes
142
+ )
143
+
144
+ connection.set_header("content-type", "text/html")
145
+
146
+ if connection.app.config.presenter.features.streaming
147
+ connection.stream do
148
+ renderer.perform(connection.body)
149
+ end
150
+ else
151
+ output = renderer.perform(StringIO.new); output.rewind
152
+ connection.body = output
153
+ end
154
+
155
+ connection.rendered
156
+ end
157
+
158
+ def render_implicitly(connection)
159
+ view_path = connection.get(:__endpoint_path) || connection.path
160
+
161
+ if render_implicitly?(connection)
162
+ begin
163
+ catch :halt do
164
+ render(connection, view_path: view_path)
165
+ end
166
+ rescue UnknownPage => error
167
+ unless connection.app.is_a?(Plugin)
168
+ raise ImplicitRenderingError.build(error, context: view_path)
169
+ end
170
+ end
171
+ end
172
+ rescue StandardError => error
173
+ connection.logger.houston(error)
174
+
175
+ if connection.app.class.includes_framework?(:routing)
176
+ catch :halt do
177
+ connection.app.controller_for_connection(connection).handle_error(error)
178
+ end
179
+ end
180
+ end
181
+
182
+ def build!(view, app:, modes:, composer:)
183
+ @__build_fns.each do |fn|
184
+ options = {}
185
+
186
+ if fn.keyword_argument?(:app)
187
+ options[:app] = app
188
+ end
189
+
190
+ if fn.keyword_argument?(:modes)
191
+ options[:modes] = modes
192
+ end
193
+
194
+ if fn.keyword_argument?(:composer)
195
+ options[:composer] = composer
196
+ end
197
+
198
+ fn.call(view, **options)
199
+ end
200
+ end
201
+
202
+ def attach!(presenter, app:)
203
+ @__attach_fns.each do |fn|
204
+ options = {}
205
+
206
+ if fn.keyword_argument?(:app)
207
+ options[:app] = app
208
+ end
209
+
210
+ fn.call(presenter, **options)
211
+ end
212
+ end
213
+
214
+ def expose!(connection)
215
+ @__expose_fns.each do |fn|
216
+ fn.call(connection)
217
+ end
218
+ end
219
+
220
+ def find_presenter(app, path)
221
+ path = String.normalize_path(path)
222
+ unless presenter = @__presenters_by_path[path]
223
+ presenter = if path.nil? || Pakyow.env?(:prototype)
224
+ app.isolated(:Presenter)
225
+ else
226
+ find_presenter_for_path(app, path)
227
+ end
228
+
229
+ @__presenters_by_path[path] = presenter
230
+ end
231
+
232
+ presenter
233
+ end
234
+
235
+ private
236
+
237
+ def build(&block)
238
+ @__build_fns << block
239
+ end
240
+
241
+ def attach(&block)
242
+ @__attach_fns << block
243
+ end
244
+
245
+ def expose(&block)
246
+ @__expose_fns << block
247
+ end
248
+
249
+ IMPLICIT_HTTP_METHODS = %i(get head).freeze
250
+ IMPLICIT_HTTP_FORMATS = %i(any html).freeze
251
+
252
+ def render_implicitly?(connection)
253
+ IMPLICIT_HTTP_METHODS.include?(connection.method) && IMPLICIT_HTTP_FORMATS.include?(connection.format) &&
254
+ (Pakyow.env?(:prototype) || ((!connection.halted?) && !connection.rendered?))
255
+ end
256
+
257
+ def find_presenter_for_path(app, path)
258
+ presenter_for_path(app, String.collapse_path(path)) || app.isolated(:Presenter)
259
+ end
260
+
261
+ def presenter_for_path(app, path)
262
+ app.state(:presenter).find { |presenter|
263
+ presenter.path == path
264
+ }
265
+ end
266
+ end
267
+ end
268
+ end
269
+ end
@@ -0,0 +1,21 @@
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
@@ -0,0 +1,35 @@
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
@@ -0,0 +1,27 @@
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
@@ -0,0 +1,101 @@
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
@@ -0,0 +1,42 @@
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
@@ -0,0 +1,56 @@
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