openstax_kitchen 3.0.0 → 3.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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -3
  3. data/Gemfile.lock +1 -1
  4. data/README.md +7 -0
  5. data/lib/kitchen/directions/bake_book_answer_key/eob_solutions_container.xhtml.erb +9 -0
  6. data/lib/kitchen/directions/bake_book_answer_key/main.rb +11 -0
  7. data/lib/kitchen/directions/bake_book_answer_key/v1.rb +13 -0
  8. data/lib/kitchen/directions/bake_chapter_answer_key/main.rb +14 -0
  9. data/lib/kitchen/directions/bake_chapter_answer_key/strategies/calculus.rb +41 -0
  10. data/lib/kitchen/directions/bake_chapter_answer_key/strategies/uphysics.rb +61 -0
  11. data/lib/kitchen/directions/bake_chapter_answer_key/v1.rb +32 -0
  12. data/lib/kitchen/directions/bake_chapter_glossary.rb +4 -2
  13. data/lib/kitchen/directions/bake_chapter_key_concepts/key_concepts.xhtml.erb +16 -0
  14. data/lib/kitchen/directions/bake_chapter_key_concepts/main.rb +11 -0
  15. data/lib/kitchen/directions/bake_chapter_key_concepts/v1.rb +30 -0
  16. data/lib/kitchen/directions/bake_chapter_key_equations.rb +4 -2
  17. data/lib/kitchen/directions/bake_chapter_review/chapter_review.xhtml.erb +9 -0
  18. data/lib/kitchen/directions/bake_chapter_review/main.rb +11 -0
  19. data/lib/kitchen/directions/bake_chapter_review/v1.rb +13 -0
  20. data/lib/kitchen/directions/bake_chapter_review_exercises/main.rb +15 -0
  21. data/lib/kitchen/directions/bake_chapter_review_exercises/review_exercises.xhtml.erb +10 -0
  22. data/lib/kitchen/directions/bake_chapter_review_exercises/v1.rb +38 -0
  23. data/lib/kitchen/directions/bake_chapter_review_exercises/v2.rb +50 -0
  24. data/lib/kitchen/directions/bake_chapter_section_exercises/main.rb +11 -0
  25. data/lib/kitchen/directions/bake_chapter_section_exercises/v1.rb +28 -0
  26. data/lib/kitchen/directions/bake_chapter_summary.rb +1 -1
  27. data/lib/kitchen/directions/bake_checkpoint.rb +44 -0
  28. data/lib/kitchen/directions/bake_composite_chapters.rb +14 -0
  29. data/lib/kitchen/directions/bake_equations.rb +27 -0
  30. data/lib/kitchen/directions/bake_example.rb +29 -7
  31. data/lib/kitchen/directions/bake_exercises/main.rb +1 -0
  32. data/lib/kitchen/directions/bake_exercises/v1.rb +34 -31
  33. data/lib/kitchen/directions/bake_non_introduction_pages.rb +26 -0
  34. data/lib/kitchen/directions/bake_notes/bake_autotitled_notes.rb +29 -0
  35. data/lib/kitchen/directions/bake_notes/bake_note_subtitle.rb +18 -0
  36. data/lib/kitchen/directions/{bake_notes.rb → bake_notes/bake_notes.rb} +6 -16
  37. data/lib/kitchen/directions/bake_notes/bake_numbered_notes.rb +63 -0
  38. data/lib/kitchen/directions/bake_notes/bake_unclassified_notes.rb +30 -0
  39. data/lib/kitchen/directions/bake_numbered_exercise/main.rb +11 -0
  40. data/lib/kitchen/directions/bake_numbered_exercise/v1.rb +34 -0
  41. data/lib/kitchen/directions/bake_numbered_table/main.rb +2 -2
  42. data/lib/kitchen/directions/bake_numbered_table/v1.rb +17 -3
  43. data/lib/kitchen/directions/bake_page_abstracts.rb +16 -0
  44. data/lib/kitchen/directions/bake_problem_first_elements.rb +16 -0
  45. data/lib/kitchen/directions/bake_stepwise.rb +1 -5
  46. data/lib/kitchen/directions/bake_theorem/main.rb +11 -0
  47. data/lib/kitchen/directions/bake_theorem/v1.rb +28 -0
  48. data/lib/kitchen/directions/bake_toc.rb +6 -0
  49. data/lib/kitchen/directions/eoc_section_title_link_snippet.rb +20 -0
  50. data/lib/kitchen/element_base.rb +40 -1
  51. data/lib/kitchen/element_enumerator_base.rb +87 -8
  52. data/lib/kitchen/exercise_element.rb +45 -0
  53. data/lib/kitchen/exercise_element_enumerator.rb +21 -0
  54. data/lib/kitchen/note_element.rb +17 -16
  55. data/lib/kitchen/page_element.rb +8 -0
  56. data/lib/kitchen/recipe.rb +35 -2
  57. data/lib/kitchen/version.rb +1 -1
  58. data/lib/locales/en.yml +9 -7
  59. data/lib/locales/pl.yml +24 -0
  60. data/lib/openstax_kitchen.rb +1 -1
  61. 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
- book.notes.each do |note|
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.replace_children(with:
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.replace_children(with:
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.replace_children(with:
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,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ module Directions
5
+ module BakeNumberedExercise
6
+ def self.v1(exercise:, number:)
7
+ V1.new.bake(exercise: exercise, number: number)
8
+ end
9
+ end
10
+ end
11
+ 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.replace_children(with:
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,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ module Directions
5
+ module BakeTheorem
6
+ def self.v1(theorem:, number:)
7
+ V1.new.bake(theorem: theorem, number: number)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -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
@@ -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
  #