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.
- checksums.yaml +5 -5
- data/{pakyow-presenter/CHANGELOG.md → CHANGELOG.md} +0 -5
- data/LICENSE +4 -0
- data/{pakyow-presenter/README.md → README.md} +1 -2
- data/lib/pakyow/generators/presenter/presenter_generator.rb +28 -0
- data/lib/pakyow/generators/presenter/templates/presenter.rb.tt +2 -0
- data/lib/pakyow/plugin/helpers/rendering.rb +19 -0
- data/lib/pakyow/presenter/actions/auto_render.rb +15 -0
- data/lib/pakyow/presenter/attributes/attribute.rb +22 -0
- data/lib/pakyow/presenter/attributes/boolean.rb +24 -0
- data/lib/pakyow/presenter/attributes/hash.rb +89 -0
- data/lib/pakyow/presenter/attributes/set.rb +61 -0
- data/lib/pakyow/presenter/attributes/string.rb +38 -0
- data/lib/pakyow/presenter/attributes.rb +126 -0
- data/lib/pakyow/presenter/behavior/config.rb +29 -0
- data/lib/pakyow/presenter/behavior/error_rendering.rb +124 -0
- data/lib/pakyow/presenter/behavior/exposures.rb +29 -0
- data/lib/pakyow/presenter/behavior/implicit_rendering.rb +21 -0
- data/lib/pakyow/presenter/behavior/initializing.rb +37 -0
- data/lib/pakyow/presenter/behavior/modes.rb +117 -0
- data/lib/pakyow/presenter/behavior/versions.rb +71 -0
- data/lib/pakyow/presenter/behavior/watching.rb +21 -0
- data/lib/pakyow/presenter/binder.rb +115 -0
- data/lib/pakyow/presenter/binding_parts.rb +64 -0
- data/lib/pakyow/presenter/component.rb +74 -0
- data/lib/pakyow/presenter/composers/component.rb +78 -0
- data/lib/pakyow/presenter/composers/view.rb +73 -0
- data/lib/pakyow/presenter/errors.rb +63 -0
- data/lib/pakyow/presenter/framework.rb +203 -0
- data/lib/pakyow/presenter/front_matter_parser.rb +42 -0
- data/lib/pakyow/presenter/helpers/rendering.rb +18 -0
- data/lib/pakyow/presenter/presentable.rb +28 -0
- data/lib/pakyow/presenter/presentable_error.rb +19 -0
- data/lib/pakyow/presenter/presenter.rb +766 -0
- data/lib/pakyow/presenter/presenters/endpoint.rb +158 -0
- data/lib/pakyow/presenter/presenters/form.rb +522 -0
- data/lib/pakyow/presenter/processor.rb +61 -0
- data/lib/pakyow/presenter/renderable.rb +28 -0
- data/lib/pakyow/presenter/renderer.rb +269 -0
- data/lib/pakyow/presenter/rendering/actions/cleanup_prototype_nodes.rb +21 -0
- data/lib/pakyow/presenter/rendering/actions/cleanup_unbound_bindings.rb +35 -0
- data/lib/pakyow/presenter/rendering/actions/create_template_nodes.rb +27 -0
- data/lib/pakyow/presenter/rendering/actions/insert_prototype_bar.rb +101 -0
- data/lib/pakyow/presenter/rendering/actions/install_authenticity.rb +42 -0
- data/lib/pakyow/presenter/rendering/actions/place_in_mode.rb +56 -0
- data/lib/pakyow/presenter/rendering/actions/render_components.rb +279 -0
- data/lib/pakyow/presenter/rendering/actions/set_page_title.rb +35 -0
- data/lib/pakyow/presenter/rendering/actions/setup_endpoints.rb +62 -0
- data/lib/pakyow/presenter/rendering/actions/setup_forms.rb +174 -0
- data/lib/pakyow/presenter/significant_nodes.rb +309 -0
- data/lib/pakyow/presenter/templates.rb +229 -0
- data/lib/pakyow/presenter/versioned_view.rb +209 -0
- data/lib/pakyow/presenter/view.rb +586 -0
- data/lib/pakyow/presenter/views/form.rb +58 -0
- data/lib/pakyow/presenter/views/layout.rb +32 -0
- data/lib/pakyow/presenter/views/page.rb +72 -0
- data/lib/pakyow/presenter/views/partial.rb +28 -0
- data/lib/pakyow/presenter.rb +33 -0
- data/lib/pakyow/views/errors/layouts/development_error.html +102 -0
- data/lib/pakyow/views/errors/layouts/production_error.html +27 -0
- data/lib/pakyow/views/errors/pages/404.html +12 -0
- data/lib/pakyow/views/errors/pages/500.html +12 -0
- data/lib/pakyow/views/errors/pages/development/500.html +39 -0
- data/lib/string_doc/attributes.rb +109 -0
- data/lib/string_doc/meta_attributes.rb +48 -0
- data/lib/string_doc/meta_node.rb +328 -0
- data/lib/string_doc/node.rb +377 -0
- data/lib/string_doc.rb +642 -0
- metadata +95 -75
- data/pakyow-presenter/LICENSE +0 -20
- data/pakyow-presenter/lib/pakyow/presenter/attributes.rb +0 -228
- data/pakyow-presenter/lib/pakyow/presenter/base.rb +0 -38
- data/pakyow-presenter/lib/pakyow/presenter/binder.rb +0 -116
- data/pakyow-presenter/lib/pakyow/presenter/binder_set.rb +0 -94
- data/pakyow-presenter/lib/pakyow/presenter/binding_eval.rb +0 -37
- data/pakyow-presenter/lib/pakyow/presenter/config/presenter.rb +0 -42
- data/pakyow-presenter/lib/pakyow/presenter/container.rb +0 -6
- data/pakyow-presenter/lib/pakyow/presenter/doc_helpers.rb +0 -17
- data/pakyow-presenter/lib/pakyow/presenter/exceptions.rb +0 -11
- data/pakyow-presenter/lib/pakyow/presenter/ext/app.rb +0 -33
- data/pakyow-presenter/lib/pakyow/presenter/ext/call_context.rb +0 -28
- data/pakyow-presenter/lib/pakyow/presenter/helpers.rb +0 -46
- data/pakyow-presenter/lib/pakyow/presenter/page.rb +0 -110
- data/pakyow-presenter/lib/pakyow/presenter/partial.rb +0 -6
- data/pakyow-presenter/lib/pakyow/presenter/presenter.rb +0 -232
- data/pakyow-presenter/lib/pakyow/presenter/string_doc.rb +0 -380
- data/pakyow-presenter/lib/pakyow/presenter/string_doc_parser.rb +0 -144
- data/pakyow-presenter/lib/pakyow/presenter/string_doc_renderer.rb +0 -18
- data/pakyow-presenter/lib/pakyow/presenter/template.rb +0 -51
- data/pakyow-presenter/lib/pakyow/presenter/view.rb +0 -541
- data/pakyow-presenter/lib/pakyow/presenter/view_collection.rb +0 -330
- data/pakyow-presenter/lib/pakyow/presenter/view_composer.rb +0 -237
- data/pakyow-presenter/lib/pakyow/presenter/view_context.rb +0 -111
- data/pakyow-presenter/lib/pakyow/presenter/view_store.rb +0 -262
- data/pakyow-presenter/lib/pakyow/presenter/view_store_loader.rb +0 -43
- data/pakyow-presenter/lib/pakyow/presenter/view_version.rb +0 -113
- data/pakyow-presenter/lib/pakyow/presenter.rb +0 -8
- data/pakyow-presenter/lib/pakyow/views/errors/404.erb +0 -26
- data/pakyow-presenter/lib/pakyow/views/errors/500.erb +0 -23
- 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
|