openstax_kitchen 15.0.0 → 18.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -0
  3. data/Gemfile.lock +5 -5
  4. data/lib/kitchen/directions/bake_annotation_classes/v1.rb +11 -2
  5. data/lib/kitchen/directions/bake_autotitled_exercise/main.rb +4 -0
  6. data/lib/kitchen/directions/bake_autotitled_exercise/v3.rb +35 -0
  7. data/lib/kitchen/directions/bake_chapter_references/main.rb +15 -0
  8. data/lib/kitchen/directions/bake_chapter_references/v2.rb +53 -0
  9. data/lib/kitchen/directions/bake_chapter_references/v3.rb +45 -0
  10. data/lib/kitchen/directions/bake_chapter_summary.rb +5 -4
  11. data/lib/kitchen/directions/bake_exercise_prefixes/main.rb +14 -0
  12. data/lib/kitchen/directions/bake_exercise_prefixes/v1.rb +22 -0
  13. data/lib/kitchen/directions/bake_footnotes/v1.rb +1 -1
  14. data/lib/kitchen/directions/bake_handbook/v1.rb +1 -1
  15. data/lib/kitchen/directions/bake_index/v1.rb +13 -8
  16. data/lib/kitchen/directions/bake_index/v1.xhtml.erb +1 -1
  17. data/lib/kitchen/directions/{bake_injected_exercise.rb → bake_injected_exercise/bake_injected_exercise.rb} +10 -1
  18. data/lib/kitchen/directions/bake_injected_exercise/bake_injected_exercise_question.rb +4 -0
  19. data/lib/kitchen/directions/bake_link_placeholders.rb +1 -1
  20. data/lib/kitchen/directions/bake_lo_link_labels.rb +19 -0
  21. data/lib/kitchen/directions/bake_non_introduction_pages.rb +3 -1
  22. data/lib/kitchen/directions/bake_numbered_table/bake_table_body.rb +6 -1
  23. data/lib/kitchen/directions/bake_numbered_table/v2.rb +2 -1
  24. data/lib/kitchen/directions/bake_references/v1.rb +13 -0
  25. data/lib/kitchen/directions/bake_screenreader_spans.rb +22 -0
  26. data/lib/kitchen/directions/bake_unit_page_title/v1.rb +8 -2
  27. data/lib/kitchen/directions/bake_unnumbered_tables.rb +4 -0
  28. data/lib/kitchen/element_base.rb +25 -5
  29. data/lib/kitchen/element_enumerator_base.rb +18 -0
  30. data/lib/kitchen/injected_exercise_element.rb +41 -0
  31. data/lib/kitchen/injected_exercise_element_enumerator.rb +21 -0
  32. data/lib/kitchen/injected_question_element.rb +7 -0
  33. data/lib/kitchen/patches/i18n.rb +4 -0
  34. data/lib/kitchen/patches/integer.rb +32 -3
  35. data/lib/kitchen/patches/nokogiri.rb +5 -4
  36. data/lib/kitchen/selectors/base.rb +3 -0
  37. data/lib/kitchen/selectors/standard_1.rb +1 -0
  38. data/lib/kitchen/version.rb +1 -1
  39. data/lib/locales/en.yml +16 -0
  40. metadata +12 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 074dfc264ca97aab5805a3ab189b49fe1e97a1108366b592b5599a70e15f1345
4
- data.tar.gz: fee3491d899d7983e55e5c6eb22010b49d23e8dd43e54ca97950a7be2fbda93f
3
+ metadata.gz: 4343b799c2a49cec3c179ba3af59dae109cdb4fb4839fd7993710d6a1125d322
4
+ data.tar.gz: 6ac5fcdb6adda5fbf080b507676156c42dfc301f8060bae4dabe1bf3561fbebf
5
5
  SHA512:
6
- metadata.gz: d9a5936f931cf6b1c3485543adf375426d71b444109c68fc80b0a06ef6f953e4ac43cd40b27941c06dec0541e02dd2b3387074aa8a956821cdca781f97607f1d
7
- data.tar.gz: 13d5bf302fe8144acef670f017bc8393847292d37f4a4dae68922cbf56c52da41c18719ec586ca1b5b1a135dc0c303e168f5515903e2b667299347cba909e7d4
6
+ metadata.gz: 4dad4bfc3619807740965bc6d8f9c4332e13d2031433a5b32576d3fb66d79005ae08bebd9e25398097921ff15e1c835ebefa2b3a35d30185f194442412355f89
7
+ data.tar.gz: 6372b3c2860ef570dd6e0ff9011ee08759138843eef48953a2187452581edcccd96df337d1441bad5f03c32482c9058104f2ae20d4e50a905baf279a478fdb87
data/CHANGELOG.md CHANGED
@@ -6,6 +6,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+
10
+ ## [18.0.0] - 2022-01-14
11
+
12
+ * Fix links in `BakeHanbook` outline to point sections (patch)
13
+ * Add unit title prefix with number to `BakeUnitPageTitle` (patch)
14
+ * Add `scope="col"` attribute to `BakeTableBody` and `BakeUnnumberedTables` (major)
15
+
16
+ ## [17.1.0] - 2021-12-17
17
+
18
+ * Add append_to support to `BakeChapterSummary` (minor)
19
+ * Add support for italicized terms in index (minor)
20
+ * Fix problem with namespaces in `BakeLinkPlaceholders` and `BakeIndex` (minor)
21
+ * Create `V3` for `BakeChapterReferences` which sorts references alphabetically (minor)
22
+
23
+ ## [17.0.0] - 2021-12-3
24
+
25
+ * Create method in `Integer` class that generate roman numbers up to 100 (minor)
26
+ * Add more roman numbers to `Integer` class (patch)
27
+ * Create `V2` for `BakeChapterReferences` (minor)
28
+ * Create `BakeExercisePrefixes` direction adding prefixes for exercises in selected sections (minor)
29
+ * Add support for 'text-heavy-top-titled' tables in `BakeTableBody` (minor)
30
+ * Remove `Nokigiri#previous` patch, `ElementBase#previous` now uses `#previous_element` (minor)
31
+ * Modifies `BakeAnnotationClasses` for annotations wrapper to be a `span` intead of a `div` (major)
32
+
33
+ ## [16.0.0] - 2021-11-19
34
+
35
+ * Add reference link separator to `BakeReferences.v1` (patch)
36
+ * Modify `BakeFootnotes` to be more general (minor)
37
+ * Add `#preceded_by_text` method to element_base and the nokigiri patch (minor)
38
+ * Remove `Nokigiri#previous` patch, `ElementBase#previous` now uses `#previous_element` (minor)
39
+ * Broaden caption selection for `BakeNumberedTable#v2` (patch)
40
+ * Add details of question count to injected exercises in `BakeInjectedExercise` (major)
41
+ * Add target labels to chapter content module pages option in `BakeNonIntroductionPages`, create a separate directory `BakeLOLinkLabels` to add `.label-text`, `.label-counter` spans wrappers for links with `.lo-reference` class (minor)
42
+ * Add `BakeScreenreaderSpans` direction (minor)
43
+ * Fix `BakeIndex` to group terms by character in polish books and transliterate it for others (minor)
44
+ * Add optional bake `exercies-context` figure_reference if there is one present in singular part exercises to `BakeInjectedExercise`,`BakeInjectedQuestion` to move it down from exercise to question problem container. (major)
45
+ * Create v3 for autotitled exercises with os-hasSolution class
46
+
9
47
  ## [15.0.0] - 2021-11-05
10
48
 
11
49
  * Add unstyled tables to `BakeTableBody` (minor)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- openstax_kitchen (15.0.0)
4
+ openstax_kitchen (18.0.0)
5
5
  activesupport
6
6
  i18n
7
7
  nokogiri
@@ -11,7 +11,7 @@ PATH
11
11
  GEM
12
12
  remote: https://rubygems.org/
13
13
  specs:
14
- activesupport (6.1.4.1)
14
+ activesupport (6.1.4.4)
15
15
  concurrent-ruby (~> 1.0, >= 1.0.2)
16
16
  i18n (>= 1.6, < 2)
17
17
  minitest (>= 5.1)
@@ -36,7 +36,7 @@ GEM
36
36
  yard (~> 0.9.12)
37
37
  method_source (1.0.0)
38
38
  mini_portile2 (2.5.0)
39
- minitest (5.14.4)
39
+ minitest (5.15.0)
40
40
  nokogiri (1.11.1)
41
41
  mini_portile2 (~> 2.5.0)
42
42
  racc (~> 1.4)
@@ -99,7 +99,7 @@ GEM
99
99
  tins (~> 1.0)
100
100
  tins (1.26.0)
101
101
  sync
102
- twitter_cldr (6.7.0)
102
+ twitter_cldr (6.11.0)
103
103
  camertron-eprun
104
104
  cldr-plurals-runtime-rb (~> 1.1)
105
105
  tzinfo
@@ -107,7 +107,7 @@ GEM
107
107
  concurrent-ruby (~> 1.0)
108
108
  unicode-display_width (1.7.0)
109
109
  yard (0.9.24)
110
- zeitwerk (2.5.1)
110
+ zeitwerk (2.5.3)
111
111
 
112
112
  PLATFORMS
113
113
  ruby
@@ -20,9 +20,18 @@ module Kitchen::Directions::BakeAnnotationClasses
20
20
  kinesthetic-icon]
21
21
  annotation_icon_classes.each do |annotation_icon_class|
22
22
  book.search("p.#{annotation_icon_class}").each do |annotation_with_icon_class|
23
- annotation_with_icon_class.search('div.os-icons').first.append(child:
23
+ annotation_with_icon_class.search('div.os-icons').first&.name = 'span'
24
+
25
+ icon_title = I18n.t(:"annotation_icons.#{annotation_icon_class}.title")
26
+
27
+ annotation_with_icon_class.search('span.os-icons').first.append(child:
24
28
  <<~HTML
25
- <span class = "#{annotation_icon_class}"></span>
29
+ <span
30
+ class = "#{annotation_icon_class}"
31
+ role="img"
32
+ title="#{icon_title}"
33
+ aria-label="#{icon_title}"
34
+ ></span>
26
35
  HTML
27
36
  )
28
37
  end
@@ -10,6 +10,10 @@ module Kitchen
10
10
  def self.v2(exercise:, title:)
11
11
  V2.new.bake(exercise: exercise, title: title)
12
12
  end
13
+
14
+ def self.v3(exercise:, title:)
15
+ V3.new.bake(exercise: exercise, title: title)
16
+ end
13
17
  end
14
18
  end
15
19
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen::Directions::BakeAutotitledExercise
4
+ # Differences from V2:
5
+ # 1. Exercise with solution has class os-hasSolution
6
+ # 2. Solution id is based on exercise id
7
+ class V3
8
+ def bake(exercise:, title:)
9
+ exercise.add_class('unnumbered')
10
+ exercise.titles.first&.trash
11
+
12
+ # bake problem
13
+ exercise.prepend(child:
14
+ <<~HTML
15
+ <h3 class="os-title" data-type="title">
16
+ <span class="os-title-label">#{title}</span>
17
+ </h3>
18
+ HTML
19
+ )
20
+ exercise.problem.wrap_children(class: 'os-problem-container')
21
+ return unless exercise.solution
22
+
23
+ exercise.add_class('os-hasSolution')
24
+ exercise.solution.id = "#{exercise.id}-solution"
25
+ exercise.solution.wrap_children(class: 'os-solution-container')
26
+ exercise.solution.prepend(child:
27
+ <<~HTML
28
+ <h4 class="solution-title" data-type="title">
29
+ <span class="os-text">#{I18n.t(:solution)}</span>
30
+ </h4>
31
+ HTML
32
+ )
33
+ end
34
+ end
35
+ end
@@ -10,6 +10,21 @@ module Kitchen
10
10
  uuid_prefix: uuid_prefix,
11
11
  klass: klass)
12
12
  end
13
+
14
+ def self.v2(chapter:, metadata_source:, uuid_prefix: '.', klass: 'references')
15
+ V2.new.bake(
16
+ chapter: chapter,
17
+ metadata_source: metadata_source,
18
+ uuid_prefix: uuid_prefix,
19
+ klass: klass)
20
+ end
21
+
22
+ def self.v3(chapter:, metadata_source:, uuid_prefix: '.')
23
+ V3.new.bake(
24
+ chapter: chapter,
25
+ metadata_source: metadata_source,
26
+ uuid_prefix: uuid_prefix)
27
+ end
13
28
  end
14
29
  end
15
30
  end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen::Directions::BakeChapterReferences
4
+ class V2
5
+ def bake(chapter:, metadata_source:, uuid_prefix: '.', klass: 'references')
6
+ chapter.pages.each do |page|
7
+ bake_page_cite(page: page)
8
+ bake_page_references(page: page)
9
+ end
10
+
11
+ return if chapter.pages.references.none?
12
+
13
+ content = chapter.pages.references.cut.paste
14
+
15
+ Kitchen::Directions::CompositePageContainer.v1(
16
+ container_key: klass,
17
+ uuid_key: "#{uuid_prefix}#{klass}",
18
+ metadata_source: metadata_source,
19
+ content: content,
20
+ append_to: chapter
21
+ )
22
+ end
23
+
24
+ def bake_page_cite(page:)
25
+ page.search('[data-type="cite"]').each do |link|
26
+ link.id = "#{page.id}-endNote#{link.count_in(:chapter)}"
27
+
28
+ link.prepend(child:
29
+ <<~HTML
30
+ <sup class="os-end-note-number">#{link.count_in(:chapter)}</sup>
31
+ HTML
32
+ )
33
+
34
+ link.search('.delete-me').trash
35
+ end
36
+ end
37
+
38
+ def bake_page_references(page:)
39
+ page.references.each do |reference|
40
+ Kitchen::Directions::RemoveSectionTitle.v1(section: reference)
41
+
42
+ reference.search('a').each do |ref_link|
43
+ ref_link.replace_children(with:
44
+ <<~HTML
45
+ <span>#{ref_link.count_in(:chapter)}.</span>
46
+ HTML
47
+ )
48
+ ref_link.href = "##{page.id}-endNote#{ref_link.count_in(:chapter)}"
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen::Directions::BakeChapterReferences
4
+ class V3
5
+ class Reference
6
+ attr_reader :element
7
+
8
+ def initialize(element)
9
+ reference_item = Kitchen::I18nString.new(element.text.downcase)
10
+ @sortable = [reference_item]
11
+ @element = element
12
+ end
13
+
14
+ def <=>(other)
15
+ sortable <=> other.sortable
16
+ end
17
+
18
+ protected
19
+
20
+ attr_reader :sortable
21
+ end
22
+
23
+ def bake(chapter:, metadata_source:, append_to: nil, uuid_prefix: '.')
24
+ @references = []
25
+
26
+ chapter.references.search('p').each do |reference_element|
27
+ @references.push(Reference.new(reference_element.cut))
28
+ end
29
+
30
+ chapter.references.trash
31
+
32
+ content = @references.sort.map { |reference| reference.element.paste }.join
33
+
34
+ return if content.empty?
35
+
36
+ Kitchen::Directions::CompositePageContainer.v1(
37
+ container_key: 'references',
38
+ uuid_key: "#{uuid_prefix}references",
39
+ metadata_source: metadata_source,
40
+ content: content,
41
+ append_to: append_to || chapter
42
+ )
43
+ end
44
+ end
45
+ end
@@ -5,17 +5,18 @@ module Kitchen
5
5
  # Bake directions for eoc summary
6
6
  #
7
7
  module BakeChapterSummary
8
- def self.v1(chapter:, metadata_source:, klass: 'summary', uuid_prefix: '.')
8
+ def self.v1(chapter:, metadata_source:, klass: 'summary', uuid_prefix: '.', append_to: nil)
9
9
  V1.new.bake(
10
10
  chapter: chapter,
11
11
  metadata_source: metadata_source,
12
12
  uuid_prefix: uuid_prefix,
13
- klass: klass
13
+ klass: klass,
14
+ append_to: append_to
14
15
  )
15
16
  end
16
17
 
17
18
  class V1
18
- def bake(chapter:, metadata_source:, uuid_prefix: '.', klass: 'summary')
19
+ def bake(chapter:, metadata_source:, uuid_prefix: '.', klass: 'summary', append_to: nil)
19
20
  summaries = Clipboard.new
20
21
 
21
22
  chapter.pages.each do |page|
@@ -36,7 +37,7 @@ module Kitchen
36
37
  uuid_key: "#{uuid_prefix}#{klass}",
37
38
  metadata_source: metadata_source,
38
39
  content: summaries.paste,
39
- append_to: chapter
40
+ append_to: append_to || chapter
40
41
  )
41
42
  end
42
43
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ module Directions
5
+ module BakeExercisePrefixes
6
+ def self.v1(chapter:, sections_prefixed:)
7
+ V1.new.bake(
8
+ chapter: chapter,
9
+ sections_prefixed: sections_prefixed
10
+ )
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen::Directions::BakeExercisePrefixes
4
+ class V1
5
+ def bake(chapter:, sections_prefixed:)
6
+ sections_prefixed.each do |section_key|
7
+ chapter.composite_pages.each do |composite_page|
8
+ composite_page.search("section.#{section_key}").exercises.each do |exercise|
9
+ problem = exercise.problem
10
+ exercise_prefix =
11
+ "<span class='os-text'>#{I18n.t(:"sections_prefixed.#{section_key}")}</span>"
12
+ problem.prepend(child:
13
+ <<~HTML
14
+ #{exercise_prefix}
15
+ HTML
16
+ )
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -30,7 +30,7 @@ module Kitchen::Directions::BakeFootnotes
30
30
  aside_id_to_footnote_number[aside_id] = footnote_number
31
31
  if anchor.parent.name == 'p'
32
32
  anchor.parent.add_class('has-noteref')
33
- elsif anchor.parent.name == 'em' && anchor.parent.parent.name == 'p'
33
+ elsif anchor.parent.name != 'p' && anchor.parent.parent.name == 'p'
34
34
  anchor.parent.parent.add_class('has-noteref')
35
35
  end
36
36
  end
@@ -43,7 +43,7 @@ module Kitchen::Directions::BakeHandbook
43
43
 
44
44
  outline_item_html = <<~HTML
45
45
  <div class="os-handbook-objective">
46
- <a class="os-handbook-objective" href="##{first_section_title[:id]}">
46
+ <a class="os-handbook-objective" href="##{section[:id]}">
47
47
  #{first_section_title.children}
48
48
  </a>
49
49
  </div>
@@ -11,12 +11,14 @@ module Kitchen::Directions::BakeIndex
11
11
  attr_reader :id
12
12
  attr_reader :group_by
13
13
  attr_reader :page_title
14
+ attr_reader :italicized
14
15
 
15
- def initialize(text:, id:, group_by:, page_title:)
16
+ def initialize(text:, id:, group_by:, page_title:, italicized:)
16
17
  @text = text.strip
17
18
  @id = id
18
19
  @group_by = group_by
19
20
  @page_title = page_title
21
+ @italicized = italicized
20
22
  end
21
23
  end
22
24
 
@@ -126,7 +128,8 @@ module Kitchen::Directions::BakeIndex
126
128
  page = term_element.ancestor(:page)
127
129
  term_element.id = "auto_#{page.id}_term#{term_element.count_in(:book)}"
128
130
  page_title = page.title.text
129
- add_term_to_index(term_element, page_title)
131
+ term_italicized = term_element&.first("em[data-effect='italics']")
132
+ add_term_to_index(term_element, page_title, term_italicized)
130
133
  end
131
134
 
132
135
  book.chapters.composite_pages.terms.each do |term_element|
@@ -135,7 +138,8 @@ module Kitchen::Directions::BakeIndex
135
138
  term_element.id = "auto_composite_page_term#{term_element.count_in(:book)}"
136
139
  chapter_number = chapter.count_in(:book)
137
140
  page_title = "#{chapter_number} #{page.title.text.strip}".strip
138
- add_term_to_index(term_element, page_title)
141
+ term_italicized = term_element&.first("em[data-effect='italics']")
142
+ add_term_to_index(term_element, page_title, term_italicized)
139
143
  end
140
144
 
141
145
  types.each do |type|
@@ -150,22 +154,22 @@ module Kitchen::Directions::BakeIndex
150
154
  end
151
155
  end
152
156
 
153
- def add_term_to_index(term_element, page_title)
157
+ def add_term_to_index(term_element, page_title, term_italicized)
154
158
  type =
155
159
  if !term_element.key?('index')
156
160
  'term'
157
- elsif term_element['cxlxt:index'] == 'name'
161
+ elsif term_element['cxlxt:index'] == 'name' || term_element['index'] == 'name'
158
162
  'name'
159
- elsif term_element['cxlxt:index'] == 'foreign'
163
+ elsif term_element['cxlxt:index'] == 'foreign' || term_element['index'] == 'foreign'
160
164
  'foreign'
161
165
  end
162
166
 
163
167
  if term_element.key?('reference')
164
- term_reference = term_element['cmlnle:reference']
168
+ term_reference = term_element['cmlnle:reference'] || term_element['reference']
165
169
  group_by = term_reference[0]
166
170
  content = term_reference
167
171
  else
168
- group_by = I18n.transliterate(term_element.text.strip[0])
172
+ group_by = I18n.character_to_group(term_element.text.strip[0])
169
173
  content = term_element.text
170
174
  end
171
175
 
@@ -175,6 +179,7 @@ module Kitchen::Directions::BakeIndex
175
179
  # Add it to our index object
176
180
  @indexes[type].add_term(
177
181
  Term.new(
182
+ italicized: term_italicized,
178
183
  text: content,
179
184
  id: term_element.id,
180
185
  group_by: group_by,
@@ -13,7 +13,7 @@
13
13
  <div class="os-index-item">
14
14
  <%- item.terms.each_with_index do |term, ii| -%>
15
15
  <%- if ii == 0 -%>
16
- <span class="os-term" group-by="<%= term.group_by %>"><%= term.text %></span>
16
+ <span class="os-term" group-by="<%= term.group_by %>"><%- if term.italicized -%><em data-effect="italics"><%= term.text %></em><%- else -%><%= term.text %><% end %></span>
17
17
  <%- else -%><span class="os-index-link-separator">, </span><% end %>
18
18
  <a class="os-term-section-link" href="#<%= term.id %>"><span class="os-term-section"><%= term.page_title %></span></a><!--
19
19
  --><%- end %>
@@ -7,12 +7,21 @@ module Kitchen::Directions::BakeInjectedExercise
7
7
 
8
8
  class V1
9
9
  def bake(exercise:)
10
- context = exercise.search('div[data-type="exercise-context"]')&.first
10
+ question_count = exercise.injected_questions.count
11
+ exercise[:'data-question-count'] = question_count
12
+ exercise[:'data-is-multipart'] = question_count > 1 ? 'True' : 'False'
13
+
14
+ context = exercise&.exercise_context
15
+
11
16
  return unless context
12
17
 
13
18
  # link replacement is done by BakeLinkPlaceholders
14
19
  link = context.first('a').cut
15
20
  context.replace_children(with: "#{I18n.t(:context_lead_text)}#{link.paste}")
21
+ return unless question_count == 1
22
+
23
+ question = exercise.exercise_question
24
+ question.prepend(child: context.cut.paste)
16
25
  end
17
26
  end
18
27
  end
@@ -41,11 +41,15 @@ module Kitchen::Directions::BakeInjectedExerciseQuestion
41
41
  end
42
42
  end
43
43
 
44
+ context = question.exercise_context_in_question&.cut&.paste
45
+
44
46
  question.prepend(child:
45
47
  <<~HTML
46
48
  #{problem_number unless only_number_solution}
47
49
  #{"<span class='os-divider'>. </span>" unless only_number_solution}
48
50
  <div class="os-problem-container">
51
+ #{context if context.present?}
52
+ #{"<span class='os-divider'>. </span>" if context.present?}
49
53
  #{question.stimulus&.cut&.paste}
50
54
  #{question.stem.cut.paste}
51
55
  #{question.answers&.cut&.paste}
@@ -9,7 +9,7 @@ module Kitchen
9
9
  book.search('a').each do |anchor|
10
10
  next unless anchor.text == '[link]'
11
11
 
12
- label_case = anchor['cmlnle:case']
12
+ label_case = anchor['cmlnle:case'] || anchor['case']
13
13
  id = anchor[:href][1..-1]
14
14
 
15
15
  if cases
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ module Directions
5
+ # Bake directions for LO link labels
6
+ module BakeLOLinkLabels
7
+ def self.v1(book:)
8
+ book.search('a.lo-reference').each do |anchor|
9
+ anchor.wrap_children('span', class: 'label-counter')
10
+ anchor.prepend(child:
11
+ <<~HTML
12
+ <span class="label-text">#{I18n.t(:lo_label_text)}</span>
13
+ HTML
14
+ )
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -3,13 +3,15 @@
3
3
  module Kitchen
4
4
  module Directions
5
5
  module BakeNonIntroductionPages
6
- def self.v1(chapter:)
6
+ def self.v1(chapter:, add_target_label: false)
7
7
  chapter.non_introduction_pages.each do |page|
8
8
  number = "#{chapter.count_in(:book)}.#{page.count_in(:chapter)}"
9
9
 
10
10
  page.search("div[data-type='description']").each(&:trash)
11
11
  page.add_class('chapter-content-module')
12
12
 
13
+ page.target_label(custom_content: number) if add_target_label
14
+
13
15
  title = page.title
14
16
  title.name = 'h2'
15
17
  title.replace_children(with:
@@ -40,12 +40,17 @@ module Kitchen
40
40
  table.remove_attribute('summary')
41
41
  table.wrap(%(<div class="os-table">))
42
42
 
43
+ table.search('th').each do |header|
44
+ header[:scope] = 'col'
45
+ end
46
+
43
47
  # Store label information
44
48
  table.target_label(label_text: 'table', custom_content: number, cases: cases)
45
49
 
46
50
  if table.top_titled?
51
+ klass = table.text_heavy? ? 'text-heavy-top-titled' : 'top-titled'
47
52
  custom_table = CustomBody.new(table: table,
48
- klass: 'top-titled',
53
+ klass: klass,
49
54
  fake_title_class: 'os-table-title',
50
55
  fake_title: table.title,
51
56
  to_trash: table.title_row)
@@ -9,7 +9,8 @@ module Kitchen::Directions::BakeNumberedTable
9
9
  Kitchen::Directions::BakeTableBody::V1.new.bake(table: table, number: number, cases: cases)
10
10
 
11
11
  caption = ''
12
- if table&.caption&.first("span[data-type='title']") && !table.top_captioned?
12
+ if (table&.caption&.first("span[data-type='title']") || table&.caption) \
13
+ && !table.top_captioned?
13
14
  caption_el = table.caption
14
15
  caption_el.add_class('os-caption')
15
16
  caption_el.name = 'span'
@@ -12,6 +12,19 @@ module Kitchen::Directions::BakeReferences
12
12
  <sup class="os-citation-number">#{link.count_in(:chapter)}</sup>
13
13
  HTML
14
14
  )
15
+
16
+ next if link.nil?
17
+
18
+ link_sibling = link.previous unless link.preceded_by_text?
19
+ next if link_sibling.nil?
20
+
21
+ next unless link_sibling&.raw&.attr('data-type') == 'cite'
22
+
23
+ link.prepend(sibling:
24
+ <<~HTML
25
+ <span class="os-reference-link-separator">, </span>
26
+ HTML
27
+ )
15
28
  end
16
29
 
17
30
  chapter.references.each do |reference|
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ module Directions
5
+ module BakeScreenreaderSpans
6
+ # Add text for accessibility.
7
+ # Additional screenreader spans can be added below.
8
+ def self.v1(book:)
9
+ book.search('u[data-effect="double-underline"]').each do |element|
10
+ element.add_previous_sibling(
11
+ '<span data-screenreader-only="true">double underline</span>'
12
+ )
13
+ end
14
+ book.search('u[data-effect="underline"]').each do |element|
15
+ element.add_previous_sibling(
16
+ '<span data-screenreader-only="true">underline</span>'
17
+ )
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -4,17 +4,23 @@ module Kitchen::Directions::BakeUnitPageTitle
4
4
  class V1
5
5
  def bake(book:)
6
6
  book.units.each do |unit|
7
+ @unit_title = I18n.t(:unit)
8
+ @unit_number = unit.count_in(:book)
7
9
  unit.element_children.only(Kitchen::PageElement).each do |page|
8
- compose_unit_page_title(page: page)
10
+ compose_unit_page_title(page: page, unit_title_prefix: @unit_title,
11
+ unit_number: @unit_number)
9
12
  end
10
13
  end
11
14
  end
12
15
 
13
- def compose_unit_page_title(page:)
16
+ def compose_unit_page_title(page:, unit_title_prefix:, unit_number:)
14
17
  title = page.title
15
18
  title.name = 'h2'
16
19
  title.replace_children(with:
17
20
  <<~HTML
21
+ <span class="os-part-text">#{unit_title_prefix} </span>
22
+ <span class="os-number">#{unit_number}</span>
23
+ <span class="os-divider"> </span>
18
24
  <span data-type="" itemprop="" class="os-text">#{title.text}</span>
19
25
  HTML
20
26
  )
@@ -10,6 +10,10 @@ module Kitchen
10
10
  table.parent.add_class('os-unstyled-container') if table.unstyled?
11
11
  table.parent.add_class('os-column-header-container') if table.column_header?
12
12
  table.parent.add_class('os-top-titled-container') if table.top_titled?
13
+
14
+ table.search('th').each do |header|
15
+ header[:scope] = 'col'
16
+ end
13
17
  end
14
18
  end
15
19
  end
@@ -82,9 +82,13 @@ module Kitchen
82
82
  # Set the inner HTML for this element
83
83
  # @see https://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/Node#inner_html=-instance_method Nokogiri::XML::Node#inner_html=
84
84
  # @return Object
85
+ # @!method preceded_by_text
86
+ # Returns true if the immediately preceding sibling is text
87
+ # @return Boolean
85
88
  def_delegators :@node, :name=, :name, :[], :[]=, :add_class, :remove_class,
86
89
  :text, :wrap, :children, :to_html, :remove_attribute,
87
- :key?, :classes, :path, :inner_html=
90
+ :key?, :classes, :path, :inner_html=, :add_previous_sibling,
91
+ :preceded_by_text?
88
92
 
89
93
  # @!method config
90
94
  # Get the config for this element's document
@@ -219,6 +223,22 @@ module Kitchen
219
223
  self[:'data-type']
220
224
  end
221
225
 
226
+ # Returns the element's href
227
+ #
228
+ # @return [String]
229
+ #
230
+ def href
231
+ self[:href]
232
+ end
233
+
234
+ # Sets the element's href
235
+ #
236
+ # @param value [String] the new value for the href
237
+ #
238
+ def href=(value)
239
+ self[:href] = value
240
+ end
241
+
222
242
  # A way to set values and chain them
223
243
  #
224
244
  # @param property [String, Symbol] the name of the property to set
@@ -502,12 +522,12 @@ module Kitchen
502
522
  Element.new(node: raw.parent, document: document, short_type: "parent(#{short_type})")
503
523
  end
504
524
 
505
- # returns previous element
506
- # skips double indentations that the nokigiri sometimes picks up
525
+ # returns previous element sibling
526
+ # (only returns elements or nil)
507
527
  # nil if there's no previous sibling
508
528
  #
509
529
  def previous
510
- prev = raw.previous
530
+ prev = raw.previous_element
511
531
  return prev if prev.nil?
512
532
 
513
533
  Element.new(
@@ -754,7 +774,7 @@ module Kitchen
754
774
  def_delegators :as_enumerator, :pages, :chapters, :terms, :figures, :notes, :tables, :examples,
755
775
  :metadatas, :non_introduction_pages, :units, :titles, :exercises, :references,
756
776
  :composite_pages, :composite_chapters, :solutions, :injected_questions,
757
- :search_with, :sections
777
+ :search_with, :sections, :injected_exercises
758
778
 
759
779
  # Returns this element as an enumerator (over only one element, itself)
760
780
  #
@@ -336,6 +336,24 @@ module Kitchen
336
336
  css_or_xpath: css_or_xpath, only: only, except: except)
337
337
  end
338
338
 
339
+ # Returns an enumerator that iterates through injected exercises within the scope of this enumerator
340
+ #
341
+ # @param css_or_xpath [String] additional selectors to further narrow the element iterated over;
342
+ # a "$" in this argument will be replaced with the default selector for the element being
343
+ # iterated over.
344
+ # @param only [Symbol, Callable] the name of a method to call on an element or a
345
+ # lambda or proc that accepts an element; elements will only be included in the
346
+ # search results if the method or callable returns true
347
+ # @param except [Symbol, Callable] the name of a method to call on an element or a
348
+ # lambda or proc that accepts an element; elements will not be included in the
349
+ # search results if the method or callable returns false
350
+ #
351
+ def injected_exercises(css_or_xpath=nil, only: nil, except: nil)
352
+ block_error_if(block_given?)
353
+ chain_to(InjectedExerciseElementEnumerator,
354
+ css_or_xpath: css_or_xpath, only: only, except: except)
355
+ end
356
+
339
357
  # Returns an enumerator that iterates within the scope of this enumerator
340
358
  #
341
359
  # @param css_or_xpath [String] additional selectors to further narrow the element iterated over
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ # An element for an example
5
+ #
6
+ class InjectedExerciseElement < ElementBase
7
+
8
+ # Creates a new +InjectedQuestionElement+
9
+ #
10
+ # @param node [Nokogiri::XML::Node] the node this element wraps
11
+ # @param document [Document] this element's document
12
+ #
13
+ def initialize(node:, document: nil)
14
+ super(node: node,
15
+ document: document,
16
+ enumerator_class: InjectedExerciseElementEnumerator)
17
+ end
18
+
19
+ # Returns the short type
20
+ # @return [Symbol]
21
+ #
22
+ def self.short_type
23
+ :injected_exercise
24
+ end
25
+
26
+ # Returns the exercise context element.
27
+ # @return [Element]
28
+ #
29
+ def exercise_context
30
+ first("div[data-type='exercise-context']")
31
+ end
32
+
33
+ # Returns the exercise question element.
34
+ # @return [Element]
35
+ #
36
+ def exercise_question
37
+ first("div[data-type='exercise-question']")
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ # An enumerator for example elements
5
+ #
6
+ class InjectedExerciseElementEnumerator < ElementEnumeratorBase
7
+
8
+ # Returns a factory for this enumerator
9
+ #
10
+ # @return [ElementEnumeratorFactory]
11
+ #
12
+ def self.factory
13
+ ElementEnumeratorFactory.new(
14
+ default_css_or_xpath: Selector.named(:injected_exercise),
15
+ sub_element_class: InjectedExerciseElement,
16
+ enumerator_class: self
17
+ )
18
+ end
19
+
20
+ end
21
+ end
@@ -55,6 +55,13 @@ module Kitchen
55
55
  first("div[data-type='question-solution']")
56
56
  end
57
57
 
58
+ # Returns the exercise context element.
59
+ # @return [Element]
60
+ #
61
+ def exercise_context_in_question
62
+ first("div[data-type='exercise-context']")
63
+ end
64
+
58
65
  # Returns the answer correctness given an alphabet
59
66
  #
60
67
  # @return [Array]
@@ -4,6 +4,10 @@ require 'twitter_cldr'
4
4
 
5
5
  # rubocop:disable Style/Documentation
6
6
  module I18n
7
+ def self.character_to_group(character)
8
+ I18n.locale == :pl ? character : I18n.transliterate(character)
9
+ end
10
+
7
11
  def self.sort_strings(first, second)
8
12
  string_sorter.compare(first, second)
9
13
  end
@@ -3,7 +3,22 @@
3
3
  # Monkey patches for +Integer+
4
4
  #
5
5
  class Integer
6
- ROMAN_NUMERALS = %w[0 i ii iii iv v vi vii viii ix x xi xii xiii xiv xv xvi xvii xviii xix xx].freeze
6
+
7
+ @roman_numerals = {
8
+ 100 => 'c',
9
+ 90 => 'xc',
10
+ 50 => 'l',
11
+ 40 => 'xl',
12
+ 10 => 'x',
13
+ 9 => 'ix',
14
+ 5 => 'v',
15
+ 4 => 'iv',
16
+ 1 => 'i'
17
+ }
18
+
19
+ class << self
20
+ attr_accessor :roman_numerals
21
+ end
7
22
 
8
23
  # Formats as different types of integers, including roman numerals.
9
24
  #
@@ -14,11 +29,25 @@ class Integer
14
29
  when :arabic
15
30
  to_s
16
31
  when :roman
17
- raise 'Unknown conversion to Roman numerals' if self >= ROMAN_NUMERALS.size
32
+ raise 'Unknown conversion to Roman numerals' if self > self.class.roman_numerals.keys.first
18
33
 
19
- ROMAN_NUMERALS[self]
34
+ to_roman
20
35
  else
21
36
  raise 'Unknown integer format'
22
37
  end
23
38
  end
39
+
40
+ def to_roman
41
+ return 0 if zero?
42
+
43
+ roman = ''
44
+ integer = self
45
+ self.class.roman_numerals.each do |number, letter|
46
+ until integer < number
47
+ roman += letter
48
+ integer -= number
49
+ end
50
+ end
51
+ roman
52
+ end
24
53
  end
@@ -67,11 +67,12 @@ module Nokogiri
67
67
  self[:class]&.split || []
68
68
  end
69
69
 
70
- def previous
71
- prev = previous_element
72
- return nil if prev.nil?
70
+ def preceded_by_text?
71
+ prev = previous_sibling
72
+ while !prev.nil? && prev.blank? do prev = prev.previous_sibling end
73
+ return false if prev.nil?
73
74
 
74
- prev.text? ? prev.previous : prev
75
+ prev.text?
75
76
  end
76
77
 
77
78
  def self.selector_to_css_nodes(selector)
@@ -65,6 +65,9 @@ module Kitchen
65
65
  # Selector for a section
66
66
  # @return [String]
67
67
  attr_accessor :section
68
+ # Selector for an injected exercise
69
+ # @return [String]
70
+ attr_accessor :injected_exercise
68
71
 
69
72
  # Override specific selectors
70
73
  #
@@ -30,6 +30,7 @@ module Kitchen
30
30
  "div[data-type='question-solution']"
31
31
  self.injected_question = "div[data-type='exercise-question']"
32
32
  self.section = 'section'
33
+ self.injected_exercise = "div[data-type='injected-exercise']"
33
34
  end
34
35
 
35
36
  end
@@ -3,5 +3,5 @@
3
3
  # A library for modifying the structure of OpenStax book XML.
4
4
  #
5
5
  module Kitchen
6
- VERSION = '15.0.0'
6
+ VERSION = '18.0.0'
7
7
  end
data/lib/locales/en.yml CHANGED
@@ -28,6 +28,7 @@ en:
28
28
  iframe_link_text: Click to view content
29
29
  handbook_outline_title: Outline
30
30
  context_lead_text: 'Refer to '
31
+ lo_label_text: 'LO '
31
32
  eoc:
32
33
  glossary: Key Terms
33
34
  key-equations: Key Equations
@@ -45,3 +46,18 @@ en:
45
46
  reference: References
46
47
  index:
47
48
  main: Index
49
+ annotation_icons:
50
+ linguistic-icon:
51
+ title: Language lens icon
52
+ culture-icon:
53
+ title: Culture lens icon
54
+ dreaming-icon:
55
+ title: Generating and capturing ideas icon
56
+ visual-icon:
57
+ title: Visual learning style icon
58
+ speech-icon:
59
+ title: Voice to text icon
60
+ auditory-icon:
61
+ title: Auditory learning style icon
62
+ kinesthetic-icon:
63
+ title: Kinesthetic learning style icon
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openstax_kitchen
3
3
  version: !ruby/object:Gem::Version
4
- version: 15.0.0
4
+ version: 18.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - JP Slavinsky
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-05 00:00:00.000000000 Z
11
+ date: 2022-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -252,6 +252,7 @@ files:
252
252
  - lib/kitchen/directions/bake_autotitled_exercise/main.rb
253
253
  - lib/kitchen/directions/bake_autotitled_exercise/v1.rb
254
254
  - lib/kitchen/directions/bake_autotitled_exercise/v2.rb
255
+ - lib/kitchen/directions/bake_autotitled_exercise/v3.rb
255
256
  - lib/kitchen/directions/bake_chapter_glossary/main.rb
256
257
  - lib/kitchen/directions/bake_chapter_glossary/v1.rb
257
258
  - lib/kitchen/directions/bake_chapter_introductions/bake_chapter_objectives.rb
@@ -264,6 +265,8 @@ files:
264
265
  - lib/kitchen/directions/bake_chapter_key_equations.rb
265
266
  - lib/kitchen/directions/bake_chapter_references/main.rb
266
267
  - lib/kitchen/directions/bake_chapter_references/v1.rb
268
+ - lib/kitchen/directions/bake_chapter_references/v2.rb
269
+ - lib/kitchen/directions/bake_chapter_references/v3.rb
267
270
  - lib/kitchen/directions/bake_chapter_section_exercises/main.rb
268
271
  - lib/kitchen/directions/bake_chapter_section_exercises/v1.rb
269
272
  - lib/kitchen/directions/bake_chapter_solutions/main.rb
@@ -280,6 +283,8 @@ files:
280
283
  - lib/kitchen/directions/bake_eoc_section_content/remove_section_title.rb
281
284
  - lib/kitchen/directions/bake_equations.rb
282
285
  - lib/kitchen/directions/bake_example.rb
286
+ - lib/kitchen/directions/bake_exercise_prefixes/main.rb
287
+ - lib/kitchen/directions/bake_exercise_prefixes/v1.rb
283
288
  - lib/kitchen/directions/bake_figure.rb
284
289
  - lib/kitchen/directions/bake_first_elements.rb
285
290
  - lib/kitchen/directions/bake_folio.rb
@@ -296,13 +301,14 @@ files:
296
301
  - lib/kitchen/directions/bake_index/main.rb
297
302
  - lib/kitchen/directions/bake_index/v1.rb
298
303
  - lib/kitchen/directions/bake_index/v1.xhtml.erb
299
- - lib/kitchen/directions/bake_injected_exercise.rb
300
304
  - lib/kitchen/directions/bake_injected_exercise/add_injected_exercise_id.rb
305
+ - lib/kitchen/directions/bake_injected_exercise/bake_injected_exercise.rb
301
306
  - lib/kitchen/directions/bake_injected_exercise/bake_injected_exercise_question.rb
302
307
  - lib/kitchen/directions/bake_inline_lists.rb
303
308
  - lib/kitchen/directions/bake_learning_objectives.rb
304
309
  - lib/kitchen/directions/bake_link_placeholders.rb
305
310
  - lib/kitchen/directions/bake_lists_with_para.rb
311
+ - lib/kitchen/directions/bake_lo_link_labels.rb
306
312
  - lib/kitchen/directions/bake_math_in_paragraph.rb
307
313
  - lib/kitchen/directions/bake_non_introduction_pages.rb
308
314
  - lib/kitchen/directions/bake_notes/bake_autotitled_notes.rb
@@ -326,6 +332,7 @@ files:
326
332
  - lib/kitchen/directions/bake_references/v1.rb
327
333
  - lib/kitchen/directions/bake_references/v2.rb
328
334
  - lib/kitchen/directions/bake_references/v3.rb
335
+ - lib/kitchen/directions/bake_screenreader_spans.rb
329
336
  - lib/kitchen/directions/bake_stepwise.rb
330
337
  - lib/kitchen/directions/bake_suggested_reading.rb
331
338
  - lib/kitchen/directions/bake_toc.rb
@@ -373,6 +380,8 @@ files:
373
380
  - lib/kitchen/figure_element_enumerator.rb
374
381
  - lib/kitchen/i18n_string.rb
375
382
  - lib/kitchen/id_tracker.rb
383
+ - lib/kitchen/injected_exercise_element.rb
384
+ - lib/kitchen/injected_exercise_element_enumerator.rb
376
385
  - lib/kitchen/injected_question_element.rb
377
386
  - lib/kitchen/injected_question_element_enumerator.rb
378
387
  - lib/kitchen/metadata_element.rb