recourse 4.4.4 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/app/views/layouts/recourses.html.erb +4 -0
- data/config/locales/recourse.en.yml +1 -0
- data/lib/recourse/controllers.rb +31 -4
- data/lib/recourse/helpers/bookmarks.rb +3 -1
- data/lib/recourse/helpers/formats.rb +11 -5
- data/lib/recourse/routes/nested.rb +4 -3
- data/lib/recourse/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 10cc1a031240c0430a970cea2dc0c79460e3b6dfe131ce6e8a854aed364a485c
|
|
4
|
+
data.tar.gz: 631f40d0bc652b90cdaf960864ea5c47f7baa55ea1808b4a366a3d26ff021220
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 43892125e4332125787621108a81ccea1de70de89c66c6cdf686d68f54d7d8eda0c7251e964e2a74df8c5a9492ec8d26b8cf99c5443fa246bc91aebe0de8b13d
|
|
7
|
+
data.tar.gz: be7fa5f7c3853ba0ccecb21f5b290ab0ac38f00f1165d541ab670ff35decd71f9df154cc09836ecc7432153d3035dad9ccd290e449cba08d36976fbd579c9965
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
For more information about changelogs, check [Keep a Changelog](http://keepachangelog.com) and
|
|
6
6
|
[Vandamme](http://tech-angels.github.io/vandamme).
|
|
7
7
|
|
|
8
|
+
## 4.5.0 - 2026-09-08
|
|
9
|
+
|
|
10
|
+
* [Fix] A row with a bookmark square is as tall as a row without one: the square no longer claims a button's minimum height
|
|
11
|
+
|
|
12
|
+
* [Feature] The arrow after a web address opens it in a new tab, while the words still open it in this one
|
|
13
|
+
|
|
14
|
+
* [Fix] A production rake task boots without Rails 8.2 warning that Action Controller and Active Record were loaded early
|
|
15
|
+
|
|
16
|
+
`recourses` defined each missing controller as the routes drew, which loaded the host's
|
|
17
|
+
`RecoursesController` and everything above it, and asked a nested name for its model the
|
|
18
|
+
same way. A boot that will not eager load — a `db:migrate` on release — draws its routes
|
|
19
|
+
before it is done, and Rails 8.2 logs a warning for every component loaded then. The
|
|
20
|
+
controller now waits for the app's first request or job, and the model is looked up as a
|
|
21
|
+
constant, without loading it.
|
|
22
|
+
|
|
8
23
|
## 4.4.4 - 2026-09-08
|
|
9
24
|
|
|
10
25
|
* [Fix] On a phone the search form keeps its place beside the breadcrumb once a filter is picked
|
|
@@ -265,6 +265,10 @@
|
|
|
265
265
|
next to one, so it takes the line's height and not `.btn`'s own minimum —
|
|
266
266
|
which would leave the row under every table taller than the words in it. */
|
|
267
267
|
.recourse-limit { min-height: 0; }
|
|
268
|
+
/* The bookmark square is an icon in a row of text, not a control in a form, so it
|
|
269
|
+
takes the line's height too: `.btn`'s minimum made every row with one taller
|
|
270
|
+
than the rows without. */
|
|
271
|
+
.recourse-bookmark { min-height: 0; }
|
|
268
272
|
/* Stacked, each control is a row of its own rather than a fragment of one:
|
|
269
273
|
there is no second control beside it to share the line with. */
|
|
270
274
|
@media (width < 768px) {
|
data/lib/recourse/controllers.rb
CHANGED
|
@@ -1,16 +1,43 @@
|
|
|
1
1
|
module Recourse
|
|
2
2
|
# Defines the controller classes a host app has not written for itself.
|
|
3
3
|
module Controllers
|
|
4
|
+
@held = []
|
|
5
|
+
@lock = Mutex.new
|
|
6
|
+
|
|
4
7
|
# Creates a controller for the named resource unless the host app has one. The
|
|
5
8
|
# name arrives with whatever namespace it was drawn in — `admin/contacts` — so
|
|
6
|
-
# the constant lands where Rails will look for it.
|
|
7
|
-
|
|
9
|
+
# the constant lands where Rails will look for it. A block names the superclass,
|
|
10
|
+
# `RecoursesController` by default, and is called only once the class is made.
|
|
11
|
+
def self.define_missing(path, &base)
|
|
8
12
|
class_name = "#{path.camelize}Controller"
|
|
9
13
|
# const_defined? is true for a Zeitwerk autoload, so files on disk count too.
|
|
10
14
|
return if Object.const_defined? class_name
|
|
11
15
|
|
|
12
|
-
|
|
13
|
-
|
|
16
|
+
booting? ? hold(class_name, base) : define(class_name, base)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Makes the controllers held back while the app booted. The executor runs this
|
|
20
|
+
# ahead of the app's first request or job, once every class may be loaded.
|
|
21
|
+
def self.define_held
|
|
22
|
+
@lock.synchronize { define(*@held.shift) until @held.empty? }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private_class_method def self.define(class_name, base)
|
|
26
|
+
superclass = base ? base.call : RecoursesController
|
|
27
|
+
namespace(class_name.deconstantize).const_set class_name.demodulize, Class.new(superclass)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Rails 8.2 warns when Action Controller is loaded during the boot of an app that
|
|
31
|
+
# will not eager load — a rake task's, which draws its routes before it is done
|
|
32
|
+
# and never dispatches to a controller — so the class waits for the first run.
|
|
33
|
+
private_class_method def self.booting?
|
|
34
|
+
app = Rails.application
|
|
35
|
+
app.present? && !app.config.eager_load && !app.initialized?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private_class_method def self.hold(class_name, base)
|
|
39
|
+
Rails.application.executor.to_run { Controllers.define_held } if @held.empty?
|
|
40
|
+
@held << [class_name, base]
|
|
14
41
|
end
|
|
15
42
|
|
|
16
43
|
# The module a namespaced controller belongs in, made where the host has none of
|
|
@@ -50,13 +50,15 @@ module Recourse
|
|
|
50
50
|
|
|
51
51
|
# Kept or not, one square either way: the same path with the verb reversed, so
|
|
52
52
|
# the button toggles by flipping the method Rails already wrote into the form.
|
|
53
|
+
# `recourse-bookmark` takes back the height `.btn` claims, so the row stays as
|
|
54
|
+
# tall as one with no square in it.
|
|
53
55
|
def bookmark_button(record)
|
|
54
56
|
kept = bookmarked_ids.include? record.id
|
|
55
57
|
label = t "recourse.#{kept ? 'unbookmark' : 'bookmark'}"
|
|
56
58
|
|
|
57
59
|
button_to bookmark_icon(kept, label), bookmark_url(record),
|
|
58
60
|
method: kept ? :delete : :post, form_class: 'd-inline-block',
|
|
59
|
-
class: 'btn btn-sm btn-link p-0 border-0 lh-1',
|
|
61
|
+
class: 'btn btn-sm btn-link p-0 border-0 lh-1 recourse-bookmark',
|
|
60
62
|
**bookmark_data(kept, label)
|
|
61
63
|
end
|
|
62
64
|
|
|
@@ -79,15 +79,21 @@ module Recourse
|
|
|
79
79
|
value.is_a?(String) && value.match?(WEB_URL)
|
|
80
80
|
end
|
|
81
81
|
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
# a
|
|
82
|
+
# The words lead where the value points, in this tab, the way any link does; the
|
|
83
|
+
# arrow after them — Bootstrap's icon link, stepping under the cursor — opens the
|
|
84
|
+
# same address in a new tab. Either reads as the host, and an ellipsis where the
|
|
85
|
+
# address goes further: a path is how a machine finds the page, and the href has it.
|
|
85
86
|
def url_link(value)
|
|
86
87
|
host, rest = value.match(WEB_URL).captures
|
|
87
88
|
said = rest.delete_suffix('/').empty? ? host : "#{host}/…"
|
|
88
89
|
|
|
89
|
-
tag.a
|
|
90
|
-
|
|
90
|
+
safe_join [tag.a(said, href: value), new_tab_arrow(value)], ' '
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def new_tab_arrow(value)
|
|
94
|
+
tag.a icon_tag(:point_right), href: value, target: '_blank', rel: 'noopener',
|
|
95
|
+
class: 'icon-link icon-link-hover',
|
|
96
|
+
aria: { label: t('recourse.new_tab') }
|
|
91
97
|
end
|
|
92
98
|
end
|
|
93
99
|
end
|
|
@@ -18,8 +18,9 @@ module Recourse
|
|
|
18
18
|
# Whether this resource has rows to address one at a time. A bookmark names one
|
|
19
19
|
# row, which means nothing for a name with no class behind it at all — and one was
|
|
20
20
|
# drawn anyway, at `/placeholders/:placeholder_id/bookmark`, where nothing linked
|
|
21
|
-
# to it and anything reaching it raised.
|
|
22
|
-
|
|
21
|
+
# to it and anything reaching it raised. Asked of the constant rather than the
|
|
22
|
+
# class: loading a model while the routes draw is what Rails 8.2 warns about.
|
|
23
|
+
def addressable_rows? = Object.const_defined? Recourse.model_name(parent_resource.name)
|
|
23
24
|
|
|
24
25
|
# The row a table's bookmark square writes: one record kept by whoever is looking,
|
|
25
26
|
# at `/places/5/bookmark`. Deliberately not recorded through `Recourse.nest` — it
|
|
@@ -28,7 +29,7 @@ module Recourse
|
|
|
28
29
|
# since the gem drew it: one segment under the resource, always.
|
|
29
30
|
def draw_bookmark
|
|
30
31
|
path = [current_module, 'bookmarks'].compact.join '/'
|
|
31
|
-
Controllers.define_missing
|
|
32
|
+
Controllers.define_missing(path) { ::BookmarksController }
|
|
32
33
|
resource :bookmark, only: %i[create destroy]
|
|
33
34
|
end
|
|
34
35
|
end
|
data/lib/recourse/version.rb
CHANGED