rest_framework 0.9.4 → 0.9.6

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +130 -0
  4. data/VERSION +1 -1
  5. data/app/views/layouts/rest_framework.html.erb +9 -183
  6. data/app/views/rest_framework/_breadcrumbs.html.erb +27 -0
  7. data/app/views/rest_framework/_head.html.erb +348 -190
  8. data/app/views/rest_framework/_header.html.erb +15 -0
  9. data/app/views/rest_framework/_heading.html.erb +10 -0
  10. data/app/views/rest_framework/_payloads.html.erb +36 -0
  11. data/app/views/rest_framework/_request_metadata.html.erb +16 -0
  12. data/app/views/rest_framework/_routes_and_forms.html.erb +52 -0
  13. data/app/views/rest_framework/head/_external.html.erb +7 -2
  14. data/app/views/rest_framework/header/_mode.html.erb +14 -0
  15. data/app/views/rest_framework/heading/_actions.html.erb +9 -0
  16. data/app/views/rest_framework/{_routes.html.erb → routes_and_forms/_routes.html.erb} +2 -2
  17. data/lib/rest_framework/controller_mixins/base.rb +11 -12
  18. data/lib/rest_framework/engine.rb +5 -3
  19. data/lib/rest_framework/filters/ransack.rb +6 -6
  20. data/lib/rest_framework/version.rb +0 -6
  21. data/lib/rest_framework.rb +25 -13
  22. data/vendor/assets/javascripts/rest_framework/external.min.js +1256 -0
  23. data/vendor/assets/stylesheets/rest_framework/{bootstrap-icons.css → external.min.css} +415 -1
  24. data/vendor/assets/stylesheets/rest_framework/{highlight-a11y-dark.css → highlight-a11y-dark.min.css} +1 -1
  25. data/vendor/assets/stylesheets/rest_framework/{highlight-a11y-light.css → highlight-a11y-light.min.css} +1 -1
  26. metadata +18 -35
  27. data/README.md +0 -1
  28. data/app/views/rest_framework/head/_shared.html +0 -164
  29. data/docs/CNAME +0 -1
  30. data/docs/Gemfile +0 -5
  31. data/docs/Gemfile.lock +0 -264
  32. data/docs/_config.yml +0 -19
  33. data/docs/_guide/1_routers.md +0 -110
  34. data/docs/_guide/2_controllers.md +0 -342
  35. data/docs/_guide/3_serializers.md +0 -60
  36. data/docs/_guide/4_filtering_and_ordering.md +0 -41
  37. data/docs/_guide/5_pagination.md +0 -21
  38. data/docs/_includes/anchor_headings.html +0 -144
  39. data/docs/_includes/external.html +0 -9
  40. data/docs/_includes/head.html +0 -155
  41. data/docs/_includes/header.html +0 -58
  42. data/docs/_includes/shared.html +0 -164
  43. data/docs/_layouts/default.html +0 -11
  44. data/docs/assets/images/favicon.ico +0 -0
  45. data/docs/index.md +0 -133
  46. data/vendor/assets/javascripts/rest_framework/bootstrap.js +0 -7
  47. data/vendor/assets/javascripts/rest_framework/highlight-json.js +0 -7
  48. data/vendor/assets/javascripts/rest_framework/highlight-xml.js +0 -29
  49. data/vendor/assets/javascripts/rest_framework/highlight.js +0 -1202
  50. data/vendor/assets/javascripts/rest_framework/neatjson.js +0 -8
  51. data/vendor/assets/javascripts/rest_framework/trix.js +0 -6
  52. data/vendor/assets/stylesheets/rest_framework/bootstrap.css +0 -6
  53. data/vendor/assets/stylesheets/rest_framework/trix.css +0 -410
  54. /data/app/views/rest_framework/{_html_form.html.erb → routes_and_forms/_html_form.html.erb} +0 -0
  55. /data/app/views/rest_framework/{_raw_form.html.erb → routes_and_forms/_raw_form.html.erb} +0 -0
  56. /data/app/views/rest_framework/{_route.html.erb → routes_and_forms/routes/_route.html.erb} +0 -0
@@ -1,342 +0,0 @@
1
- ---
2
- layout: default
3
- title: Controllers
4
- position: 2
5
- slug: controllers
6
- ---
7
- # Controllers
8
-
9
- This is the core of the REST Framework. Generally speaking, projects already have an existing
10
- controller inheritance hierarchy, so we want developers to be able to maintain that project
11
- structure while leveraging the power of the REST Framework. Also, different controllers which
12
- inherit from the same parent often need different REST Framework functionality and behavior. For
13
- these reasons, REST Framework provides the controller functionality as modules that you mix into
14
- your controllers.
15
-
16
- Here is a graph of the controller mixins (all exist within the `RESTFramework` namespace), with
17
- supplementary mixins shown as well:
18
-
19
- ```shell
20
- BaseControllerMixin
21
- BaseModelControllerMixin (includes BaseControllerMixin)
22
- ModelControllerMixin (includes BaseModelControllerMixin)
23
- ├── ListModelMixin
24
- ├── ShowModelMixin
25
- ├── CreateModelMixin
26
- ├── UpdateModelMixin
27
- └── DestroyModelMixin
28
- ReadOnlyModelControllerMixin (includes BaseModelControllerMixin)
29
- ├── ListModelMixin
30
- └── ShowModelMixin
31
- BulkModelControllerMixin (includes ModelControllerMixin)
32
- ├── BulkCreateModelMixin
33
- ├── BulkUpdateModelMixin
34
- └── BulkDestroyModelMixin
35
- ```
36
-
37
- All API controllers should include at least one of these top-level controller mixins, and can
38
- include any of the supplementary mixins to add additional functionality. For example, if you want to
39
- permit create but not update or destroy, then you could do this:
40
-
41
- ```ruby
42
- class Api::MoviesController < ApiController
43
- include RESTFramework::BaseModelControllerMixin
44
- include RESTFramework::CreateModelMixin
45
- end
46
- ```
47
-
48
- ## BaseControllerMixin
49
-
50
- To transform a controller into the simplest possible RESTful controller, you can include
51
- `BaseControllerMixin`, which provides a simple `root` action so it can be used at the API root.
52
-
53
- ```ruby
54
- class ApiController < ApplicationController
55
- include RESTFramework::BaseControllerMixin
56
- end
57
- ```
58
-
59
- ### Response Rendering
60
-
61
- A fundamental feature that REST Framework provides is the ability to render a browsable API. This
62
- allows developers to discover and interact with the API's functionality, while also providing faster
63
- and more lightweight JSON/XML formats for consumption by the systems these developers create.
64
-
65
- The `api_response` method is how this is accomplished. The first argument is the data to be
66
- rendered (often an array or hash), and keyword arguments can be provided to customize the response
67
- (e.g., setting the HTTP status code). Using this method instead of the classic Rails helpers, such
68
- as `render`, will automatically provide the browsable API as well as JSON/XML rendering.
69
-
70
- Here is a simple example of rendering a hash with a `message` key:
71
-
72
- ```ruby
73
- class ApiController < ApplicationController
74
- include RESTFramework::BaseControllerMixin
75
- self.extra_actions = {test: :get}
76
-
77
- def test
78
- api_response({message: "Test successful!"})
79
- end
80
- end
81
- ```
82
-
83
- ### Routing Extra Actions
84
-
85
- The `extra_actions` property defines extra actions on the controller to be routed. It is a hash of
86
- `endpoint -> method(s)` (where `method(s)` can be a method symbol or an array of method symbols).
87
-
88
- ```ruby
89
- class ApiController < ApplicationController
90
- include RESTFramework::BaseControllerMixin
91
- self.extra_actions = {test: :get}
92
-
93
- def test
94
- api_response({message: "Test successful!"})
95
- end
96
- end
97
- ```
98
-
99
- Or with multiple methods:
100
-
101
- ```ruby
102
- class ApiController < ApplicationController
103
- include RESTFramework::BaseControllerMixin
104
- self.extra_actions = {test: [:get, :post]}
105
-
106
- def test
107
- api_response({message: "Test successful!"})
108
- end
109
- end
110
- ```
111
-
112
- If your action conflicts with a builtin method, then you can also override the path:
113
-
114
- ```ruby
115
- class ApiController < ApplicationController
116
- include RESTFramework::BaseControllerMixin
117
-
118
- # This will route `test_action` to `/test`, in case there is already a `test` method that cannot
119
- # be overridden.
120
- self.extra_actions = {test_action: {path: :test, methods: :get}}
121
-
122
- def test_action
123
- api_response({message: "Test successful!"})
124
- end
125
- end
126
- ```
127
-
128
- ## ModelControllerMixin
129
-
130
- `ModelControllerMixin` assists with providing the standard model CRUD (create, read, update,
131
- destroy) for your controller. This is the most commonly used mixin since it provides default
132
- behavior for models which matches Rails' resourceful routing.
133
-
134
- ```ruby
135
- class Api::MoviesController < ApiController
136
- include RESTFramework::ModelControllerMixin
137
- end
138
- ```
139
-
140
- By default, all columns and associations are included in the controller's `fields`, which can be
141
- helpful when developing an administrative API. For most APIs, however, `fields` should be explicitly
142
- defined. See [Specifying the Fields](#specifying-the-fields) for more information.
143
-
144
- ### Defining the Model
145
-
146
- The `model` property allows you to define the model if it is not derivable from the controller name.
147
-
148
- ```ruby
149
- class Api::CoolMoviesController < ApiController
150
- include RESTFramework::ModelControllerMixin
151
-
152
- self.model = Movie
153
- end
154
- ```
155
-
156
- ### Specifying the Recordset
157
-
158
- The `recordset` property allows you to define the set of records this API should be limited to. If
159
- you need to change the recordset based on properties of the request, then you can override the
160
- `get_recordset` method.
161
-
162
- ```ruby
163
- class Api::CoolMoviesController < ApiController
164
- include RESTFramework::ModelControllerMixin
165
-
166
- self.recordset = Movie.where(cool: true).order({id: :asc})
167
- end
168
- ```
169
-
170
- If you override `get_recordset`, you should ensure you also set the `model` property if it's not
171
- derivable from the controller name.
172
-
173
- ```ruby
174
- class Api::CoolMoviesController < ApiController
175
- include RESTFramework::ModelControllerMixin
176
-
177
- self.model = Movie
178
-
179
- def get_recordset
180
- return Movie.where(cool: true).order({id: :asc})
181
- end
182
- end
183
- ```
184
-
185
- ### Specifying Extra Member Actions
186
-
187
- While `extra_actions` (and the synonym `extra_collection_actions`) allows you to define additional
188
- actions on the controller, `extra_member_actions` allows you to define additional member actions on
189
- the controller, which require a record ID to be provided as a path param.
190
-
191
- ```ruby
192
- class Api::MoviesController < ApiController
193
- include RESTFramework::ModelControllerMixin
194
-
195
- self.extra_member_actions = {disable: :patch}
196
-
197
- def disable
198
- # REST Framework will rescue ActiveRecord::RecordNotFound.
199
- @record = self.get_record
200
-
201
- # REST Framework will rescue ActiveRecord::RecordInvalid or ActiveRecord::RecordNotSaved.
202
- @record.update!(enabled: false)
203
-
204
- return api_response(@record)
205
- end
206
- end
207
- ```
208
-
209
- ### Specifying the Fields
210
-
211
- The `fields` property defines the fields available for things like serialization and allowed
212
- parameters in body or query params. If `fields` is not set, then it will default to all columns and
213
- associations, which is helpful when developing an administrative API. For most APIs, however,
214
- `fields` should be explicitly defined.
215
-
216
- While you can also define per-request fields by overriding `get_fields`, you should also define a
217
- set of fields on the controller which is used for things like the `OPTIONS` metadata.
218
-
219
- ```ruby
220
- class Api::MoviesController < ApiController
221
- include RESTFramework::ModelControllerMixin
222
-
223
- self.fields = [:id, :name]
224
- end
225
- ```
226
-
227
- You can also mutate the default set of fields by removing existing columns/associations, and even
228
- adding methods. The framework will automatically detect if the given field is a column, association,
229
- or method, and will handle it appropriately.
230
-
231
- ```ruby
232
- class Api::MoviesController < ApiController
233
- include RESTFramework::ModelControllerMixin
234
-
235
- # This will include all columns, all associations except `owners`, and the `is_featured` method.
236
- self.fields = {
237
- exclude: [:owners],
238
- include: [:is_featured],
239
- }
240
- end
241
- ```
242
-
243
- ### Specifying the Serializer Configuration
244
-
245
- For most cases, the default serializer configuration is sufficient, and can be modified by adjusting
246
- the `fields` property on the controller. However, there are cases where you may want to define a
247
- serializer configuation, such as when you want to customize nested associations, or if you want to
248
- remove certain fields (like methods) when serializing multiple records.
249
-
250
- The property `native_serializer_config` defines the serializer configuration if you are using the
251
- default serializer. You can also specify serializers for singular/plural data.
252
-
253
- ```ruby
254
- class Api::MoviesController < ApiController
255
- include RESTFramework::ModelControllerMixin
256
-
257
- self.native_serializer_config = {
258
- only: [:id, :name],
259
- methods: [:active, :some_expensive_computed_property],
260
- include: {cast_members: { only: [:id, :name], methods: [:net_worth] }},
261
- }
262
-
263
- # Or you could configure a default and a plural serializer:
264
- self.native_serializer_config = {
265
- only: [:id, :name],
266
- methods: [:active, :some_expensive_computed_property],
267
- include: {cast_members: { only: [:id, :name], methods: [:net_worth] }},
268
- }
269
- self.native_serializer_plural_config = {
270
- only: [:id, :name],
271
- methods: [:active],
272
- include: {cast_members: { only: [:id, :name], methods: [:net_worth] }},
273
- }
274
-
275
- # Or you could configure a default and a singular serializer:
276
- self.native_serializer_config = {
277
- only: [:id, :name],
278
- methods: [:active],
279
- include: {cast_members: { only: [:id, :name], methods: [:net_worth] }},
280
- }
281
- self.native_serializer_singular_config = {
282
- only: [:id, :name],
283
- methods: [:active, :some_expensive_computed_property],
284
- include: {cast_members: { only: [:id, :name], methods: [:net_worth] }},
285
- }
286
- end
287
- ```
288
-
289
- ### Specifying Allowed Parameters
290
-
291
- The `allowed_parameters` property defines the allowed parameters for create/update actions. The
292
- framework uses strong parameters to execute this filtering.
293
-
294
- ```ruby
295
- class Api::MoviesController < ApiController
296
- include RESTFramework::ModelControllerMixin
297
-
298
- self.allowed_parameters = [:name]
299
- end
300
- ```
301
-
302
- If you want different allowed parameters for create/update actions, or if you need stronger control
303
- over what request body parameters get passed to create/update, then you can also override the
304
- `get_create_params` or `get_update_params` methods.
305
-
306
- ### Controlling Create Behavior
307
-
308
- The `create_from_recordset` attribute (`true` by default) is a boolean to control the behavior in
309
- the `create` action. If it is disabled, records will not be created from the filtered recordset, but
310
- rather will be created directly from the model interface.
311
-
312
- For example, if this is your controller:
313
-
314
- ```ruby
315
- class Api::CoolMoviesController < ApiController
316
- include RESTFramework::ModelControllerMixin
317
-
318
- # Notice that `cool` is read-only with the following two configurations:
319
- self.fields = [:id, :name]
320
- self.native_serializer_config = {only: [:id, :name, :cool]}
321
-
322
- # New records created from this controller will have `cool` set to `true`.
323
- def get_recordset
324
- return Movie.where(cool: true)
325
- end
326
- end
327
- ```
328
-
329
- Then if you hit the `create` action with the payload `{name: "Superman"}`, it will also set `cool`
330
- to `true` on the new record, because that property is inherited from the recordset.
331
-
332
- ## ReadOnlyModelControllerMixin
333
-
334
- `ReadOnlyModelControllerMixin` only enables list/show actions.
335
-
336
- ```ruby
337
- class Api::ReadOnlyMoviesController < ApiController
338
- include RESTFramework::ReadOnlyModelControllerMixin
339
-
340
- self.model = Movie
341
- end
342
- ```
@@ -1,60 +0,0 @@
1
- ---
2
- layout: default
3
- title: Serializers
4
- position: 3
5
- slug: serializers
6
- ---
7
- # Serializers
8
-
9
- Serializers allow complex objects to be converted to Ruby primitives (`Array` and `Hash` objects),
10
- which can then be converted to JSON or XML.
11
-
12
- ## NativeSerializer
13
-
14
- This serializer uses Rails' native `ActiveModel::Serialization.serializable_hash` method to convert
15
- records/recordsets to Ruby primitives (`Array` and `Hash`).
16
-
17
- This is the default serializer, you can configure it using the controller class attributes
18
- `native_serializer_config` (or `native_serializer_singular_config` /
19
- `native_serializer_plural_config`):
20
-
21
- ```ruby
22
- class Api::MoviesController < ApiController
23
- include RESTFramework::ModelControllerMixin
24
-
25
- self.native_serializer_config = {
26
- only: [:id, :name],
27
- methods: [:active, :some_expensive_computed_property],
28
- include: {cast_members: { only: [:id, :name] }},
29
- }
30
- end
31
- ```
32
-
33
- If you want to re-use a serializer, then you can define it as a standalone class, and you can even
34
- nest them. You can also define separate configurations for serializing individual records vs
35
- recordsets using `singular_config` and `plural_config`, respectively.
36
-
37
- ```ruby
38
- class Api::MoviesController < ApiController
39
- include RESTFramework::ModelControllerMixin
40
-
41
- class CastMemberSerializer < RESTFramework::NativeSerializer
42
- self.config = { only: [:id, :name], methods: [:net_worth] }
43
- self.plural_config = { only: [:id, :name] }
44
- end
45
-
46
- class MovieSerializer < RESTFramework::NativeSerializer
47
- self.config = {
48
- only: [:id, :name],
49
- include: {cast_members: CastMemberSerializer.new(many: true)},
50
- }
51
- self.singular_config = {
52
- only: [:id, :name],
53
- methods: [:active, :some_expensive_computed_property],
54
- include: {cast_members: CastMemberSerializer.new(many: true)},
55
- }
56
- end
57
-
58
- self.serializer_class = MovieSerializer
59
- end
60
- ```
@@ -1,41 +0,0 @@
1
- ---
2
- layout: default
3
- title: Filtering / Ordering
4
- position: 4
5
- slug: filtering-and-ordering
6
- ---
7
- # Filtering and Ordering
8
-
9
- While you can control the recordset that the API exposes, sometimes you want the user to control the
10
- records they want to see, or the order of those records. Both filtering and ordering are
11
- accomplished through a generic mechanism called "filters". To control the filter backends that a
12
- controller uses, you can either adjust the `filter_backends` controller attribute or you can
13
- override the `get_filter_backends()` method.
14
-
15
- ## ModelQueryFilter
16
-
17
- This filter provides basic user-controllable filtering of the recordset using query params. For
18
- example, a request to `/api/movies?cool=true` would return movies where `cool` is `true`.
19
-
20
- If you include `ModelControllerMixin` into your controller, `ModelQueryFilter` is included in the filter
21
- backends by default.
22
-
23
- ## ModelOrderingFilter
24
-
25
- This filter provides basic user-controllable ordering of the recordset using query params. For
26
- example, a request to `/api/movies?ordering=name` could order the movies by `name` rather than `id`.
27
- `ordering=-name` would invert the ordering. You can also order with multiple parameters with a comma
28
- separated list, like: `ordering=director,-name`.
29
-
30
- If you include `ModelControllerMixin` into your controller, `ModelOrderingFilter` is included in the
31
- filter backends by default. You can use `ordering_fields` to controller which fields are allowed to
32
- be ordered by. To adjust the parameter that the user passes, adjust `ordering_query_param`; the
33
- default is `"ordering"`.
34
-
35
- ## ModelSearchFilter
36
-
37
- This filter provides basic user-controllable searching of the recordset using the `search` query
38
- parameter (adjustable with the `search_query_param`). For example, a request to
39
- `/api/movies?search=Star` could return movies where `name` contains the string `Star`. The search is
40
- performed against the `search_fields` attribute, but if that is not set, then the search is
41
- performed against a configurable default set of fields (`search_columns`).
@@ -1,21 +0,0 @@
1
- ---
2
- layout: default
3
- title: Pagination
4
- position: 5
5
- slug: pagination
6
- ---
7
- # Pagination
8
-
9
- For large result sets, you may need to provide pagination. You can configure the paginator for a
10
- controller by setting the `paginator_class` to the paginator you want to use.
11
-
12
- ## PageNumberPaginator
13
-
14
- This is a simple paginator which splits a recordset into pages and allows the user to select the
15
- desired page using the `page` query parameter (e.g., `/api/movies?page=3`). To adjust this query
16
- parameter, set the `page_query_param` controller attribute.
17
-
18
- By default the user can adjust the page size using the `page_size` query param. To adjust this query
19
- parameter, you can set the `page_size_query_param` controller attribute, or set it to `nil` to
20
- disable this functionality. By default, there is no upper limit to the size of a page a user can
21
- request. To enforce an upper limit, set the `max_page_size` controller attribute.
@@ -1,144 +0,0 @@
1
- {% capture headingsWorkspace %}
2
- {% comment %}
3
- Copyright (c) 2018 Vladimir "allejo" Jimenez
4
-
5
- Permission is hereby granted, free of charge, to any person
6
- obtaining a copy of this software and associated documentation
7
- files (the "Software"), to deal in the Software without
8
- restriction, including without limitation the rights to use,
9
- copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- copies of the Software, and to permit persons to whom the
11
- Software is furnished to do so, subject to the following
12
- conditions:
13
-
14
- The above copyright notice and this permission notice shall be
15
- included in all copies or substantial portions of the Software.
16
-
17
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
- OTHER DEALINGS IN THE SOFTWARE.
25
- {% endcomment %}
26
- {% comment %}
27
- Version 1.0.7
28
- https://github.com/allejo/jekyll-anchor-headings
29
-
30
- "Be the pull request you wish to see in the world." ~Ben Balter
31
-
32
- Usage:
33
- {% include anchor_headings.html html=content anchorBody="#" %}
34
-
35
- Parameters:
36
- * html (string) - the HTML of compiled markdown generated by kramdown in Jekyll
37
-
38
- Optional Parameters:
39
- * beforeHeading (bool) : false - Set to true if the anchor should be placed _before_ the heading's content
40
- * anchorAttrs (string) : '' - Any custom HTML attributes that will be added to the `<a>` tag; you may NOT use `href`, `class` or `title`;
41
- the `%heading%` and `%html_id%` placeholders are available
42
- * anchorBody (string) : '' - The content that will be placed inside the anchor; the `%heading%` placeholder is available
43
- * anchorClass (string) : '' - The class(es) that will be used for each anchor. Separate multiple classes with a space
44
- * anchorTitle (string) : '' - The `title` attribute that will be used for anchors
45
- * h_min (int) : 1 - The minimum header level to build an anchor for; any header lower than this value will be ignored
46
- * h_max (int) : 6 - The maximum header level to build an anchor for; any header greater than this value will be ignored
47
- * bodyPrefix (string) : '' - Anything that should be inserted inside of the heading tag _before_ its anchor and content
48
- * bodySuffix (string) : '' - Anything that should be inserted inside of the heading tag _after_ its anchor and content
49
-
50
- Output:
51
- The original HTML with the addition of anchors inside of all of the h1-h6 headings.
52
- {% endcomment %}
53
-
54
- {% assign minHeader = include.h_min | default: 1 %}
55
- {% assign maxHeader = include.h_max | default: 6 %}
56
- {% assign beforeHeading = include.beforeHeading %}
57
- {% assign nodes = include.html | split: '<h' %}
58
-
59
- {% capture edited_headings %}{% endcapture %}
60
-
61
- {% for _node in nodes %}
62
- {% capture node %}{{ _node | strip }}{% endcapture %}
63
-
64
- {% if node == "" %}
65
- {% continue %}
66
- {% endif %}
67
-
68
- {% assign nextChar = node | replace: '"', '' | strip | slice: 0, 1 %}
69
- {% assign headerLevel = nextChar | times: 1 %}
70
-
71
- <!-- If the level is cast to 0, it means it's not a h1-h6 tag, so let's see if we need to fix it -->
72
- {% if headerLevel == 0 %}
73
- <!-- Split up the node based on closing angle brackets and get the first one. -->
74
- {% assign firstChunk = node | split: '>' | first %}
75
-
76
- <!-- If the first chunk does NOT contain a '<', that means we've broken another HTML tag that starts with 'h' -->
77
- {% unless firstChunk contains '<' %}
78
- {% capture node %}<h{{ node }}{% endcapture %}
79
- {% endunless %}
80
-
81
- {% capture edited_headings %}{{ edited_headings }}{{ node }}{% endcapture %}
82
- {% continue %}
83
- {% endif %}
84
-
85
- {% capture _closingTag %}</h{{ headerLevel }}>{% endcapture %}
86
- {% assign _workspace = node | split: _closingTag %}
87
- {% assign _idWorkspace = _workspace[0] | split: 'id="' %}
88
- {% assign _idWorkspace = _idWorkspace[1] | split: '"' %}
89
- {% assign html_id = _idWorkspace[0] %}
90
-
91
- {% capture _hAttrToStrip %}{{ _workspace[0] | split: '>' | first }}>{% endcapture %}
92
- {% assign header = _workspace[0] | replace: _hAttrToStrip, '' %}
93
-
94
- <!-- Build the anchor to inject for our heading -->
95
- {% capture anchor %}{% endcapture %}
96
-
97
- {% if html_id and headerLevel >= minHeader and headerLevel <= maxHeader %}
98
- {% capture anchor %}href="#{{ html_id }}"{% endcapture %}
99
-
100
- {% if include.anchorClass %}
101
- {% capture anchor %}{{ anchor }} class="{{ include.anchorClass }}"{% endcapture %}
102
- {% endif %}
103
-
104
- {% if include.anchorTitle %}
105
- {% capture anchor %}{{ anchor }} title="{{ include.anchorTitle | replace: '%heading%', header }}"{% endcapture %}
106
- {% endif %}
107
-
108
- {% if include.anchorAttrs %}
109
- {% capture anchor %}{{ anchor }} {{ include.anchorAttrs | replace: '%heading%', header | replace: '%html_id%', html_id }}{% endcapture %}
110
- {% endif %}
111
-
112
- {% capture anchor %}<a {{ anchor }}>{{ include.anchorBody | replace: '%heading%', header | default: '' }}</a>{% endcapture %}
113
-
114
- <!-- In order to prevent adding extra space after a heading, we'll let the 'anchor' value contain it -->
115
- {% if beforeHeading %}
116
- {% capture anchor %}{{ anchor }} {% endcapture %}
117
- {% else %}
118
- {% capture anchor %} {{ anchor }}{% endcapture %}
119
- {% endif %}
120
- {% endif %}
121
-
122
- {% capture new_heading %}
123
- <h{{ _hAttrToStrip }}
124
- {{ include.bodyPrefix }}
125
- {% if beforeHeading %}
126
- {{ anchor }}{{ header }}
127
- {% else %}
128
- {{ header }}{{ anchor }}
129
- {% endif %}
130
- {{ include.bodySuffix }}
131
- </h{{ headerLevel }}>
132
- {% endcapture %}
133
-
134
- <!--
135
- If we have content after the `</hX>` tag, then we'll want to append that here so we don't lost any content.
136
- -->
137
- {% assign chunkCount = _workspace | size %}
138
- {% if chunkCount > 1 %}
139
- {% capture new_heading %}{{ new_heading }}{{ _workspace | last }}{% endcapture %}
140
- {% endif %}
141
-
142
- {% capture edited_headings %}{{ edited_headings }}{{ new_heading }}{% endcapture %}
143
- {% endfor %}
144
- {% endcapture %}{% assign headingsWorkspace = '' %}{{ edited_headings | strip }}
@@ -1,9 +0,0 @@
1
- <!-- AUTOGENERATED -->
2
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha2/dist/css/bootstrap.min.css" integrity="sha384-aFq/bzH65dt+w6FI2ooMVUpc+21e0SRygnTpmBvdBgSdnuTN7QbdgL+OapgHtvPp" crossorigin="anonymous">
3
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha2/dist/js/bootstrap.bundle.min.js" integrity="sha384-qKXV1j0HvMUeCBQ+QVp7JcfGl760yU08IQ+GpUo5hlbpg51QRiuqHAJz8+BrxE/N" crossorigin="anonymous" referrerpolicy="no-referrer" defer="defer"></script>
4
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.4/font/bootstrap-icons.min.css" crossorigin="anonymous">
5
- <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js" integrity="sha512-bgHRAiTjGrzHzLyKOnpFvaEpGzJet3z4tZnXGjpsCcqOnAH6VGUx9frc5bcIhKTVLEiCO6vEhNAgx5jtLUYrfA==" crossorigin="anonymous" referrerpolicy="no-referrer" defer="defer"></script>
6
- <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/json.min.js" integrity="sha512-0xYvyncS9OLE7GOpNBZFnwyh9+bq4HVgk4yVVYI678xRvE22ASicF1v6fZ1UiST+M6pn17MzFZdvVCI3jTHSyw==" crossorigin="anonymous" referrerpolicy="no-referrer" defer="defer"></script>
7
- <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/xml.min.js" integrity="sha512-5zBcw+OKRkaNyvUEPlTSfYylVzgpi7KpncY36b0gRudfxIYIH0q0kl2j26uCUB3YBRM6ytQQEZSgRg+ZlBTmdA==" crossorigin="anonymous" referrerpolicy="no-referrer" defer="defer"></script>
8
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/a11y-dark.min.css" integrity="sha512-Vj6gPCk8EZlqnoveEyuGyYaWZ1+jyjMPg8g4shwyyNlRQl6d3L9At02ZHQr5K6s5duZl/+YKMnM3/8pDhoUphg==" crossorigin="anonymous" class="rrf-dark-mode">
9
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/a11y-light.min.css" integrity="sha512-WDk6RzwygsN9KecRHAfm9HTN87LQjqdygDmkHSJxVkVI7ErCZ8ZWxP6T8RvBujY1n2/E4Ac+bn2ChXnp5rnnHA==" crossorigin="anonymous" class="rrf-light-mode">