bible270 1.1.3 → 1.1.5
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 +25 -3
- data/README.md +4 -5
- data/Rakefile +1 -1
- data/app/controllers/bible270/admin_controller.rb +30 -0
- data/app/controllers/bible270/days_controller.rb +1 -1
- data/app/helpers/bible270/plan_helper.rb +15 -3
- data/app/models/bible270/comment.rb +1 -1
- data/app/models/bible270/reader.rb +6 -8
- data/app/models/bible270/setting.rb +32 -2
- data/app/views/bible270/admin/index.html.erb +47 -7
- data/app/views/bible270/days/_reading.html.erb +6 -6
- data/app/views/bible270/days/index.html.erb +1 -1
- data/app/views/bible270/shared/_interaction_ui.html.erb +29 -0
- data/app/views/bible270/shared/_progress.html.erb +8 -3
- data/app/views/bible270/shared/_styles.html.erb +1 -1
- data/config/routes.rb +2 -0
- data/lib/bible270/configuration.rb +1 -3
- data/lib/bible270/plan.rb +4 -4
- data/lib/bible270/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: 1a655ad0a130cd6a4106374efb885fa76856b7f93c7fc05284062648a330125e
|
|
4
|
+
data.tar.gz: d23e6b7180c152f1b452e6eac5db9523f0e8cb7683ee50492fc8bbdc00d271cb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 791373f6597dde62c9a6ce8eaab3251868f4b19bbf24615fec46613ebab7e918e4f90e3eb8f318ed85502b1a769eb71c7290adb4973f17d3400eb411d2664202
|
|
7
|
+
data.tar.gz: 71b588c2a184a1939ee9c7c79dce661fcc017e2199ea732e334ebc2ba49412ec3bfcd029880e4cdffe64724c21d33a5e157c7f9dc886feda1d583f9b56e64db4
|
data/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,24 @@ All notable changes to bible270. Format follows [Keep a Changelog](https://keepa
|
|
|
4
4
|
|
|
5
5
|
## Unreleased Changes
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- reuse one dedicated browser tab for Bible Gateway and Blue Letter Bible Scripture links instead of opening an unlimited series of tabs
|
|
10
|
+
|
|
11
|
+
### Removed
|
|
12
|
+
|
|
13
|
+
- remove the unused `passage_url_builder` configuration hook; Bible Gateway and Blue Letter Bible are now the intentionally fixed passage providers
|
|
14
|
+
|
|
15
|
+
**[Full Changelog](https://github.com/avonderluft/bible270/compare/v1.1.3...main)**
|
|
16
|
+
|
|
17
|
+
## [1.1.3] - 2026-08-23
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- align Profile reminder choices with the recommended 15-minute scheduler interval while preserving existing off-quarter preferences
|
|
22
|
+
- document concrete host cron and Docker Compose setup, output logging, verification, and one-scheduler-per-database guidance
|
|
23
|
+
|
|
24
|
+
**[Full Changelog](https://github.com/avonderluft/bible270/compare/v1.1.2...v1.1.3)**
|
|
8
25
|
|
|
9
26
|
## [1.1.2] - 2026-08-22
|
|
10
27
|
|
|
@@ -12,13 +29,17 @@ All notable changes to bible270. Format follows [Keep a Changelog](https://keepa
|
|
|
12
29
|
|
|
13
30
|
- include complete 1.1.0 and 1.1.1 release history in the packaged changelog
|
|
14
31
|
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- make the mobile navigation menu toggle reliably on iOS Safari with an explicit accessible button, synchronized `aria-expanded` state, and controlled menu visibility
|
|
35
|
+
|
|
15
36
|
**[Full Changelog](https://github.com/avonderluft/bible270/compare/v1.1.1...v1.1.2)**
|
|
16
37
|
|
|
17
38
|
## [1.1.1] - 2026-08-22
|
|
18
39
|
|
|
19
|
-
###
|
|
40
|
+
### Changed
|
|
20
41
|
|
|
21
|
-
-
|
|
42
|
+
- replace the first custom mobile-menu handler with native `details` disclosure behavior
|
|
22
43
|
|
|
23
44
|
**[Full Changelog](https://github.com/avonderluft/bible270/compare/v1.1.0...v1.1.1)**
|
|
24
45
|
|
|
@@ -508,6 +529,7 @@ This is the initial public release.
|
|
|
508
529
|
|
|
509
530
|
* Email sign-in requires working Action Mailer delivery in the host application. Set `config.mailer_from`; delivery is inline by default, or set `email_sign_in_deliver_later` when a queue backend is available.
|
|
510
531
|
|
|
532
|
+
[1.1.3]: https://github.com/avonderluft/bible270/releases/tag/v1.1.3
|
|
511
533
|
[1.1.2]: https://github.com/avonderluft/bible270/releases/tag/v1.1.2
|
|
512
534
|
[1.1.1]: https://github.com/avonderluft/bible270/releases/tag/v1.1.1
|
|
513
535
|
[1.1.0]: https://github.com/avonderluft/bible270/releases/tag/v1.1.0
|
data/README.md
CHANGED
|
@@ -318,7 +318,7 @@ config.allow_reader_start_date = true # allow personal per-reader calendars
|
|
|
318
318
|
| a date | false | Everyone is pinned to the community date; stored individual dates are ignored |
|
|
319
319
|
| nil | false | Fully undated — no calendar anywhere |
|
|
320
320
|
|
|
321
|
-
Dated plans show each day's date with a **Today** badge and a "Go to today" link.
|
|
321
|
+
Dated plans show each day's date with a **Today** badge and a "Go to today" link. `config.start_date` is the deploy-time default; an administrator may override the current run's shared date from the Admin panel without a deploy, or reset it to the configured value. The shared-date change immediately re-maps calendar dates, **Today**, and reminders for readers following the shared calendar. Administrators may also re-map an individual reader's calendar. Check-offs and reflections remain keyed to day numbers, so nothing in their history moves.
|
|
322
322
|
|
|
323
323
|
Date helpers are pure functions, usable anywhere:
|
|
324
324
|
|
|
@@ -415,9 +415,6 @@ Bible270.configure do |config|
|
|
|
415
415
|
config.after_sign_out_path = nil
|
|
416
416
|
|
|
417
417
|
config.bible_version = "NKJV"
|
|
418
|
-
config.passage_url_builder = ->(reference, version) {
|
|
419
|
-
"https://www.biblegateway.com/passage/?search=#{URI.encode_www_form_component(reference)}&version=#{version}"
|
|
420
|
-
}
|
|
421
418
|
end
|
|
422
419
|
```
|
|
423
420
|
### Footer
|
|
@@ -460,7 +457,9 @@ It's emitted by the engine's layout, so if you point `config.layout` at your own
|
|
|
460
457
|
References link to Bible Gateway by default. Readers choose Bible Gateway or Blue Letter Bible from
|
|
461
458
|
their profile, and an admin can set the same source for any reader. The `HEB/GRK` option always uses
|
|
462
459
|
Blue Letter Bible: WLC for Old Testament, Psalms, and Proverbs readings, and mGNT for New Testament
|
|
463
|
-
readings.
|
|
460
|
+
readings. Scripture links share one dedicated browser tab so moving among the day's passages does not
|
|
461
|
+
leave a trail of open tabs; Ctrl-click, Cmd-click, middle-click, and the browser's context menu still
|
|
462
|
+
open additional tabs when a reader wants to compare passages.
|
|
464
463
|
|
|
465
464
|
## With ComfortableMediaSurfer
|
|
466
465
|
|
data/Rakefile
CHANGED
|
@@ -160,7 +160,7 @@ namespace :test do
|
|
|
160
160
|
Rake::Task['test:serial'].enhance(['test:prepare_serial'])
|
|
161
161
|
|
|
162
162
|
task :parallel do
|
|
163
|
-
workers = ENV.fetch('PARALLEL_WORKERS', '
|
|
163
|
+
workers = ENV.fetch('PARALLEL_WORKERS', '6')
|
|
164
164
|
FileUtils.rm_rf('coverage')
|
|
165
165
|
env = {
|
|
166
166
|
'PARALLEL_COVERAGE' => 'true',
|
|
@@ -28,10 +28,40 @@ module Bible270
|
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
+
def update_run_start
|
|
32
|
+
if Setting.set_run_start_date!(params[:start_date])
|
|
33
|
+
date = Setting.run_start_date
|
|
34
|
+
redirect_to admin_path, notice: "Current run start date changed to #{date.strftime('%B %-d, %Y')}."
|
|
35
|
+
else
|
|
36
|
+
redirect_to admin_path, alert: 'Choose a valid start date.'
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def reset_run_start
|
|
41
|
+
Setting.clear_run_start_date!
|
|
42
|
+
date = Setting.run_start_date
|
|
43
|
+
notice = if date
|
|
44
|
+
"Current run now uses the configured start date, #{date.strftime('%B %-d, %Y')}."
|
|
45
|
+
else
|
|
46
|
+
'Current run now uses the configured undated schedule.'
|
|
47
|
+
end
|
|
48
|
+
redirect_to admin_path, notice: notice
|
|
49
|
+
end
|
|
50
|
+
|
|
31
51
|
def index
|
|
32
52
|
@enrollment_closed = Setting.enrollment_closed?
|
|
33
53
|
@enrollment_closed_at = Setting.enrollment_closed_at
|
|
34
54
|
@readers = Reader.all.to_a.sort_by(&:sort_name)
|
|
55
|
+
@run_start_date = Setting.run_start_date
|
|
56
|
+
@configured_start_date = Bible270.config.start_date
|
|
57
|
+
@run_start_date_overridden = Setting.run_start_date_overridden?
|
|
58
|
+
if Bible270.config.allow_reader_start_date
|
|
59
|
+
@shared_calendar_readers = @readers.count { |reader| reader.started_on.nil? }
|
|
60
|
+
@personal_calendar_readers = @readers.size - @shared_calendar_readers
|
|
61
|
+
else
|
|
62
|
+
@shared_calendar_readers = @readers.size
|
|
63
|
+
@personal_calendar_readers = 0
|
|
64
|
+
end
|
|
35
65
|
counts = Checkoff.group(:reader_id, :day).count
|
|
36
66
|
@days_completed = Hash.new(0)
|
|
37
67
|
counts.each { |(rid, day), n| @days_completed[rid] += 1 if n >= Plan.total_parts(day) }
|
|
@@ -8,7 +8,7 @@ module Bible270
|
|
|
8
8
|
@start_day = current_reader&.current_day || 1
|
|
9
9
|
# nil outside the plan's window, so no "Go to today" before it begins
|
|
10
10
|
@today_day = current_reader&.today_day
|
|
11
|
-
@community_start_date =
|
|
11
|
+
@community_start_date = Setting.run_start_date
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def show
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
module Bible270
|
|
4
4
|
module PlanHelper
|
|
5
|
+
PASSAGE_LINK_TARGET = 'bible270_scripture'
|
|
6
|
+
|
|
5
7
|
def b270_track(track)
|
|
6
8
|
Plan::TRACKS.fetch(track.to_s)
|
|
7
9
|
end
|
|
@@ -117,7 +119,18 @@ module Bible270
|
|
|
117
119
|
return Translations.passage_url(reference, selected_version, blue_letter: true)
|
|
118
120
|
end
|
|
119
121
|
|
|
120
|
-
|
|
122
|
+
Translations.passage_url(reference, selected_version)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# The named target and noopener are the secure no-JavaScript fallback.
|
|
126
|
+
# Interaction UI retains one opener-backed tab handle on desktop. iOS Safari
|
|
127
|
+
# cannot foreground a reused background tab, so it closes and replaces that
|
|
128
|
+
# script-opened tab on each click. The two fixed providers are intentionally
|
|
129
|
+
# trusted for this enhanced path.
|
|
130
|
+
def b270_passage_link(reference, **options)
|
|
131
|
+
data = options.fetch(:data, {}).merge(b270_passage_link: true)
|
|
132
|
+
options.merge!(data: data, target: PASSAGE_LINK_TARGET, rel: 'noopener')
|
|
133
|
+
link_to reference, b270_passage_url(reference), options
|
|
121
134
|
end
|
|
122
135
|
|
|
123
136
|
# Small grey "(NKJV)" after a reading, so it's clear which translation the
|
|
@@ -224,8 +237,7 @@ module Bible270
|
|
|
224
237
|
reference = readings[track]
|
|
225
238
|
next if reference.blank?
|
|
226
239
|
|
|
227
|
-
|
|
228
|
-
class: 'b270-reflink', target: '_blank', rel: 'noopener'
|
|
240
|
+
b270_passage_link reference, class: 'b270-reflink'
|
|
229
241
|
end
|
|
230
242
|
|
|
231
243
|
safe_join(links, ' · ')
|
|
@@ -90,7 +90,7 @@ module Bible270
|
|
|
90
90
|
|
|
91
91
|
# Every reflection is visible when written; these are the moderation actions.
|
|
92
92
|
def hide! = update!(approved: false, moderated_at: Time.current)
|
|
93
|
-
def unhide! = update!(approved: true,
|
|
93
|
+
def unhide! = update!(approved: true, moderated_at: Time.current)
|
|
94
94
|
def hidden? = !approved
|
|
95
95
|
def reply? = parent_id.present?
|
|
96
96
|
|
|
@@ -515,14 +515,13 @@ module Bible270
|
|
|
515
515
|
|
|
516
516
|
# The start date that actually governs this reader. A reader's own
|
|
517
517
|
# started_on wins when per-reader dates are allowed; otherwise (or if they
|
|
518
|
-
# haven't got one) the
|
|
519
|
-
#
|
|
518
|
+
# haven't got one) the current run's shared date applies. Nil means the plan
|
|
519
|
+
# is undated for this reader and no calendar mapping exists.
|
|
520
520
|
def effective_start_date
|
|
521
|
-
|
|
522
|
-
if config.allow_reader_start_date && started_on
|
|
521
|
+
if Bible270.config.allow_reader_start_date && started_on
|
|
523
522
|
started_on
|
|
524
523
|
else
|
|
525
|
-
|
|
524
|
+
Setting.run_start_date
|
|
526
525
|
end
|
|
527
526
|
end
|
|
528
527
|
|
|
@@ -607,10 +606,9 @@ module Bible270
|
|
|
607
606
|
# Called when a reader first participates. Only stamps a personal start date
|
|
608
607
|
# when per-reader dates are enabled and a shared date isn't already in force.
|
|
609
608
|
def ensure_started!
|
|
610
|
-
|
|
611
|
-
return unless config.allow_reader_start_date
|
|
609
|
+
return unless Bible270.config.allow_reader_start_date
|
|
612
610
|
return if started_on.present?
|
|
613
|
-
return if
|
|
611
|
+
return if Setting.run_start_date.present?
|
|
614
612
|
|
|
615
613
|
update!(started_on: Bible270.today)
|
|
616
614
|
end
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Bible270
|
|
4
|
-
# Runtime state an admin can change without a deploy
|
|
5
|
-
#
|
|
4
|
+
# Runtime state an admin can change without a deploy: enrollment and the
|
|
5
|
+
# current run's shared calendar date.
|
|
6
6
|
class Setting < ApplicationRecord
|
|
7
7
|
self.table_name = 'bible270_settings'
|
|
8
8
|
|
|
9
9
|
ENROLLMENT_CLOSED_AT = 'enrollment_closed_at'
|
|
10
|
+
RUN_START_DATE = 'run_start_date'
|
|
10
11
|
|
|
11
12
|
validates :key, presence: true, uniqueness: true
|
|
12
13
|
|
|
@@ -25,6 +26,35 @@ module Bible270
|
|
|
25
26
|
where(key: key.to_s).delete_all
|
|
26
27
|
end
|
|
27
28
|
|
|
29
|
+
# ---- current run ------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
def self.run_start_date
|
|
32
|
+
run_start_date_override || Bible270.config.start_date
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.run_start_date_override
|
|
36
|
+
Plan.to_date(read(RUN_START_DATE))
|
|
37
|
+
rescue ActiveRecord::StatementInvalid
|
|
38
|
+
nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.run_start_date_overridden?
|
|
42
|
+
run_start_date_override.present?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.set_run_start_date!(value)
|
|
46
|
+
date = Plan.to_date(value)
|
|
47
|
+
return false if date.nil?
|
|
48
|
+
|
|
49
|
+
write(RUN_START_DATE, date.iso8601)
|
|
50
|
+
true
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.clear_run_start_date!
|
|
54
|
+
delete_key(RUN_START_DATE)
|
|
55
|
+
true
|
|
56
|
+
end
|
|
57
|
+
|
|
28
58
|
# ---- enrolment --------------------------------------------------------
|
|
29
59
|
|
|
30
60
|
# Closed either because an admin closed it, or because the app was configured
|
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
<div class="b270-panel">
|
|
8
8
|
<h2 class="b270-subhead">This run of the plan is <%= @enrollment_closed ? 'closed' : 'open' %> to new readers.</h2>
|
|
9
9
|
<% if @enrollment_closed %>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
on <%= b270_date(@enrollment_closed_at) %><% end %>.
|
|
10
|
+
<p class="b270-startline">
|
|
11
|
+
<% if @enrollment_closed_at %>Enrollment closed on <%= b270_date(@enrollment_closed_at) %>.<% end %>
|
|
13
12
|
The <%= @readers.size %> reader<%= 's' unless @readers.size == 1 %> already taking part can
|
|
14
|
-
still sign in and carry on
|
|
13
|
+
still sign in and carry on.
|
|
14
|
+
</p>
|
|
15
15
|
<%= button_to 'Open to new readers', admin_enrollment_path, method: :patch,
|
|
16
16
|
params: { state: 'open' }, class: 'b270-btn' %>
|
|
17
17
|
<% else %>
|
|
@@ -22,11 +22,52 @@
|
|
|
22
22
|
<% end %>
|
|
23
23
|
</div>
|
|
24
24
|
|
|
25
|
+
<div class="b270-panel">
|
|
26
|
+
<h2 class="b270-subhead">Current run start date</h2>
|
|
27
|
+
<% if @run_start_date %>
|
|
28
|
+
<p class="b270-startline">
|
|
29
|
+
This run <%= @run_start_date > Bible270.today ? 'starts' : 'started' %>
|
|
30
|
+
<strong><%= @run_start_date.strftime('%B %-d, %Y') %></strong> and ends
|
|
31
|
+
<strong><%= Bible270::Plan.end_date_for(@run_start_date).strftime('%B %-d, %Y') %></strong>.
|
|
32
|
+
<% if @run_start_date_overridden %><span class="b270-badge">Admin override</span><% end %>
|
|
33
|
+
</p>
|
|
34
|
+
<% else %>
|
|
35
|
+
<p class="b270-startline">This run is undated.</p>
|
|
36
|
+
<% end %>
|
|
37
|
+
|
|
38
|
+
<%= form_with url: admin_run_start_path, method: :patch, class: "b270-startform",
|
|
39
|
+
data: { turbo_confirm: "Change the current run start date? Calendar dates, Today, and reminders will be re-mapped. Check-offs and reflections will not change." } do %>
|
|
40
|
+
<label class="b270-field">
|
|
41
|
+
<span>Start date</span>
|
|
42
|
+
<%= date_field_tag :start_date, @run_start_date, required: true %>
|
|
43
|
+
</label>
|
|
44
|
+
<%= submit_tag(@run_start_date ? 'Change start date' : 'Set start date', class: 'b270-btn') %>
|
|
45
|
+
<% end %>
|
|
46
|
+
|
|
47
|
+
<p class="b270-hint">
|
|
48
|
+
This affects <%= pluralize(@shared_calendar_readers, 'reader') %> following the shared calendar.
|
|
49
|
+
<% if @personal_calendar_readers.positive? %>
|
|
50
|
+
<%= pluralize(@personal_calendar_readers, 'reader') %> with a personal calendar will not move.
|
|
51
|
+
<% end %>
|
|
52
|
+
Check-offs and reflections remain attached to their existing day numbers.
|
|
53
|
+
</p>
|
|
54
|
+
|
|
55
|
+
<% if @run_start_date_overridden %>
|
|
56
|
+
<%= button_to 'Use configured date', admin_run_start_path, method: :delete, class: 'b270-linkbtn',
|
|
57
|
+
form: { data: { turbo_confirm: 'Remove the Admin override and use the configured start date?' } } %>
|
|
58
|
+
<p class="b270-hint">
|
|
59
|
+
Configured date:
|
|
60
|
+
<%= @configured_start_date ? @configured_start_date.strftime('%B %-d, %Y') : 'undated' %>.
|
|
61
|
+
</p>
|
|
62
|
+
<% end %>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
25
65
|
<% if @readers.any? %>
|
|
26
66
|
<div class="b270-list">
|
|
27
67
|
<% @readers.each do |reader| %>
|
|
28
68
|
<div class="b270-li">
|
|
29
|
-
<%= b270_avatar(reader, size: 72)
|
|
69
|
+
<%= link_to b270_avatar(reader, size: 72), admin_reader_path(reader),
|
|
70
|
+
"aria-label": reader.display_name %>
|
|
30
71
|
<div>
|
|
31
72
|
<div class="name"><%= link_to reader.display_name, admin_reader_path(reader), style: 'text-decoration:none' %>
|
|
32
73
|
<% if Bible270.config.admin?(reader) %> <span class="sub"><strong>[admin]</strong></span> <% end %>
|
|
@@ -58,8 +99,7 @@
|
|
|
58
99
|
<%= @reachable == 1 ? 'reader' : 'readers' %> individually, not as one message with
|
|
59
100
|
everyone in bcc — so each is greeted by name.
|
|
60
101
|
<% if @last_broadcast_at.present? %>
|
|
61
|
-
<br>Last sent <%= b270_datetime(@last_broadcast_at) %><%
|
|
62
|
-
%><% if @last_broadcast_subject.present? %>: <em><%= @last_broadcast_subject %></em><% end %>.
|
|
102
|
+
<br>Last sent <%= b270_datetime(@last_broadcast_at) %><% if @last_broadcast_subject.present? %>: <em><%= @last_broadcast_subject %></em><% end %>.
|
|
63
103
|
<% end %>
|
|
64
104
|
</p>
|
|
65
105
|
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
b270_success: (part_done ? "Reading marked unread." : "Reading marked read."),
|
|
28
28
|
b270_failure: "Couldn’t update that reading. Try again." } },
|
|
29
29
|
aria: { label: (part_done ? "Mark #{part_ref} unread" : "Mark #{part_ref} read") } do %>
|
|
30
|
-
<span class="b270-check"><svg viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg></span>
|
|
30
|
+
<span class="b270-check"><svg viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12" /></svg></span>
|
|
31
31
|
<% end %>
|
|
32
32
|
<% else %>
|
|
33
|
-
<span class="b270-check"><svg viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg></span>
|
|
33
|
+
<span class="b270-check"><svg viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12" /></svg></span>
|
|
34
34
|
<% end %>
|
|
35
35
|
<span class="b270-ref">
|
|
36
|
-
<%=
|
|
36
|
+
<%= b270_passage_link part_ref %>
|
|
37
37
|
</span>
|
|
38
38
|
</li>
|
|
39
39
|
<% end %>
|
|
@@ -51,14 +51,14 @@
|
|
|
51
51
|
b270_success: (done ? "Reading marked unread." : "Reading marked read."),
|
|
52
52
|
b270_failure: "Couldn’t update that reading. Try again." } },
|
|
53
53
|
aria: { label: (done ? "Mark #{t[:label]} unread" : "Mark #{t[:label]} read") } do %>
|
|
54
|
-
<span class="b270-check"><svg viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg></span>
|
|
54
|
+
<span class="b270-check"><svg viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12" /></svg></span>
|
|
55
55
|
<% end %>
|
|
56
56
|
<% else %>
|
|
57
|
-
<span class="b270-check"><svg viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg></span>
|
|
57
|
+
<span class="b270-check"><svg viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12" /></svg></span>
|
|
58
58
|
<% end %>
|
|
59
59
|
<div class="b270-rbody">
|
|
60
60
|
<div class="b270-cat"><%= t[:label] %></div>
|
|
61
|
-
<div class="b270-ref"><%=
|
|
61
|
+
<div class="b270-ref"><%= b270_passage_link ref %> <%= b270_version_tag(track: track) %></div>
|
|
62
62
|
</div>
|
|
63
63
|
<% end %>
|
|
64
64
|
</div>
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
<h1><%= Bible270.config.app_name %> <em>— read God's whole story</em></h1>
|
|
4
4
|
<p class="lede">Daily passages from the Old Testament, New Testament, and Psalms or Proverbs — portions sized to take about the same time to read. Check off what you read; your place is saved for you, and you can share reflections and encourage one another along the way.</p>
|
|
5
5
|
|
|
6
|
-
<%= render "bible270/shared/progress" %>
|
|
6
|
+
<%= render "bible270/shared/progress", show_start_date: true %>
|
|
7
7
|
|
|
8
8
|
<p style="margin:12px 0 0"><%= link_to "Meet your fellow readers →", community_path %></p>
|
|
@@ -30,6 +30,35 @@
|
|
|
30
30
|
document.querySelectorAll("form[data-b270-submit='true']").forEach(resetForm);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
let scriptureWindow = null;
|
|
34
|
+
const replacesBackgroundTabs = /iPad|iPhone|iPod/.test(navigator.userAgent) ||
|
|
35
|
+
(navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1);
|
|
36
|
+
|
|
37
|
+
document.addEventListener("click", (event) => {
|
|
38
|
+
const target = event.target;
|
|
39
|
+
const link = target.closest && target.closest("a[data-b270-passage-link='true']");
|
|
40
|
+
if (!link || event.defaultPrevented || event.button !== 0) return;
|
|
41
|
+
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
if (replacesBackgroundTabs && scriptureWindow && !scriptureWindow.closed) {
|
|
45
|
+
scriptureWindow.close();
|
|
46
|
+
scriptureWindow = null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!scriptureWindow || scriptureWindow.closed) {
|
|
50
|
+
scriptureWindow = window.open(link.href, "_blank");
|
|
51
|
+
if (!scriptureWindow) return;
|
|
52
|
+
} else {
|
|
53
|
+
scriptureWindow.location = link.href;
|
|
54
|
+
}
|
|
55
|
+
event.preventDefault();
|
|
56
|
+
scriptureWindow.focus();
|
|
57
|
+
} catch (_error) {
|
|
58
|
+
scriptureWindow = null;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
33
62
|
document.addEventListener("submit", (event) => {
|
|
34
63
|
const form = event.target.closest("form[data-b270-submit='true']");
|
|
35
64
|
if (!form) return;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<%# locals: (reader: nil, start_day: nil, today_day: nil, community_start_date: :unset) %>
|
|
1
|
+
<%# locals: (reader: nil, start_day: nil, today_day: nil, community_start_date: :unset, show_start_date: false) %>
|
|
2
2
|
<%#
|
|
3
3
|
The progress panel.
|
|
4
4
|
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
panel_reader = reader || current_reader
|
|
22
22
|
panel_start_day = start_day || panel_reader&.current_day || 1
|
|
23
23
|
panel_today_day = today_day || panel_reader&.today_day
|
|
24
|
-
panel_community_date = community_start_date == :unset ? Bible270.
|
|
24
|
+
panel_community_date = community_start_date == :unset ? Bible270::Setting.run_start_date : community_start_date
|
|
25
|
+
panel_start_date = panel_reader&.effective_start_date if show_start_date
|
|
25
26
|
day_verb = panel_start_day == 1 ? 'Start' : 'Continue'
|
|
26
27
|
panel_behind = panel_today_day.present? && panel_start_day < panel_today_day
|
|
27
28
|
%>
|
|
@@ -29,7 +30,11 @@
|
|
|
29
30
|
<% if panel_reader %>
|
|
30
31
|
<div class="b270-bignum">
|
|
31
32
|
<span class="n"><%= panel_reader.days_completed %></span>
|
|
32
|
-
<span class="of">
|
|
33
|
+
<span class="of">
|
|
34
|
+
of <%= Bible270::Plan::DAYS %> days complete<% if panel_start_date %>
|
|
35
|
+
· plan <% if panel_start_date == Bible270.today %>starts today<% elsif panel_start_date > Bible270.today %>starts on <%= panel_start_date.strftime("%b %-d, %Y") %><% else %>started on <%= panel_start_date.strftime("%b %-d, %Y") %><% end %>
|
|
36
|
+
<% end %>
|
|
37
|
+
</span>
|
|
33
38
|
<span class="pct"><%= panel_reader.completion_percent %>%</span>
|
|
34
39
|
</div>
|
|
35
40
|
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
|
|
113
113
|
.b270-startline{margin:0;font-size:13.5px;color:var(--muted)}
|
|
114
114
|
.b270-startline strong{color:var(--ink)}
|
|
115
|
-
.b270-startform{display:flex;align-items:
|
|
115
|
+
.b270-startform{display:flex;align-items:flex-end;gap:10px;margin-top:10px;flex-wrap:wrap}
|
|
116
116
|
.b270-startform input[type=date]{font:inherit;font-size:14px;padding:8px 10px;border:1px solid var(--line);border-radius:8px;background:#fff;color:var(--ink)}
|
|
117
117
|
.b270-linkbtn{background:none;border:none;padding:0;margin-top:8px;font:inherit;font-size:12.5px;color:var(--oxblood);cursor:pointer;text-decoration:underline}
|
|
118
118
|
.b270-hint{margin:8px 0 0;font-size:12px;color:var(--faint);max-width:111ch}
|
data/config/routes.rb
CHANGED
|
@@ -29,6 +29,8 @@ Bible270::Engine.routes.draw do
|
|
|
29
29
|
|
|
30
30
|
post 'admin/broadcast', to: 'admin#broadcast', as: :admin_broadcast
|
|
31
31
|
patch 'admin/enrollment', to: 'admin#update_enrollment', as: :admin_enrollment
|
|
32
|
+
patch 'admin/run-start', to: 'admin#update_run_start', as: :admin_run_start
|
|
33
|
+
delete 'admin/run-start', to: 'admin#reset_run_start'
|
|
32
34
|
get 'admin/comments', to: 'admin#comments', as: :admin_comments
|
|
33
35
|
patch 'admin/comments/:id/hide', to: 'admin#hide_comment', as: :admin_hide_comment
|
|
34
36
|
patch 'admin/comments/:id/unhide', to: 'admin#unhide_comment', as: :admin_unhide_comment
|
|
@@ -271,7 +271,6 @@ module Bible270
|
|
|
271
271
|
PROVIDER_LABELS[key.to_sym] || key.to_s.tr('_', ' ').split.map(&:capitalize).join(' ')
|
|
272
272
|
end
|
|
273
273
|
|
|
274
|
-
# Default Bible translation and a builder for external passage links.
|
|
275
274
|
# Which translations readers may choose from. Defaults to all of
|
|
276
275
|
# Bible270::Translations::VERSIONS; narrow it to offer fewer.
|
|
277
276
|
attr_accessor :bible_versions
|
|
@@ -297,7 +296,7 @@ module Bible270
|
|
|
297
296
|
# application owns scheduling the bible270:reminders:send task.
|
|
298
297
|
attr_accessor :daily_reminders
|
|
299
298
|
|
|
300
|
-
attr_accessor :after_sign_out_path, :email_sign_in_max_per_window, :
|
|
299
|
+
attr_accessor :after_sign_out_path, :email_sign_in_max_per_window, :tagline, :footer_html, :footer, :favicon, :avatar_max_bytes, :chapter_breaks, :admin_emails, :admin_resolver, :bible_version, :header_mark, :remember_for, :require_sign_in_to_participate
|
|
301
300
|
|
|
302
301
|
# Public labels.
|
|
303
302
|
attr_accessor :app_name
|
|
@@ -355,7 +354,6 @@ module Bible270
|
|
|
355
354
|
@after_sign_out_path = nil
|
|
356
355
|
@bible_version = 'NKJV'
|
|
357
356
|
@bible_versions = Translations::VERSIONS.keys
|
|
358
|
-
@passage_url_builder = ->(reference, version) { Translations.passage_url(reference, version) }
|
|
359
357
|
@app_name = 'Daily Bread'
|
|
360
358
|
@tagline = 'Journeying through Scripture in 9 months'
|
|
361
359
|
@time_zone = nil
|
data/lib/bible270/plan.rb
CHANGED
|
@@ -493,14 +493,14 @@ module Bible270
|
|
|
493
493
|
pinned.merge(pinned_from_breaks(chapters))
|
|
494
494
|
end
|
|
495
495
|
|
|
496
|
-
def psalm_parts = memo(:psalm_parts)
|
|
496
|
+
def psalm_parts = memo(:psalm_parts) { pp_parts.first(psalm_chapters.size) }
|
|
497
497
|
def proverbs_parts = memo(:proverbs_parts) { pp_parts.last(proverbs_chapters.size) }
|
|
498
498
|
|
|
499
|
-
def psalm_readings = memo(:psalm_readings)
|
|
499
|
+
def psalm_readings = memo(:psalm_readings) { expand_readings(psalm_chapters, psalm_parts) }
|
|
500
500
|
def proverbs_readings = memo(:proverbs_readings) { expand_readings(proverbs_chapters, proverbs_parts) }
|
|
501
501
|
|
|
502
502
|
# Readings grouped by chapter, so a divided chapter stays together.
|
|
503
|
-
def psalm_groups = memo(:psalm_groups)
|
|
503
|
+
def psalm_groups = memo(:psalm_groups) { group_by_chapter(psalm_readings) }
|
|
504
504
|
def proverbs_groups = memo(:proverbs_groups) { group_by_chapter(proverbs_readings) }
|
|
505
505
|
|
|
506
506
|
def group_by_chapter(readings)
|
|
@@ -530,7 +530,7 @@ module Bible270
|
|
|
530
530
|
end
|
|
531
531
|
end
|
|
532
532
|
|
|
533
|
-
def pp_plan = memo(:pp_plan)
|
|
533
|
+
def pp_plan = memo(:pp_plan) { pp_readings.map { |seg| format_segment(seg) } }
|
|
534
534
|
def pp_verse_loads = memo(:pp_verse_loads) { pp_readings.map { |seg| segment_length(seg) } }
|
|
535
535
|
|
|
536
536
|
# 1-indexed days carrying a Proverbs reading.
|
data/lib/bible270/version.rb
CHANGED