piko-lite-box 0.0.1

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 (99) hide show
  1. checksums.yaml +7 -0
  2. data/hanami-3.0.1/CHANGELOG.md +1701 -0
  3. data/hanami-3.0.1/LICENSE +20 -0
  4. data/hanami-3.0.1/README.md +89 -0
  5. data/hanami-3.0.1/hanami.gemspec +49 -0
  6. data/hanami-3.0.1/lib/hanami/app.rb +197 -0
  7. data/hanami-3.0.1/lib/hanami/boot.rb +5 -0
  8. data/hanami-3.0.1/lib/hanami/config/actions/content_security_policy.rb +140 -0
  9. data/hanami-3.0.1/lib/hanami/config/actions/cookies.rb +57 -0
  10. data/hanami-3.0.1/lib/hanami/config/actions/sessions.rb +83 -0
  11. data/hanami-3.0.1/lib/hanami/config/actions.rb +189 -0
  12. data/hanami-3.0.1/lib/hanami/config/assets.rb +84 -0
  13. data/hanami-3.0.1/lib/hanami/config/console.rb +79 -0
  14. data/hanami-3.0.1/lib/hanami/config/db.rb +35 -0
  15. data/hanami-3.0.1/lib/hanami/config/i18n.rb +138 -0
  16. data/hanami-3.0.1/lib/hanami/config/logger.rb +207 -0
  17. data/hanami-3.0.1/lib/hanami/config/null_config.rb +17 -0
  18. data/hanami-3.0.1/lib/hanami/config/router.rb +48 -0
  19. data/hanami-3.0.1/lib/hanami/config/views.rb +103 -0
  20. data/hanami-3.0.1/lib/hanami/config.rb +564 -0
  21. data/hanami-3.0.1/lib/hanami/constants.rb +62 -0
  22. data/hanami-3.0.1/lib/hanami/env.rb +52 -0
  23. data/hanami-3.0.1/lib/hanami/errors.rb +41 -0
  24. data/hanami-3.0.1/lib/hanami/extensions/action/i18n_helper.rb +64 -0
  25. data/hanami-3.0.1/lib/hanami/extensions/action/name_inferrer.rb +34 -0
  26. data/hanami-3.0.1/lib/hanami/extensions/action/slice_configured_action.rb +190 -0
  27. data/hanami-3.0.1/lib/hanami/extensions/action.rb +147 -0
  28. data/hanami-3.0.1/lib/hanami/extensions/db/repo.rb +108 -0
  29. data/hanami-3.0.1/lib/hanami/extensions/mailer/slice_configured_mailer.rb +134 -0
  30. data/hanami-3.0.1/lib/hanami/extensions/mailer.rb +28 -0
  31. data/hanami-3.0.1/lib/hanami/extensions/operation/slice_configured_db_operation.rb +90 -0
  32. data/hanami-3.0.1/lib/hanami/extensions/operation.rb +33 -0
  33. data/hanami-3.0.1/lib/hanami/extensions/router/errors.rb +58 -0
  34. data/hanami-3.0.1/lib/hanami/extensions/view/context.rb +298 -0
  35. data/hanami-3.0.1/lib/hanami/extensions/view/part.rb +92 -0
  36. data/hanami-3.0.1/lib/hanami/extensions/view/scope.rb +36 -0
  37. data/hanami-3.0.1/lib/hanami/extensions/view/slice_configured_context.rb +73 -0
  38. data/hanami-3.0.1/lib/hanami/extensions/view/slice_configured_helpers.rb +55 -0
  39. data/hanami-3.0.1/lib/hanami/extensions/view/slice_configured_part.rb +73 -0
  40. data/hanami-3.0.1/lib/hanami/extensions/view/slice_configured_view.rb +243 -0
  41. data/hanami-3.0.1/lib/hanami/extensions/view/standard_helpers.rb +26 -0
  42. data/hanami-3.0.1/lib/hanami/extensions/view.rb +38 -0
  43. data/hanami-3.0.1/lib/hanami/extensions.rb +30 -0
  44. data/hanami-3.0.1/lib/hanami/helpers/assets_helper.rb +804 -0
  45. data/hanami-3.0.1/lib/hanami/helpers/form_helper/form_builder.rb +1389 -0
  46. data/hanami-3.0.1/lib/hanami/helpers/form_helper/values.rb +75 -0
  47. data/hanami-3.0.1/lib/hanami/helpers/form_helper.rb +213 -0
  48. data/hanami-3.0.1/lib/hanami/helpers/i18n_helper.rb +241 -0
  49. data/hanami-3.0.1/lib/hanami/logger/rack_formatter.rb +73 -0
  50. data/hanami-3.0.1/lib/hanami/logger/sql_formatter.rb +80 -0
  51. data/hanami-3.0.1/lib/hanami/logger/sql_logger.rb +48 -0
  52. data/hanami-3.0.1/lib/hanami/middleware/assets.rb +21 -0
  53. data/hanami-3.0.1/lib/hanami/middleware/content_security_policy_nonce.rb +53 -0
  54. data/hanami-3.0.1/lib/hanami/middleware/public_errors_app.rb +75 -0
  55. data/hanami-3.0.1/lib/hanami/middleware/render_errors.rb +90 -0
  56. data/hanami-3.0.1/lib/hanami/port.rb +45 -0
  57. data/hanami-3.0.1/lib/hanami/prepare.rb +5 -0
  58. data/hanami-3.0.1/lib/hanami/provider/source.rb +16 -0
  59. data/hanami-3.0.1/lib/hanami/provider_registrar.rb +28 -0
  60. data/hanami-3.0.1/lib/hanami/providers/assets.rb +28 -0
  61. data/hanami-3.0.1/lib/hanami/providers/db/adapter.rb +75 -0
  62. data/hanami-3.0.1/lib/hanami/providers/db/adapters.rb +66 -0
  63. data/hanami-3.0.1/lib/hanami/providers/db/config.rb +44 -0
  64. data/hanami-3.0.1/lib/hanami/providers/db/gateway.rb +87 -0
  65. data/hanami-3.0.1/lib/hanami/providers/db/sql_adapter.rb +100 -0
  66. data/hanami-3.0.1/lib/hanami/providers/db.rb +325 -0
  67. data/hanami-3.0.1/lib/hanami/providers/db_logging.rb +19 -0
  68. data/hanami-3.0.1/lib/hanami/providers/i18n/backend.rb +373 -0
  69. data/hanami-3.0.1/lib/hanami/providers/i18n/locale/en.yml +57 -0
  70. data/hanami-3.0.1/lib/hanami/providers/i18n.rb +114 -0
  71. data/hanami-3.0.1/lib/hanami/providers/inflector.rb +17 -0
  72. data/hanami-3.0.1/lib/hanami/providers/logger.rb +41 -0
  73. data/hanami-3.0.1/lib/hanami/providers/mailers.rb +101 -0
  74. data/hanami-3.0.1/lib/hanami/providers/rack.rb +47 -0
  75. data/hanami-3.0.1/lib/hanami/providers/relations.rb +31 -0
  76. data/hanami-3.0.1/lib/hanami/providers/routes.rb +29 -0
  77. data/hanami-3.0.1/lib/hanami/rake_tasks.rb +54 -0
  78. data/hanami-3.0.1/lib/hanami/routes.rb +146 -0
  79. data/hanami-3.0.1/lib/hanami/settings/composite_store.rb +53 -0
  80. data/hanami-3.0.1/lib/hanami/settings/env_store.rb +32 -0
  81. data/hanami-3.0.1/lib/hanami/settings.rb +234 -0
  82. data/hanami-3.0.1/lib/hanami/setup.rb +6 -0
  83. data/hanami-3.0.1/lib/hanami/slice/router.rb +280 -0
  84. data/hanami-3.0.1/lib/hanami/slice/routes_helper.rb +37 -0
  85. data/hanami-3.0.1/lib/hanami/slice/routing/middleware/stack.rb +216 -0
  86. data/hanami-3.0.1/lib/hanami/slice/routing/resolver.rb +88 -0
  87. data/hanami-3.0.1/lib/hanami/slice/view_name_inferrer.rb +63 -0
  88. data/hanami-3.0.1/lib/hanami/slice.rb +1239 -0
  89. data/hanami-3.0.1/lib/hanami/slice_configurable.rb +72 -0
  90. data/hanami-3.0.1/lib/hanami/slice_name.rb +111 -0
  91. data/hanami-3.0.1/lib/hanami/slice_registrar.rb +215 -0
  92. data/hanami-3.0.1/lib/hanami/universal_logger.rb +250 -0
  93. data/hanami-3.0.1/lib/hanami/version.rb +45 -0
  94. data/hanami-3.0.1/lib/hanami/web/rack_logger.rb +126 -0
  95. data/hanami-3.0.1/lib/hanami/web/welcome.html.erb +584 -0
  96. data/hanami-3.0.1/lib/hanami/web/welcome.rb +46 -0
  97. data/hanami-3.0.1/lib/hanami.rb +276 -0
  98. data/piko-lite-box.gemspec +11 -0
  99. metadata +137 -0
@@ -0,0 +1,804 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+ require "hanami/view"
5
+ require_relative "../constants"
6
+
7
+ module Hanami
8
+ module Helpers
9
+ # HTML assets helpers
10
+ #
11
+ # Inject these helpers in a view
12
+ #
13
+ # @since 2.1.0
14
+ #
15
+ # @see http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/HtmlHelper
16
+ module AssetsHelper
17
+ # @since 2.1.0
18
+ # @api private
19
+ NEW_LINE_SEPARATOR = "\n"
20
+
21
+ # @since 2.1.0
22
+ # @api private
23
+ WILDCARD_EXT = ".*"
24
+
25
+ # @since 2.1.0
26
+ # @api private
27
+ JAVASCRIPT_EXT = ".js"
28
+
29
+ # @since 2.1.0
30
+ # @api private
31
+ STYLESHEET_EXT = ".css"
32
+
33
+ # @since 2.1.0
34
+ # @api private
35
+ JAVASCRIPT_MIME_TYPE = "text/javascript"
36
+
37
+ # @since 2.1.0
38
+ # @api private
39
+ STYLESHEET_MIME_TYPE = "text/css"
40
+
41
+ # @since 2.1.0
42
+ # @api private
43
+ FAVICON_MIME_TYPE = "image/x-icon"
44
+
45
+ # @since 2.1.0
46
+ # @api private
47
+ STYLESHEET_REL = "stylesheet"
48
+
49
+ # @since 2.1.0
50
+ # @api private
51
+ FAVICON_REL = "shortcut icon"
52
+
53
+ # @since 2.1.0
54
+ # @api private
55
+ DEFAULT_FAVICON = "favicon.ico"
56
+
57
+ # @since 0.3.0
58
+ # @api private
59
+ CROSSORIGIN_ANONYMOUS = "anonymous"
60
+
61
+ # @since 0.3.0
62
+ # @api private
63
+ # TODO: we can drop the defined?-check and fallback once Ruby 3.3 becomes our minimum required version
64
+ ABSOLUTE_URL_MATCHER = (
65
+ defined?(URI::RFC2396_PARSER) ? URI::RFC2396_PARSER : URI::DEFAULT_PARSER
66
+ ).make_regexp
67
+
68
+ # @since 1.1.0
69
+ # @api private
70
+ QUERY_STRING_MATCHER = /\?/
71
+
72
+ include Hanami::View::Helpers::TagHelper
73
+
74
+ # Generate `script` tag for given source(s)
75
+ #
76
+ # It accepts one or more strings representing the name of the asset, if it
77
+ # comes from the application or third party gems. It also accepts strings
78
+ # representing absolute URLs in case of public CDN (eg. jQuery CDN).
79
+ #
80
+ # If the "fingerprint mode" is on, `src` is the fingerprinted
81
+ # version of the relative URL.
82
+ #
83
+ # If the "CDN mode" is on, the `src` is an absolute URL of the
84
+ # application CDN.
85
+ #
86
+ # If the "subresource integrity mode" is on, `integrity` is the
87
+ # name of the algorithm, then a hyphen, then the hash value of the file.
88
+ # If more than one algorithm is used, they"ll be separated by a space.
89
+ #
90
+ # If the Content Security Policy uses 'nonce' and the source is not
91
+ # absolute, the nonce value of the current request is automatically added
92
+ # as an attribute. You can override this with the `nonce: false` option.
93
+ # See {#content_security_policy_nonce} for more.
94
+ #
95
+ # @param sources [Array<String, #url>] one or more assets by name or absolute URL
96
+ #
97
+ # @return [Hanami::View::HTML::SafeString] the markup
98
+ #
99
+ # @raise [Hanami::Assets::MissingManifestAssetError] if `fingerprint` or
100
+ # `subresource_integrity` modes are on and the javascript file is missing
101
+ # from the manifest
102
+ #
103
+ # @since 2.1.0
104
+ #
105
+ # @see Hanami::Assets::Helpers#path
106
+ #
107
+ # @example Single Asset
108
+ #
109
+ # <%= javascript_tag "application" %>
110
+ #
111
+ # # <script src="/assets/application.js" type="text/javascript"></script>
112
+ #
113
+ # @example Multiple Assets
114
+ #
115
+ # <%= javascript_tag "application", "dashboard" %>
116
+ #
117
+ # # <script src="/assets/application.js" type="text/javascript"></script>
118
+ # # <script src="/assets/dashboard.js" type="text/javascript"></script>
119
+ #
120
+ # @example Asynchronous Execution
121
+ #
122
+ # <%= javascript_tag "application", async: true %>
123
+ #
124
+ # # <script src="/assets/application.js" type="text/javascript" async="async"></script>
125
+ #
126
+ # @example Subresource Integrity
127
+ #
128
+ # <%= javascript_tag "application" %>
129
+ #
130
+ # # <script src="/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js"
131
+ # # type="text/javascript" integrity="sha384-oqVu...Y8wC" crossorigin="anonymous"></script>
132
+ #
133
+ # @example Subresource Integrity for 3rd Party Scripts
134
+ #
135
+ # <%= javascript_tag "https://example.com/assets/example.js", integrity: "sha384-oqVu...Y8wC" %>
136
+ #
137
+ # # <script src="https://example.com/assets/example.js" type="text/javascript"
138
+ # # integrity="sha384-oqVu...Y8wC" crossorigin="anonymous"></script>
139
+ #
140
+ # @example Deferred Execution
141
+ #
142
+ # <%= javascript_tag "application", defer: true %>
143
+ #
144
+ # # <script src="/assets/application.js" type="text/javascript" defer="defer"></script>
145
+ #
146
+ # @example Disable nonce
147
+ #
148
+ # <%= javascript_tag "application", nonce: false %>
149
+ #
150
+ # @example Absolute URL
151
+ #
152
+ # <%= javascript_tag "https://code.jquery.com/jquery-2.1.4.min.js" %>
153
+ #
154
+ # # <script src="https://code.jquery.com/jquery-2.1.4.min.js" type="text/javascript"></script>
155
+ #
156
+ # @example Fingerprint Mode
157
+ #
158
+ # <%= javascript_tag "application" %>
159
+ #
160
+ # # <script src="/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js" type="text/javascript"></script>
161
+ #
162
+ # @example CDN Mode
163
+ #
164
+ # <%= javascript_tag "application" %>
165
+ #
166
+ # # <script src="https://assets.bookshelf.org/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js"
167
+ # # type="text/javascript"></script>
168
+ def javascript_tag(*sources, **options)
169
+ options = options.reject { |k, _| k.to_sym == :src }
170
+ nonce_option = options.delete(:nonce)
171
+
172
+ _safe_tags(*sources) do |source|
173
+ attributes = {
174
+ src: _typed_url(source, JAVASCRIPT_EXT),
175
+ type: JAVASCRIPT_MIME_TYPE,
176
+ nonce: _nonce(source, nonce_option)
177
+ }
178
+ attributes.merge!(options)
179
+
180
+ if _context.assets.subresource_integrity? || attributes.include?(:integrity)
181
+ attributes[:integrity] ||= _subresource_integrity_value(source, JAVASCRIPT_EXT)
182
+ attributes[:crossorigin] ||= CROSSORIGIN_ANONYMOUS
183
+ end
184
+
185
+ tag.script(**attributes).to_s
186
+ end
187
+ end
188
+
189
+ # Generate `link` tag for given source(s)
190
+ #
191
+ # It accepts one or more strings representing the name of the asset, if it
192
+ # comes from the application or third party gems. It also accepts strings
193
+ # representing absolute URLs in case of public CDN (eg. Bootstrap CDN).
194
+ #
195
+ # If the "fingerprint mode" is on, `href` is the fingerprinted
196
+ # version of the relative URL.
197
+ #
198
+ # If the "CDN mode" is on, the `href` is an absolute URL of the
199
+ # application CDN.
200
+ #
201
+ # If the "subresource integrity mode" is on, `integrity` is the
202
+ # name of the algorithm, then a hyphen, then the hashed value of the file.
203
+ # If more than one algorithm is used, they"ll be separated by a space.
204
+ #
205
+ # If the Content Security Policy uses 'nonce' and the source is not
206
+ # absolute, the nonce value of the current request is automatically added
207
+ # as an attribute. You can override this with the `nonce: false` option.
208
+ # See {#content_security_policy_nonce} for more.
209
+ #
210
+ # @param sources [Array<String, #url>] one or more assets by name or absolute URL
211
+ #
212
+ # @return [Hanami::View::HTML::SafeString] the markup
213
+ #
214
+ # @raise [Hanami::Assets::MissingManifestAssetError] if `fingerprint` or
215
+ # `subresource_integrity` modes are on and the stylesheet file is missing
216
+ # from the manifest
217
+ #
218
+ # @since 2.1.0
219
+ #
220
+ # @see Hanami::Assets::Helpers#path
221
+ #
222
+ # @example Single Asset
223
+ #
224
+ # <%= stylesheet_tag "application" %>
225
+ #
226
+ # # <link href="/assets/application.css" type="text/css" rel="stylesheet">
227
+ #
228
+ # @example Multiple Assets
229
+ #
230
+ # <%= stylesheet_tag "application", "dashboard" %>
231
+ #
232
+ # # <link href="/assets/application.css" type="text/css" rel="stylesheet">
233
+ # # <link href="/assets/dashboard.css" type="text/css" rel="stylesheet">
234
+ #
235
+ # @example Disable nonce
236
+ #
237
+ # <%= stylesheet_tag "application", nonce: false %>
238
+ #
239
+ # @example Subresource Integrity
240
+ #
241
+ # <%= stylesheet_tag "application" %>
242
+ #
243
+ # # <link href="/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.css"
244
+ # # type="text/css" integrity="sha384-oqVu...Y8wC" crossorigin="anonymous"></script>
245
+ #
246
+ # @example Subresource Integrity for 3rd Party Assets
247
+ #
248
+ # <%= stylesheet_tag "https://example.com/assets/example.css", integrity: "sha384-oqVu...Y8wC" %>
249
+ #
250
+ # # <link href="https://example.com/assets/example.css"
251
+ # # type="text/css" rel="stylesheet" integrity="sha384-oqVu...Y8wC" crossorigin="anonymous"></script>
252
+ #
253
+ # @example Absolute URL
254
+ #
255
+ # <%= stylesheet_tag "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" %>
256
+ #
257
+ # # <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"
258
+ # # type="text/css" rel="stylesheet">
259
+ #
260
+ # @example Fingerprint Mode
261
+ #
262
+ # <%= stylesheet_tag "application" %>
263
+ #
264
+ # # <link href="/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.css" type="text/css" rel="stylesheet">
265
+ #
266
+ # @example CDN Mode
267
+ #
268
+ # <%= stylesheet_tag "application" %>
269
+ #
270
+ # # <link href="https://assets.bookshelf.org/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.css"
271
+ # # type="text/css" rel="stylesheet">
272
+ def stylesheet_tag(*sources, **options)
273
+ options = options.reject { |k, _| k.to_sym == :href }
274
+ nonce_option = options.delete(:nonce)
275
+
276
+ _safe_tags(*sources) do |source|
277
+ attributes = {
278
+ href: _typed_url(source, STYLESHEET_EXT),
279
+ type: STYLESHEET_MIME_TYPE,
280
+ rel: STYLESHEET_REL,
281
+ nonce: _nonce(source, nonce_option)
282
+ }
283
+ attributes.merge!(options)
284
+
285
+ if _context.assets.subresource_integrity? || attributes.include?(:integrity)
286
+ attributes[:integrity] ||= _subresource_integrity_value(source, STYLESHEET_EXT)
287
+ attributes[:crossorigin] ||= CROSSORIGIN_ANONYMOUS
288
+ end
289
+
290
+ tag.link(**attributes).to_s
291
+ end
292
+ end
293
+
294
+ # Generate `img` tag for given source
295
+ #
296
+ # It accepts one string representing the name of the asset, if it comes
297
+ # from the application or third party gems. It also accepts strings
298
+ # representing absolute URLs in case of public CDN (eg. Bootstrap CDN).
299
+ #
300
+ # `alt` Attribute is auto generated from `src`.
301
+ # You can specify a different value, by passing the `:src` option.
302
+ #
303
+ # If the "fingerprint mode" is on, `src` is the fingerprinted
304
+ # version of the relative URL.
305
+ #
306
+ # If the "CDN mode" is on, the `src` is an absolute URL of the
307
+ # application CDN.
308
+ #
309
+ # @param source [String, #url] asset name, absolute URL, or asset object
310
+ # @param options [Hash] HTML 5 attributes
311
+ #
312
+ # @return [Hanami::View::HTML::SafeString] the markup
313
+ #
314
+ # @raise [Hanami::Assets::MissingManifestAssetError] if `fingerprint` or
315
+ # `subresource_integrity` modes are on and the image file is missing
316
+ # from the manifest
317
+ #
318
+ # @since 2.1.0
319
+ #
320
+ # @see Hanami::Assets::Helpers#path
321
+ #
322
+ # @example Basic Usage
323
+ #
324
+ # <%= image_tag "logo.png" %>
325
+ #
326
+ # # <img src="/assets/logo.png" alt="Logo">
327
+ #
328
+ # @example Custom alt Attribute
329
+ #
330
+ # <%= image_tag "logo.png", alt: "Application Logo" %>
331
+ #
332
+ # # <img src="/assets/logo.png" alt="Application Logo">
333
+ #
334
+ # @example Custom HTML Attributes
335
+ #
336
+ # <%= image_tag "logo.png", id: "logo", class: "image" %>
337
+ #
338
+ # # <img src="/assets/logo.png" alt="Logo" id="logo" class="image">
339
+ #
340
+ # @example Absolute URL
341
+ #
342
+ # <%= image_tag "https://example-cdn.com/images/logo.png" %>
343
+ #
344
+ # # <img src="https://example-cdn.com/images/logo.png" alt="Logo">
345
+ #
346
+ # @example Fingerprint Mode
347
+ #
348
+ # <%= image_tag "logo.png" %>
349
+ #
350
+ # # <img src="/assets/logo-28a6b886de2372ee3922fcaf3f78f2d8.png" alt="Logo">
351
+ #
352
+ # @example CDN Mode
353
+ #
354
+ # <%= image_tag "logo.png" %>
355
+ #
356
+ # # <img src="https://assets.bookshelf.org/assets/logo-28a6b886de2372ee3922fcaf3f78f2d8.png" alt="Logo">
357
+ def image_tag(source, options = {})
358
+ options = options.reject { |k, _| k.to_sym == :src }
359
+ attributes = {
360
+ src: asset_url(source),
361
+ alt: _context.inflector.humanize(::File.basename(source, WILDCARD_EXT))
362
+ }
363
+ attributes.merge!(options)
364
+
365
+ tag.img(**attributes)
366
+ end
367
+
368
+ # Generate `link` tag application favicon.
369
+ #
370
+ # If no argument is given, it assumes `favico.ico` from the application.
371
+ #
372
+ # It accepts one string representing the name of the asset.
373
+ #
374
+ # If the "fingerprint mode" is on, `href` is the fingerprinted version
375
+ # of the relative URL.
376
+ #
377
+ # If the "CDN mode" is on, the `href` is an absolute URL of the
378
+ # application CDN.
379
+ #
380
+ # @param source [String, #url] asset name or asset object
381
+ # @param options [Hash] HTML 5 attributes
382
+ #
383
+ # @return [Hanami::View::HTML::SafeString] the markup
384
+ #
385
+ # @raise [Hanami::Assets::MissingManifestAssetError] if `fingerprint` or
386
+ # `subresource_integrity` modes are on and the favicon is file missing
387
+ # from the manifest
388
+ #
389
+ # @since 2.1.0
390
+ #
391
+ # @see Hanami::Assets::Helpers#path
392
+ #
393
+ # @example Basic Usage
394
+ #
395
+ # <%= favicon_tag %>
396
+ #
397
+ # # <link href="/assets/favicon.ico" rel="shortcut icon" type="image/x-icon">
398
+ #
399
+ # @example Custom Path
400
+ #
401
+ # <%= favicon_tag "fav.ico" %>
402
+ #
403
+ # # <link href="/assets/fav.ico" rel="shortcut icon" type="image/x-icon">
404
+ #
405
+ # @example Custom HTML Attributes
406
+ #
407
+ # <%= favicon_tag "favicon.ico", id: "fav" %>
408
+ #
409
+ # # <link id="fav" href="/assets/favicon.ico" rel="shortcut icon" type="image/x-icon">
410
+ #
411
+ # @example Fingerprint Mode
412
+ #
413
+ # <%= favicon_tag %>
414
+ #
415
+ # # <link href="/assets/favicon-28a6b886de2372ee3922fcaf3f78f2d8.ico" rel="shortcut icon" type="image/x-icon">
416
+ #
417
+ # @example CDN Mode
418
+ #
419
+ # <%= favicon_tag %>
420
+ #
421
+ # # <link href="https://assets.bookshelf.org/assets/favicon-28a6b886de2372ee3922fcaf3f78f2d8.ico"
422
+ # rel="shortcut icon" type="image/x-icon">
423
+ def favicon_tag(source = DEFAULT_FAVICON, options = {})
424
+ options = options.reject { |k, _| k.to_sym == :href }
425
+
426
+ attributes = {
427
+ href: asset_url(source),
428
+ rel: FAVICON_REL,
429
+ type: FAVICON_MIME_TYPE
430
+ }
431
+ attributes.merge!(options)
432
+
433
+ tag.link(**attributes)
434
+ end
435
+
436
+ # Generate `video` tag for given source
437
+ #
438
+ # It accepts one string representing the name of the asset, if it comes
439
+ # from the application or third party gems. It also accepts strings
440
+ # representing absolute URLs in case of public CDN (eg. Bootstrap CDN).
441
+ #
442
+ # Alternatively, it accepts a block that allows to specify one or more
443
+ # sources via the `source` tag.
444
+ #
445
+ # If the "fingerprint mode" is on, `src` is the fingerprinted
446
+ # version of the relative URL.
447
+ #
448
+ # If the "CDN mode" is on, the `src` is an absolute URL of the
449
+ # application CDN.
450
+ #
451
+ # @param source [String, #url] asset name, absolute URL or asset object
452
+ # @param options [Hash] HTML 5 attributes
453
+ #
454
+ # @return [Hanami::View::HTML::SafeString] the markup
455
+ #
456
+ # @raise [Hanami::Assets::MissingManifestAssetError] if `fingerprint` or
457
+ # `subresource_integrity` modes are on and the video file is missing
458
+ # from the manifest
459
+ #
460
+ # @raise [ArgumentError] if source isn"t specified both as argument or
461
+ # tag inside the given block
462
+ #
463
+ # @since 2.1.0
464
+ #
465
+ # @see Hanami::Assets::Helpers#path
466
+ #
467
+ # @example Basic Usage
468
+ #
469
+ # <%= video_tag "movie.mp4" %>
470
+ #
471
+ # # <video src="/assets/movie.mp4"></video>
472
+ #
473
+ # @example Absolute URL
474
+ #
475
+ # <%= video_tag "https://example-cdn.com/assets/movie.mp4" %>
476
+ #
477
+ # # <video src="https://example-cdn.com/assets/movie.mp4"></video>
478
+ #
479
+ # @example Custom HTML Attributes
480
+ #
481
+ # <%= video_tag("movie.mp4", autoplay: true, controls: true) %>
482
+ #
483
+ # # <video src="/assets/movie.mp4" autoplay="autoplay" controls="controls"></video>
484
+ #
485
+ # @example Fallback Content
486
+ #
487
+ # <%=
488
+ # video("movie.mp4") do
489
+ # "Your browser does not support the video tag"
490
+ # end
491
+ # %>
492
+ #
493
+ # # <video src="/assets/movie.mp4">
494
+ # # Your browser does not support the video tag
495
+ # # </video>
496
+ #
497
+ # @example Tracks
498
+ #
499
+ # <%=
500
+ # video("movie.mp4") do
501
+ # tag.track(kind: "captions", src: asset_url("movie.en.vtt"),
502
+ # srclang: "en", label: "English")
503
+ # end
504
+ # %>
505
+ #
506
+ # # <video src="/assets/movie.mp4">
507
+ # # <track kind="captions" src="/assets/movie.en.vtt" srclang="en" label="English">
508
+ # # </video>
509
+ #
510
+ # @example Without Any Argument
511
+ #
512
+ # <%= video_tag %>
513
+ #
514
+ # # ArgumentError
515
+ #
516
+ # @example Without src And Without Block
517
+ #
518
+ # <%= video_tag(content: true) %>
519
+ #
520
+ # # ArgumentError
521
+ #
522
+ # @example Fingerprint Mode
523
+ #
524
+ # <%= video_tag "movie.mp4" %>
525
+ #
526
+ # # <video src="/assets/movie-28a6b886de2372ee3922fcaf3f78f2d8.mp4"></video>
527
+ #
528
+ # @example CDN Mode
529
+ #
530
+ # <%= video_tag "movie.mp4" %>
531
+ #
532
+ # # <video src="https://assets.bookshelf.org/assets/movie-28a6b886de2372ee3922fcaf3f78f2d8.mp4"></video>
533
+ def video_tag(source = nil, options = {}, &blk)
534
+ options = _source_options(source, options, &blk)
535
+ tag.video(**options, &blk)
536
+ end
537
+
538
+ # Generate `audio` tag for given source
539
+ #
540
+ # It accepts one string representing the name of the asset, if it comes
541
+ # from the application or third party gems. It also accepts strings
542
+ # representing absolute URLs in case of public CDN (eg. Bootstrap CDN).
543
+ #
544
+ # Alternatively, it accepts a block that allows to specify one or more
545
+ # sources via the `source` tag.
546
+ #
547
+ # If the "fingerprint mode" is on, `src` is the fingerprinted
548
+ # version of the relative URL.
549
+ #
550
+ # If the "CDN mode" is on, the `src` is an absolute URL of the
551
+ # application CDN.
552
+ #
553
+ # @param source [String, #url] asset name, absolute URL or asset object
554
+ # @param options [Hash] HTML 5 attributes
555
+ #
556
+ # @return [Hanami::View::HTML::SafeString] the markup
557
+ #
558
+ # @raise [Hanami::Assets::MissingManifestAssetError] if `fingerprint` or
559
+ # `subresource_integrity` modes are on and the audio file is missing
560
+ # from the manifest
561
+ #
562
+ # @raise [ArgumentError] if source isn"t specified both as argument or
563
+ # tag inside the given block
564
+ #
565
+ # @since 2.1.0
566
+ #
567
+ # @see Hanami::Assets::Helpers#path
568
+ #
569
+ # @example Basic Usage
570
+ #
571
+ # <%= audio_tag "song.ogg" %>
572
+ #
573
+ # # <audio src="/assets/song.ogg"></audio>
574
+ #
575
+ # @example Absolute URL
576
+ #
577
+ # <%= audio_tag "https://example-cdn.com/assets/song.ogg" %>
578
+ #
579
+ # # <audio src="https://example-cdn.com/assets/song.ogg"></audio>
580
+ #
581
+ # @example Custom HTML Attributes
582
+ #
583
+ # <%= audio_tag("song.ogg", autoplay: true, controls: true) %>
584
+ #
585
+ # # <audio src="/assets/song.ogg" autoplay="autoplay" controls="controls"></audio>
586
+ #
587
+ # @example Fallback Content
588
+ #
589
+ # <%=
590
+ # audio("song.ogg") do
591
+ # "Your browser does not support the audio tag"
592
+ # end
593
+ # %>
594
+ #
595
+ # # <audio src="/assets/song.ogg">
596
+ # # Your browser does not support the audio tag
597
+ # # </audio>
598
+ #
599
+ # @example Tracks
600
+ #
601
+ # <%=
602
+ # audio("song.ogg") do
603
+ # tag.track(kind: "captions", src: asset_url("song.pt-BR.vtt"),
604
+ # srclang: "pt-BR", label: "Portuguese")
605
+ # end
606
+ # %>
607
+ #
608
+ # # <audio src="/assets/song.ogg">
609
+ # # <track kind="captions" src="/assets/song.pt-BR.vtt" srclang="pt-BR" label="Portuguese">
610
+ # # </audio>
611
+ #
612
+ # @example Without Any Argument
613
+ #
614
+ # <%= audio_tag %>
615
+ #
616
+ # # ArgumentError
617
+ #
618
+ # @example Without src And Without Block
619
+ #
620
+ # <%= audio_tag(controls: true) %>
621
+ #
622
+ # # ArgumentError
623
+ #
624
+ # @example Fingerprint Mode
625
+ #
626
+ # <%= audio_tag "song.ogg" %>
627
+ #
628
+ # # <audio src="/assets/song-28a6b886de2372ee3922fcaf3f78f2d8.ogg"></audio>
629
+ #
630
+ # @example CDN Mode
631
+ #
632
+ # <%= audio_tag "song.ogg" %>
633
+ #
634
+ # # <audio src="https://assets.bookshelf.org/assets/song-28a6b886de2372ee3922fcaf3f78f2d8.ogg"></audio>
635
+ def audio_tag(source = nil, options = {}, &blk)
636
+ options = _source_options(source, options, &blk)
637
+ tag.audio(**options, &blk)
638
+ end
639
+
640
+ # It generates the relative or absolute URL for the given asset.
641
+ # It automatically decides if it has to use the relative or absolute
642
+ # depending on the configuration and current environment.
643
+ #
644
+ # Absolute URLs are returned as they are.
645
+ #
646
+ # It can be the name of the asset, coming from the sources or third party
647
+ # gems.
648
+ #
649
+ # If Fingerprint mode is on, it returns the fingerprinted path of the source
650
+ #
651
+ # If CDN mode is on, it returns the absolute URL of the asset.
652
+ #
653
+ # @param source [String, #url] the asset name or asset object
654
+ #
655
+ # @return [String] the asset path
656
+ #
657
+ # @raise [Hanami::Assets::MissingManifestAssetError] if `fingerprint` or
658
+ # `subresource_integrity` modes are on and the asset is missing
659
+ # from the manifest
660
+ #
661
+ # @since 2.1.0
662
+ #
663
+ # @example Basic Usage
664
+ #
665
+ # <%= asset_url "application.js" %>
666
+ #
667
+ # # "/assets/application.js"
668
+ #
669
+ # @example Alias
670
+ #
671
+ # <%= asset_url "application.js" %>
672
+ #
673
+ # # "/assets/application.js"
674
+ #
675
+ # @example Absolute URL
676
+ #
677
+ # <%= asset_url "https://code.jquery.com/jquery-2.1.4.min.js" %>
678
+ #
679
+ # # "https://code.jquery.com/jquery-2.1.4.min.js"
680
+ #
681
+ # @example Fingerprint Mode
682
+ #
683
+ # <%= asset_url "application.js" %>
684
+ #
685
+ # # "/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js"
686
+ #
687
+ # @example CDN Mode
688
+ #
689
+ # <%= asset_url "application.js" %>
690
+ #
691
+ # # "https://assets.bookshelf.org/assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js"
692
+ def asset_url(source)
693
+ return source.url if source.respond_to?(:url)
694
+ return source if _absolute_url?(source)
695
+
696
+ _context.assets[source].url
697
+ end
698
+
699
+ # Random per request nonce value for Content Security Policy (CSP) rules.
700
+ #
701
+ # If the `Hanami::Middleware::ContentSecurityPolicyNonce` middleware is
702
+ # in use, this helper returns the nonce value for the current request
703
+ # or `nil` otherwise.
704
+ #
705
+ # For this policy to work in the browser, you have to add the `'nonce'`
706
+ # placeholder to the script and/or style source policy rule. It will be
707
+ # substituted by the current nonce value like `'nonce-A12OggyZ'.
708
+ #
709
+ # @return [String, nil] nonce value of the current request
710
+ #
711
+ # @since 2.3.0
712
+ #
713
+ # @example App configuration
714
+ #
715
+ # config.middleware.use Hanami::Middleware::ContentSecurityPolicyNonce
716
+ # config.actions.content_security_policy[:script_src] = "'self' 'nonce'"
717
+ # config.actions.content_security_policy[:style_src] = "'self' 'nonce'"
718
+ #
719
+ # @example View helper
720
+ #
721
+ # <script nonce="<%= content_security_policy_nonce %>">
722
+ def content_security_policy_nonce
723
+ return unless _context.request?
724
+
725
+ _context.request.env[CONTENT_SECURITY_POLICY_NONCE_REQUEST_KEY]
726
+ end
727
+
728
+ private
729
+
730
+ # @since 2.1.0
731
+ # @api private
732
+ def _safe_tags(*sources, &blk)
733
+ ::Hanami::View::HTML::SafeString.new(
734
+ sources.map(&blk).join(NEW_LINE_SEPARATOR)
735
+ )
736
+ end
737
+
738
+ # @since 2.1.0
739
+ # @api private
740
+ def _typed_url(source, ext)
741
+ source = "#{source}#{ext}" if source.is_a?(String) && _append_extension?(source, ext)
742
+ asset_url(source)
743
+ end
744
+
745
+ # @api private
746
+ def _subresource_integrity_value(source, ext)
747
+ return if _absolute_url?(source)
748
+
749
+ source = "#{source}#{ext}" unless /#{Regexp.escape(ext)}\z/.match?(source)
750
+ _context.assets[source].sri
751
+ end
752
+
753
+ # @since 2.1.0
754
+ # @api private
755
+ def _absolute_url?(source)
756
+ ABSOLUTE_URL_MATCHER.match?(source.respond_to?(:url) ? source.url : source)
757
+ end
758
+
759
+ # @since 1.2.0
760
+ # @api private
761
+ def _crossorigin?(source)
762
+ return false unless _absolute_url?(source)
763
+
764
+ _context.assets.crossorigin?(source)
765
+ end
766
+
767
+ # @since 2.3.0
768
+ # @api private
769
+ def _nonce(source, nonce_option)
770
+ if nonce_option == false
771
+ nil
772
+ elsif nonce_option == true || (nonce_option.nil? && !_absolute_url?(source))
773
+ content_security_policy_nonce
774
+ else
775
+ nonce_option
776
+ end
777
+ end
778
+
779
+ # @since 2.1.0
780
+ # @api private
781
+ def _source_options(src, options, &blk)
782
+ options ||= {}
783
+
784
+ if src.respond_to?(:to_hash)
785
+ options = src.to_hash
786
+ elsif src
787
+ options[:src] = asset_url(src)
788
+ end
789
+
790
+ if !options[:src] && !blk
791
+ raise ArgumentError.new("You should provide a source via `src` option or with a `source` HTML tag")
792
+ end
793
+
794
+ options
795
+ end
796
+
797
+ # @since 1.1.0
798
+ # @api private
799
+ def _append_extension?(source, ext)
800
+ source !~ QUERY_STRING_MATCHER && source !~ /#{Regexp.escape(ext)}\z/
801
+ end
802
+ end
803
+ end
804
+ end