openstax_kitchen 14.0.0 → 17.1.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 +47 -3
- data/Gemfile.lock +4 -4
- data/codecov.yaml +4 -0
- data/lib/kitchen/directions/bake_all_chapter_solutions_types.rb +30 -0
- data/lib/kitchen/directions/bake_all_numbered_exercise_types.rb +26 -0
- data/lib/kitchen/directions/bake_annotation_classes/v1.rb +11 -2
- data/lib/kitchen/directions/bake_autotitled_exercise/main.rb +4 -0
- data/lib/kitchen/directions/bake_autotitled_exercise/v3.rb +35 -0
- data/lib/kitchen/directions/bake_chapter_references/main.rb +15 -0
- data/lib/kitchen/directions/bake_chapter_references/v2.rb +53 -0
- data/lib/kitchen/directions/bake_chapter_references/v3.rb +45 -0
- data/lib/kitchen/directions/bake_chapter_summary.rb +5 -4
- data/lib/kitchen/directions/bake_example.rb +1 -1
- data/lib/kitchen/directions/bake_exercise_prefixes/main.rb +14 -0
- data/lib/kitchen/directions/bake_exercise_prefixes/v1.rb +22 -0
- data/lib/kitchen/directions/bake_footnotes/v1.rb +1 -1
- data/lib/kitchen/directions/bake_index/v1.rb +13 -8
- data/lib/kitchen/directions/bake_index/v1.xhtml.erb +6 -10
- data/lib/kitchen/directions/{bake_injected_exercise.rb → bake_injected_exercise/bake_injected_exercise.rb} +10 -1
- data/lib/kitchen/directions/bake_injected_exercise/bake_injected_exercise_question.rb +4 -0
- data/lib/kitchen/directions/bake_link_placeholders.rb +1 -1
- data/lib/kitchen/directions/bake_lo_link_labels.rb +19 -0
- data/lib/kitchen/directions/bake_non_introduction_pages.rb +3 -1
- data/lib/kitchen/directions/bake_numbered_exercise/main.rb +8 -3
- data/lib/kitchen/directions/bake_numbered_exercise/v1.rb +48 -7
- data/lib/kitchen/directions/bake_numbered_table/bake_table_body.rb +5 -1
- data/lib/kitchen/directions/bake_numbered_table/v2.rb +2 -1
- data/lib/kitchen/directions/bake_references/v1.rb +13 -0
- data/lib/kitchen/directions/bake_screenreader_spans.rb +22 -0
- data/lib/kitchen/directions/bake_unnumbered_exercise.rb +16 -0
- data/lib/kitchen/directions/book_answer_key_container/eob_answer_key_container.xhtml.erb +9 -0
- data/lib/kitchen/directions/book_answer_key_container/v1.rb +6 -2
- data/lib/kitchen/directions/default_strategy_for_answer_key_solutions.rb +35 -0
- data/lib/kitchen/directions/move_solutions_to_answer_key/answer_key_inner_container.rb +29 -0
- data/lib/kitchen/element_base.rb +25 -5
- data/lib/kitchen/element_enumerator_base.rb +18 -0
- data/lib/kitchen/injected_exercise_element.rb +41 -0
- data/lib/kitchen/injected_exercise_element_enumerator.rb +21 -0
- data/lib/kitchen/injected_question_element.rb +7 -0
- data/lib/kitchen/patches/i18n.rb +4 -0
- data/lib/kitchen/patches/integer.rb +32 -3
- data/lib/kitchen/patches/nokogiri.rb +5 -4
- data/lib/kitchen/patches/renderable.rb +1 -1
- data/lib/kitchen/selectors/base.rb +3 -0
- data/lib/kitchen/selectors/standard_1.rb +1 -0
- data/lib/kitchen/version.rb +1 -1
- data/lib/locales/en.yml +16 -0
- data/lib/locales/es.yml +6 -1
- metadata +18 -11
- data/lib/kitchen/directions/book_answer_key_container/eob_answer_key_outer_container.xhtml.erb +0 -9
- data/lib/kitchen/directions/move_solutions_to_answer_key/main.rb +0 -18
- data/lib/kitchen/directions/move_solutions_to_answer_key/strategies/calculus.rb +0 -41
- data/lib/kitchen/directions/move_solutions_to_answer_key/strategies/contemporary_math.rb +0 -40
- data/lib/kitchen/directions/move_solutions_to_answer_key/strategies/default.rb +0 -27
- data/lib/kitchen/directions/move_solutions_to_answer_key/strategies/precalculus.rb +0 -63
- data/lib/kitchen/directions/move_solutions_to_answer_key/strategies/uphysics.rb +0 -21
- data/lib/kitchen/directions/move_solutions_to_answer_key/v1.rb +0 -47
@@ -3,14 +3,19 @@
|
|
3
3
|
module Kitchen
|
4
4
|
module Directions
|
5
5
|
module BakeNumberedExercise
|
6
|
+
# rubocop:disable Metrics/ParameterLists
|
7
|
+
# :/
|
6
8
|
def self.v1(exercise:, number:, suppress_solution_if: false,
|
7
|
-
note_suppressed_solutions: false, cases: false)
|
9
|
+
note_suppressed_solutions: false, cases: false, solution_stays_put: false)
|
8
10
|
V1.new.bake(exercise: exercise, number: number, suppress_solution_if: suppress_solution_if,
|
9
|
-
note_suppressed_solutions: note_suppressed_solutions, cases: cases
|
11
|
+
note_suppressed_solutions: note_suppressed_solutions, cases: cases,
|
12
|
+
solution_stays_put: solution_stays_put)
|
10
13
|
end
|
14
|
+
# rubocop:enable Metrics/ParameterLists
|
11
15
|
|
12
16
|
def self.bake_solution_v1(exercise:, number:, divider: '. ')
|
13
|
-
V1.new.bake_solution(exercise: exercise, number: number, divider: divider
|
17
|
+
V1.new.bake_solution(exercise: exercise, number: number, divider: divider,
|
18
|
+
solution_stays_put: false)
|
14
19
|
end
|
15
20
|
end
|
16
21
|
end
|
@@ -2,13 +2,25 @@
|
|
2
2
|
|
3
3
|
module Kitchen::Directions::BakeNumberedExercise
|
4
4
|
class V1
|
5
|
-
|
6
|
-
|
5
|
+
# rubocop:disable Metrics/ParameterLists
|
6
|
+
def bake(exercise:, number:, suppress_solution_if:,
|
7
|
+
note_suppressed_solutions:, cases:, solution_stays_put:)
|
7
8
|
problem = exercise.problem
|
8
9
|
solution = exercise.solution
|
9
10
|
|
11
|
+
in_appendix = exercise.has_ancestor?(:page) && exercise.ancestor(:page).has_class?('appendix')
|
12
|
+
|
10
13
|
# Store label information
|
11
|
-
|
14
|
+
if in_appendix
|
15
|
+
label_number = number
|
16
|
+
title_label = "<span class=\"os-title-label\">#{I18n.t('exercise')}</span>"
|
17
|
+
problem_divider = ''
|
18
|
+
else
|
19
|
+
label_number = "#{exercise.ancestor(:chapter).count_in(:book)}.#{number}"
|
20
|
+
title_label = ''
|
21
|
+
problem_divider = "<span class='os-divider'>. </span>"
|
22
|
+
end
|
23
|
+
|
12
24
|
exercise.target_label(label_text: 'exercise', custom_content: label_number, cases: cases)
|
13
25
|
|
14
26
|
problem_number = "<span class='os-number'>#{number}</span>"
|
@@ -26,25 +38,54 @@ module Kitchen::Directions::BakeNumberedExercise
|
|
26
38
|
solution.trash
|
27
39
|
exercise.add_class('os-hasSolution-trashed') if note_suppressed_solutions
|
28
40
|
else
|
29
|
-
problem_number =
|
30
|
-
|
41
|
+
problem_number = \
|
42
|
+
if solution_stays_put || in_appendix
|
43
|
+
"<span class='os-number'>#{number}</span>"
|
44
|
+
else
|
45
|
+
"<a class='os-number' href='##{exercise.id}-solution'>#{number}</a>"
|
46
|
+
end
|
47
|
+
bake_solution(
|
48
|
+
exercise: exercise,
|
49
|
+
number: number,
|
50
|
+
solution_stays_put: solution_stays_put,
|
51
|
+
in_appendix: in_appendix
|
52
|
+
)
|
31
53
|
end
|
32
54
|
end
|
33
55
|
|
34
56
|
problem.replace_children(with:
|
35
57
|
<<~HTML
|
58
|
+
#{title_label}
|
36
59
|
#{problem_number}
|
37
|
-
|
60
|
+
#{problem_divider}
|
38
61
|
<div class="os-problem-container">#{problem.children}</div>
|
39
62
|
HTML
|
40
63
|
)
|
41
64
|
end
|
65
|
+
# rubocop:enable Metrics/ParameterLists
|
42
66
|
|
43
|
-
def bake_solution(exercise:, number:, divider: '. ')
|
67
|
+
def bake_solution(exercise:, number:, solution_stays_put:, divider: '. ', in_appendix: false)
|
44
68
|
solution = exercise.solution
|
69
|
+
if solution_stays_put
|
70
|
+
solution.wrap_children(class: 'os-solution-container')
|
71
|
+
solution.prepend(child:
|
72
|
+
<<~HTML
|
73
|
+
<h4 class="solution-title" data-type="title">
|
74
|
+
<span class="os-text">#{I18n.t(:solution)}</span>
|
75
|
+
</h4>
|
76
|
+
HTML
|
77
|
+
)
|
78
|
+
return
|
79
|
+
end
|
80
|
+
|
45
81
|
solution.id = "#{exercise.id}-solution"
|
46
82
|
exercise.add_class('os-hasSolution')
|
47
83
|
|
84
|
+
if in_appendix
|
85
|
+
solution.wrap_children(class: 'os-solution-container')
|
86
|
+
return
|
87
|
+
end
|
88
|
+
|
48
89
|
solution.replace_children(with:
|
49
90
|
<<~HTML
|
50
91
|
<a class='os-number' href='##{exercise.id}'>#{number}</a>
|
@@ -44,8 +44,9 @@ module Kitchen
|
|
44
44
|
table.target_label(label_text: 'table', custom_content: number, cases: cases)
|
45
45
|
|
46
46
|
if table.top_titled?
|
47
|
+
klass = table.text_heavy? ? 'text-heavy-top-titled' : 'top-titled'
|
47
48
|
custom_table = CustomBody.new(table: table,
|
48
|
-
klass:
|
49
|
+
klass: klass,
|
49
50
|
fake_title_class: 'os-table-title',
|
50
51
|
fake_title: table.title,
|
51
52
|
to_trash: table.title_row)
|
@@ -65,6 +66,9 @@ module Kitchen
|
|
65
66
|
elsif table.text_heavy?
|
66
67
|
custom_table = CustomBody.new(table: table, klass: 'text-heavy')
|
67
68
|
custom_table.modify_body(has_fake_title: false)
|
69
|
+
elsif table.unstyled?
|
70
|
+
custom_table = CustomBody.new(table: table, klass: 'unstyled')
|
71
|
+
custom_table.modify_body(has_fake_title: false)
|
68
72
|
end
|
69
73
|
end
|
70
74
|
end
|
@@ -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']")
|
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
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen
|
4
|
+
module Directions
|
5
|
+
module BakeUnnumberedExercise
|
6
|
+
def self.v1(exercise:)
|
7
|
+
exercise.problem.wrap_children(class: 'os-problem-container')
|
8
|
+
return unless exercise.solution
|
9
|
+
|
10
|
+
exercise.solutions.each do |solution|
|
11
|
+
solution.wrap_children(class: 'os-solution-container')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<div class="os-eob os-<%= @solutions_or_solution %>-container" data-type="<%= @composite_element %>" data-uuid-key=".<%= @uuid_key %>">
|
2
|
+
<<%= @main_title_tag %> data-type="document-title">
|
3
|
+
<span class="os-text"><%= @title %></span>
|
4
|
+
</<%= @main_title_tag %>>
|
5
|
+
<div data-type="metadata" style="display: none;">
|
6
|
+
<h1 data-type="document-title" itemprop="name"><%= @title %></h1>
|
7
|
+
<%= @metadata.paste %>
|
8
|
+
</div>
|
9
|
+
</div>
|
@@ -4,10 +4,14 @@ module Kitchen::Directions::BookAnswerKeyContainer
|
|
4
4
|
class V1
|
5
5
|
renderable
|
6
6
|
|
7
|
-
def bake(book:, solutions_plural:
|
7
|
+
def bake(book:, solutions_plural:)
|
8
|
+
@composite_element = 'composite-chapter'
|
8
9
|
@metadata = book.metadata.children_to_keep.copy
|
9
10
|
@solutions_or_solution = solutions_plural ? 'solutions' : 'solution'
|
10
|
-
|
11
|
+
@title = I18n.t(:answer_key_title)
|
12
|
+
@main_title_tag = 'h1'
|
13
|
+
@uuid_key = @solutions_or_solution
|
14
|
+
book.body.append(child: render(file: 'eob_answer_key_container.xhtml.erb'))
|
11
15
|
book.body.first("div.os-eob.os-#{@solutions_or_solution}-container")
|
12
16
|
end
|
13
17
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen::Directions::DefaultStrategyForAnswerKeySolutions
|
4
|
+
def self.v1(strategy_options:, chapter:, append_to:)
|
5
|
+
V1.new(
|
6
|
+
strategy_options
|
7
|
+
).bake(
|
8
|
+
chapter: chapter,
|
9
|
+
append_to: append_to
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
class V1
|
14
|
+
def bake(chapter:, append_to:)
|
15
|
+
bake_section(chapter: chapter, append_to: append_to)
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def bake_section(chapter:, append_to:)
|
21
|
+
@selectors.each do |selector|
|
22
|
+
chapter.search("#{selector} div[data-type='solution']").each do |solution|
|
23
|
+
append_to.append(child: solution.cut.to_s) unless @condition.present? && !@condition
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# This method helps to obtain more strategy-specific params through
|
29
|
+
# "strategy_options: {blah1: 1, blah2: 2}"
|
30
|
+
def initialize(strategy_options)
|
31
|
+
@selectors = strategy_options[:selectors] || (raise 'missing selectors for strategy')
|
32
|
+
@condition = strategy_options[:condition]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen::Directions::AnswerKeyInnerContainer
|
4
|
+
def self.v1(chapter:, metadata_source:, append_to:, solutions_plural: true)
|
5
|
+
V1.new.bake(
|
6
|
+
chapter: chapter,
|
7
|
+
metadata_source: metadata_source,
|
8
|
+
append_to: append_to,
|
9
|
+
solutions_plural: solutions_plural
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
class V1
|
14
|
+
renderable
|
15
|
+
|
16
|
+
def bake(chapter:, metadata_source:, append_to:, solutions_plural:)
|
17
|
+
@solutions_or_solution = solutions_plural ? 'solutions' : 'solution'
|
18
|
+
@uuid_key = "#{@solutions_or_solution}#{chapter.count_in(:book)}"
|
19
|
+
@metadata = metadata_source.children_to_keep.copy
|
20
|
+
@composite_element = 'composite-page'
|
21
|
+
@title = "#{I18n.t(:chapter)} #{chapter.count_in(:book)}"
|
22
|
+
@main_title_tag = 'h2'
|
23
|
+
|
24
|
+
append_to.append(
|
25
|
+
child: render(file: '../book_answer_key_container/eob_answer_key_container.xhtml.erb')
|
26
|
+
).first("div[data-uuid-key='.#{@uuid_key}']")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/kitchen/element_base.rb
CHANGED
@@ -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
|
-
#
|
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.
|
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]
|
data/lib/kitchen/patches/i18n.rb
CHANGED
@@ -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
|
-
|
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
|
32
|
+
raise 'Unknown conversion to Roman numerals' if self > self.class.roman_numerals.keys.first
|
18
33
|
|
19
|
-
|
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
|
71
|
-
prev =
|
72
|
-
|
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?
|
75
|
+
prev.text?
|
75
76
|
end
|
76
77
|
|
77
78
|
def self.selector_to_css_nodes(selector)
|
data/lib/kitchen/version.rb
CHANGED
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
|
data/lib/locales/es.yml
CHANGED
@@ -21,17 +21,22 @@ es:
|
|
21
21
|
eoc_exercises_title: Ejercicios
|
22
22
|
eoc_composite_metadata_title: Revisión Del Capítulo
|
23
23
|
eoc_solutions_title: Soluciones
|
24
|
-
eoc_key_concepts: Conceptos Clave
|
25
24
|
eoc_suggested_reading: Sugerencias Para Estudios Adicionales
|
26
25
|
eob_index_symbols_group: Símbolos
|
27
26
|
review_exercises: Ejercicios De Repaso
|
28
27
|
section_exercises: ! 'Sección %{number} Ejercicios'
|
28
|
+
iframe_link_text: Haga Clic Para Ver El Contenido
|
29
|
+
handbook_outline_title: Esquema
|
30
|
+
context_lead_text: 'Referirse a '
|
29
31
|
eoc:
|
30
32
|
glossary: Términos Clave
|
31
33
|
key-equations: Ecuaciones Clave
|
32
34
|
summary: Resumen
|
33
35
|
further-research: Investigación Adicional
|
36
|
+
key-concepts: Conceptos Clave
|
34
37
|
references: Referencias
|
38
|
+
solutions: Soluciones
|
39
|
+
section-exercises: ! 'Sección %{number} Ejercicios'
|
35
40
|
folio:
|
36
41
|
preface: Prefacio
|
37
42
|
access_for_free: Acceso gratis en openstax.org
|