openstax_kitchen 3.0.0 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -3
- data/Gemfile.lock +1 -1
- data/README.md +7 -0
- data/lib/kitchen/directions/bake_book_answer_key/eob_solutions_container.xhtml.erb +9 -0
- data/lib/kitchen/directions/bake_book_answer_key/main.rb +11 -0
- data/lib/kitchen/directions/bake_book_answer_key/v1.rb +13 -0
- data/lib/kitchen/directions/bake_chapter_answer_key/main.rb +14 -0
- data/lib/kitchen/directions/bake_chapter_answer_key/strategies/calculus.rb +41 -0
- data/lib/kitchen/directions/bake_chapter_answer_key/strategies/uphysics.rb +61 -0
- data/lib/kitchen/directions/bake_chapter_answer_key/v1.rb +32 -0
- data/lib/kitchen/directions/bake_chapter_glossary.rb +4 -2
- data/lib/kitchen/directions/bake_chapter_key_concepts/key_concepts.xhtml.erb +16 -0
- data/lib/kitchen/directions/bake_chapter_key_concepts/main.rb +11 -0
- data/lib/kitchen/directions/bake_chapter_key_concepts/v1.rb +30 -0
- data/lib/kitchen/directions/bake_chapter_key_equations.rb +4 -2
- data/lib/kitchen/directions/bake_chapter_review/chapter_review.xhtml.erb +9 -0
- data/lib/kitchen/directions/bake_chapter_review/main.rb +11 -0
- data/lib/kitchen/directions/bake_chapter_review/v1.rb +13 -0
- data/lib/kitchen/directions/bake_chapter_review_exercises/main.rb +15 -0
- data/lib/kitchen/directions/bake_chapter_review_exercises/review_exercises.xhtml.erb +10 -0
- data/lib/kitchen/directions/bake_chapter_review_exercises/v1.rb +38 -0
- data/lib/kitchen/directions/bake_chapter_review_exercises/v2.rb +50 -0
- data/lib/kitchen/directions/bake_chapter_section_exercises/main.rb +11 -0
- data/lib/kitchen/directions/bake_chapter_section_exercises/v1.rb +28 -0
- data/lib/kitchen/directions/bake_chapter_summary.rb +1 -1
- data/lib/kitchen/directions/bake_checkpoint.rb +44 -0
- data/lib/kitchen/directions/bake_composite_chapters.rb +14 -0
- data/lib/kitchen/directions/bake_equations.rb +27 -0
- data/lib/kitchen/directions/bake_example.rb +29 -7
- data/lib/kitchen/directions/bake_exercises/main.rb +1 -0
- data/lib/kitchen/directions/bake_exercises/v1.rb +34 -31
- data/lib/kitchen/directions/bake_non_introduction_pages.rb +26 -0
- data/lib/kitchen/directions/bake_notes/bake_autotitled_notes.rb +29 -0
- data/lib/kitchen/directions/bake_notes/bake_note_subtitle.rb +18 -0
- data/lib/kitchen/directions/{bake_notes.rb → bake_notes/bake_notes.rb} +6 -16
- data/lib/kitchen/directions/bake_notes/bake_numbered_notes.rb +63 -0
- data/lib/kitchen/directions/bake_notes/bake_unclassified_notes.rb +30 -0
- data/lib/kitchen/directions/bake_numbered_exercise/main.rb +11 -0
- data/lib/kitchen/directions/bake_numbered_exercise/v1.rb +34 -0
- data/lib/kitchen/directions/bake_numbered_table/main.rb +2 -2
- data/lib/kitchen/directions/bake_numbered_table/v1.rb +17 -3
- data/lib/kitchen/directions/bake_page_abstracts.rb +16 -0
- data/lib/kitchen/directions/bake_problem_first_elements.rb +16 -0
- data/lib/kitchen/directions/bake_stepwise.rb +1 -5
- data/lib/kitchen/directions/bake_theorem/main.rb +11 -0
- data/lib/kitchen/directions/bake_theorem/v1.rb +28 -0
- data/lib/kitchen/directions/bake_toc.rb +6 -0
- data/lib/kitchen/directions/eoc_section_title_link_snippet.rb +20 -0
- data/lib/kitchen/element_base.rb +40 -1
- data/lib/kitchen/element_enumerator_base.rb +87 -8
- data/lib/kitchen/exercise_element.rb +45 -0
- data/lib/kitchen/exercise_element_enumerator.rb +21 -0
- data/lib/kitchen/note_element.rb +17 -16
- data/lib/kitchen/page_element.rb +8 -0
- data/lib/kitchen/recipe.rb +35 -2
- data/lib/kitchen/version.rb +1 -1
- data/lib/locales/en.yml +9 -7
- data/lib/locales/pl.yml +24 -0
- data/lib/openstax_kitchen.rb +1 -1
- metadata +39 -3
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen
|
4
|
+
module Directions
|
5
|
+
module BakeNoteSubtitle
|
6
|
+
def self.v1(note:)
|
7
|
+
title = note.title&.cut
|
8
|
+
|
9
|
+
return unless title
|
10
|
+
|
11
|
+
title.name = 'h4'
|
12
|
+
title.add_class('os-subtitle')
|
13
|
+
title.wrap_children('span', class: 'os-subtitle-label')
|
14
|
+
note.first!('.os-note-body').prepend(child: title.to_s)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -4,14 +4,12 @@ module Kitchen
|
|
4
4
|
module Directions
|
5
5
|
module BakeNotes
|
6
6
|
def self.v1(book:)
|
7
|
-
|
7
|
+
warn 'WARNING! deprecated direction used: BakeNotes'
|
8
|
+
|
9
|
+
book.notes('$:not(.checkpoint):not(.theorem)').each do |note|
|
8
10
|
title = note.title&.cut
|
9
11
|
|
10
|
-
note.
|
11
|
-
<<~HTML
|
12
|
-
<div class="os-note-body">#{note.children}</div>
|
13
|
-
HTML
|
14
|
-
)
|
12
|
+
note.wrap_children(class: 'os-note-body')
|
15
13
|
|
16
14
|
if title
|
17
15
|
if note.indicates_autogenerated_title?
|
@@ -25,20 +23,12 @@ module Kitchen
|
|
25
23
|
|
26
24
|
title.name = 'h4'
|
27
25
|
title.add_class('os-subtitle')
|
28
|
-
title.
|
29
|
-
<<~HTML
|
30
|
-
<span class="os-subtitle-label">#{title.children}</span>
|
31
|
-
HTML
|
32
|
-
)
|
26
|
+
title.wrap_children('span', class: 'os-subtitle-label')
|
33
27
|
note.first!('.os-note-body').prepend(child: title.raw)
|
34
28
|
else
|
35
29
|
title.name = 'h3'
|
36
30
|
title.add_class('os-title')
|
37
|
-
title.
|
38
|
-
<<~HTML
|
39
|
-
<span data-type="" id="#{title.id}" class="os-title-label">#{title.children}</span>
|
40
|
-
HTML
|
41
|
-
)
|
31
|
+
title.wrap_children('span', data_type: '', id: title.id, class: 'os-title-label')
|
42
32
|
title.remove_attribute('id')
|
43
33
|
note.prepend(child: title.raw)
|
44
34
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen
|
4
|
+
module Directions
|
5
|
+
module BakeNumberedNotes
|
6
|
+
def self.v1(book:, classes:)
|
7
|
+
classes.each do |klass|
|
8
|
+
book.chapters.notes("$.#{klass}").each do |note|
|
9
|
+
bake_note(note: note)
|
10
|
+
bake_note_exercise(note: note)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.bake_note(note:)
|
16
|
+
note.wrap_children(class: 'os-note-body')
|
17
|
+
|
18
|
+
chapter_count = note.ancestor(:chapter).count_in(:book)
|
19
|
+
note_count = note.count_in(:chapter)
|
20
|
+
note.prepend(child:
|
21
|
+
<<~HTML
|
22
|
+
<div class="os-title">
|
23
|
+
<span class="os-title-label">#{note.autogenerated_title}</span>
|
24
|
+
<span class="os-number">#{chapter_count}.#{note_count}</span>
|
25
|
+
<span class="os-divider"> </span>
|
26
|
+
</div>
|
27
|
+
HTML
|
28
|
+
)
|
29
|
+
|
30
|
+
return unless note['use-subtitle']
|
31
|
+
|
32
|
+
BakeNoteSubtitle.v1(note: note)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.bake_note_exercise(note:)
|
36
|
+
exercise = note.exercises.first
|
37
|
+
return unless exercise
|
38
|
+
|
39
|
+
exercise.add_class('unnumbered')
|
40
|
+
# bake problem
|
41
|
+
exercise.problem.wrap_children('div', class: 'os-problem-container')
|
42
|
+
exercise.problem.first('strong')&.trash
|
43
|
+
exercise.search('[data-type="commentary"]').each(&:trash)
|
44
|
+
solution = exercise.solution
|
45
|
+
return unless solution
|
46
|
+
|
47
|
+
# bake solution in place
|
48
|
+
exercise.add_class('os-hasSolution')
|
49
|
+
solution[:id] = "#{exercise[:id]}-solution"
|
50
|
+
solution_number = note.first('.os-number').text
|
51
|
+
solution.replace_children(with:
|
52
|
+
<<~HTML
|
53
|
+
<a class="os-number" href="##{exercise[:id]}">#{solution_number}</a>
|
54
|
+
<span class="os-divider"> </span>
|
55
|
+
<div class="os-solution-container">
|
56
|
+
#{solution.children}
|
57
|
+
</div>
|
58
|
+
HTML
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen
|
4
|
+
module Directions
|
5
|
+
module BakeUnclassifiedNotes
|
6
|
+
def self.v1(book:)
|
7
|
+
book.notes.each do |note|
|
8
|
+
next unless note.classes.empty?
|
9
|
+
|
10
|
+
bake_note(note: note)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.bake_note(note:)
|
15
|
+
note.wrap_children(class: 'os-note-body')
|
16
|
+
|
17
|
+
title = note.title&.cut
|
18
|
+
return unless title
|
19
|
+
|
20
|
+
note.prepend(child:
|
21
|
+
<<~HTML
|
22
|
+
<h3 class="os-title" data-type="title">
|
23
|
+
<span class="os-title-label" data-type="" id="#{title[:id]}">#{title.children}</span>
|
24
|
+
</h3>
|
25
|
+
HTML
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen::Directions::BakeNumberedExercise
|
4
|
+
class V1
|
5
|
+
def bake(exercise:, number:)
|
6
|
+
problem = exercise.problem
|
7
|
+
solution = exercise.solution
|
8
|
+
|
9
|
+
problem_number = "<span class='os-number'>#{number}</span>"
|
10
|
+
|
11
|
+
if solution.present?
|
12
|
+
solution.id = "#{exercise.id}-solution"
|
13
|
+
exercise.add_class('os-hasSolution')
|
14
|
+
problem_number = "<a class='os-number' href='##{exercise.id}-solution'>#{number}</a>"
|
15
|
+
|
16
|
+
solution.replace_children(with:
|
17
|
+
<<~HTML
|
18
|
+
<a class='os-number' href='##{exercise.id}'>#{number}</a>
|
19
|
+
<span class='os-divider'>. </span>
|
20
|
+
<div class="os-solution-container">#{solution.children}</div>
|
21
|
+
HTML
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
problem.replace_children(with:
|
26
|
+
<<~HTML
|
27
|
+
#{problem_number}
|
28
|
+
<span class='os-divider'>. </span>
|
29
|
+
<div class="os-problem-container">#{problem.children}</div>
|
30
|
+
HTML
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -3,8 +3,8 @@
|
|
3
3
|
module Kitchen
|
4
4
|
module Directions
|
5
5
|
module BakeNumberedTable
|
6
|
-
def self.v1(table:, number:)
|
7
|
-
V1.new.bake(table: table, number: number)
|
6
|
+
def self.v1(table:, number:, always_caption: false)
|
7
|
+
V1.new.bake(table: table, number: number, always_caption: always_caption)
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Kitchen::Directions::BakeNumberedTable
|
4
4
|
class V1
|
5
5
|
|
6
|
-
def bake(table:, number:)
|
6
|
+
def bake(table:, number:, always_caption: false)
|
7
7
|
table.wrap(%(<div class="os-table">))
|
8
8
|
|
9
9
|
table_label = "#{I18n.t(:table_label)} #{number}"
|
@@ -22,14 +22,28 @@ module Kitchen::Directions::BakeNumberedTable
|
|
22
22
|
table.parent.add_class('os-column-header-container') if table.column_header?
|
23
23
|
|
24
24
|
# TODO: extra spaces added here to match legacy implementation, but probably not meaningful?
|
25
|
-
new_summary = "#{table_label}
|
25
|
+
new_summary = "#{table_label} "
|
26
26
|
new_caption = ''
|
27
|
+
caption_title = ''
|
28
|
+
|
29
|
+
if (title = table.first("span[data-type='title']")&.cut)
|
30
|
+
new_summary += title.text
|
31
|
+
caption_title = <<~HTML
|
32
|
+
\n<span class="os-title" data-type="title">#{title.children}</span>
|
33
|
+
HTML
|
34
|
+
end
|
35
|
+
|
36
|
+
new_summary += ' '
|
27
37
|
|
28
38
|
if (caption = table.caption&.cut)
|
29
39
|
new_summary += caption.text
|
30
40
|
new_caption = <<~HTML
|
31
41
|
\n<span class="os-caption">#{caption.children}</span>
|
32
42
|
HTML
|
43
|
+
elsif always_caption
|
44
|
+
new_caption = <<~HTML
|
45
|
+
\n<span class="os-caption"></span>
|
46
|
+
HTML
|
33
47
|
end
|
34
48
|
|
35
49
|
table[:summary] = new_summary
|
@@ -41,7 +55,7 @@ module Kitchen::Directions::BakeNumberedTable
|
|
41
55
|
<div class="os-caption-container">
|
42
56
|
<span class="os-title-label">#{I18n.t(:table_label)} </span>
|
43
57
|
<span class="os-number">#{number}</span>
|
44
|
-
<span class="os-divider"> </span
|
58
|
+
<span class="os-divider"> </span>#{caption_title}
|
45
59
|
<span class="os-divider"> </span>#{new_caption}
|
46
60
|
</div>
|
47
61
|
HTML
|
@@ -9,6 +9,22 @@ module Kitchen
|
|
9
9
|
abstract.prepend(child: "<h3 data-type='title'>#{I18n.t(:learning_objectives)}</h3>")
|
10
10
|
end
|
11
11
|
end
|
12
|
+
|
13
|
+
def self.v2(chapter:)
|
14
|
+
chapter.abstracts.each do |abstract|
|
15
|
+
abstract.prepend(child: "<h3 data-type='title'>#{I18n.t(:learning_objectives)}</h3>")
|
16
|
+
ul = abstract.first!('ul')
|
17
|
+
ul.add_class('os-abstract')
|
18
|
+
ul.search('li').each_with_index do |li, index|
|
19
|
+
li.replace_children(with:
|
20
|
+
<<~HTML
|
21
|
+
<span class="os-abstract-token">#{chapter.count_in(:book)}.#{abstract.count_in(:chapter)}.#{index + 1}</span>
|
22
|
+
<span class="os-abstract-content">#{li.text}</span>
|
23
|
+
HTML
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
12
28
|
end
|
13
29
|
end
|
14
30
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen
|
4
|
+
module Directions
|
5
|
+
module BakeProblemFirstElements
|
6
|
+
def self.v1(within:, selectors:)
|
7
|
+
selectors.each do |selector|
|
8
|
+
within.search(".os-problem-container > #{selector}:first-child").each do |problem|
|
9
|
+
problem.add_class('first-element')
|
10
|
+
problem.parent.add_class('has-first-element')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -9,11 +9,7 @@ module Kitchen
|
|
9
9
|
ol.add_class('os-stepwise')
|
10
10
|
|
11
11
|
ol.search('li').each_with_index do |li, ii|
|
12
|
-
li.
|
13
|
-
<<~HTML
|
14
|
-
<span class="os-stepwise-content">#{li.children}</span>
|
15
|
-
HTML
|
16
|
-
)
|
12
|
+
li.wrap_children('span', class: 'os-stepwise-content')
|
17
13
|
li.prepend(child:
|
18
14
|
<<~HTML
|
19
15
|
<span class="os-stepwise-token">#{I18n.t(:stepwise_step_label)} #{ii + 1}. </span>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen::Directions::BakeTheorem
|
4
|
+
class V1
|
5
|
+
def bake(theorem:, number:)
|
6
|
+
theorem['use-subtitle'] = true
|
7
|
+
new_subtitle = theorem.title.cut
|
8
|
+
|
9
|
+
theorem.wrap_children(class: 'os-note-body')
|
10
|
+
note_body = theorem.first('.os-note-body')
|
11
|
+
|
12
|
+
note_body.prepend(sibling:
|
13
|
+
<<~HTML
|
14
|
+
<div class="os-title">
|
15
|
+
<span class="os-title-label">#{I18n.t(:theorem)} </span>
|
16
|
+
<span class="os-number">#{number}</span>
|
17
|
+
<span class="os-divider"> </span>
|
18
|
+
</div>
|
19
|
+
HTML
|
20
|
+
)
|
21
|
+
|
22
|
+
new_subtitle.name = 'h4'
|
23
|
+
new_subtitle.add_class('os-subtitle')
|
24
|
+
new_subtitle.children.wrap('<span class="os-subtitle-label">')
|
25
|
+
note_body.prepend(child: new_subtitle.paste)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -59,6 +59,7 @@ module Kitchen
|
|
59
59
|
|
60
60
|
def self.li_for_chapter(chapter)
|
61
61
|
pages = chapter.element_children.only(PageElement, CompositePageElement)
|
62
|
+
inner_composite_chapters = chapter.element_children.only(CompositeChapterElement)
|
62
63
|
|
63
64
|
<<~HTML
|
64
65
|
<li class="os-toc-chapter" cnx-archive-shortid="" cnx-archive-uri="">
|
@@ -69,6 +70,11 @@ module Kitchen
|
|
69
70
|
</a>
|
70
71
|
<ol class="os-chapter">
|
71
72
|
#{pages.map { |page| li_for_page(page) }.join("\n")}
|
73
|
+
#{
|
74
|
+
inner_composite_chapters.map do |composite_chapter|
|
75
|
+
li_for_composite_chapter(composite_chapter)
|
76
|
+
end.join("\n")
|
77
|
+
}
|
72
78
|
</ol>
|
73
79
|
</li>
|
74
80
|
HTML
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kitchen
|
4
|
+
module Directions
|
5
|
+
module EocSectionTitleLinkSnippet
|
6
|
+
def self.v1(page:)
|
7
|
+
chapter = page.ancestor(:chapter)
|
8
|
+
<<~HTML
|
9
|
+
<a href="##{page.title.id}">
|
10
|
+
<h3 data-type="document-title" id="#{page.title.copied_id}">
|
11
|
+
<span class="os-number">#{chapter.count_in(:book)}.#{page.count_in(:chapter)}</span>
|
12
|
+
<span class="os-divider"> </span>
|
13
|
+
<span class="os-text" data-type="" itemprop="">#{page.title.text}</span>
|
14
|
+
</h3>
|
15
|
+
</a>
|
16
|
+
HTML
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/kitchen/element_base.rb
CHANGED
@@ -423,6 +423,12 @@ module Kitchen
|
|
423
423
|
temp_copy.to_s
|
424
424
|
end
|
425
425
|
|
426
|
+
# Copy the element's id
|
427
|
+
def copied_id
|
428
|
+
document.record_id_copied(id)
|
429
|
+
document.modified_id_to_paste(id)
|
430
|
+
end
|
431
|
+
|
426
432
|
# Delete the element
|
427
433
|
#
|
428
434
|
def trash
|
@@ -491,6 +497,35 @@ module Kitchen
|
|
491
497
|
self
|
492
498
|
end
|
493
499
|
|
500
|
+
# Wraps the element's children in a new element. Yields the new wrapper element
|
501
|
+
# to a block, if provided.
|
502
|
+
#
|
503
|
+
# @param name [String] the wrapper's tag name, defaults to 'div'.
|
504
|
+
# @param attributes [Hash] the wrapper's attributes. XML attributes often use hyphens
|
505
|
+
# (e.g. 'data-type') which are hard to put into symbols. Therefore underscores in
|
506
|
+
# keys passed to this method will be converted to hyphens. If you really want an
|
507
|
+
# underscore you can use a double underscore.
|
508
|
+
# @yieldparam [Element] the wrapper Element
|
509
|
+
# @return [Element] self
|
510
|
+
#
|
511
|
+
def wrap_children(name='div', attributes={})
|
512
|
+
if name.is_a?(Hash)
|
513
|
+
attributes = name
|
514
|
+
name = 'div'
|
515
|
+
end
|
516
|
+
|
517
|
+
node.children = node.document.create_element(name) do |new_node|
|
518
|
+
# For some reason passing attributes to create_element doesn't work, so doing here
|
519
|
+
attributes.each do |k, v|
|
520
|
+
new_node[k.to_s.gsub(/([^_])_([^_])/, '\1-\2').gsub('__', '_')] = v
|
521
|
+
end
|
522
|
+
new_node.children = children.to_s
|
523
|
+
yield Element.new(node: new_node, document: document, short_type: nil) if block_given?
|
524
|
+
end.to_s
|
525
|
+
|
526
|
+
self
|
527
|
+
end
|
528
|
+
|
494
529
|
# TODO: methods like replace_children that take string, either forbid or handle Element/Node args
|
495
530
|
|
496
531
|
# Get the content of children matching the provided selector. Mostly
|
@@ -604,10 +639,14 @@ module Kitchen
|
|
604
639
|
end
|
605
640
|
end
|
606
641
|
|
642
|
+
def last_element
|
643
|
+
node.last_element_child
|
644
|
+
end
|
645
|
+
|
607
646
|
# @!method pages
|
608
647
|
# Returns a pages enumerator
|
609
648
|
def_delegators :as_enumerator, :pages, :chapters, :terms, :figures, :notes, :tables, :examples,
|
610
|
-
:metadatas, :units
|
649
|
+
:metadatas, :non_introduction_pages, :units, :titles, :exercises, :composite_pages
|
611
650
|
|
612
651
|
# Returns this element as an enumerator (over only one element, itself)
|
613
652
|
#
|