openstax_kitchen 11.2.0 → 13.0.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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +39 -0
  3. data/Gemfile.lock +1 -1
  4. data/lib/kitchen/chapter_element.rb +7 -0
  5. data/lib/kitchen/directions/bake_autotitled_exercise/main.rb +11 -0
  6. data/lib/kitchen/directions/bake_autotitled_exercise/v1.rb +28 -0
  7. data/lib/kitchen/directions/bake_chapter_glossary/v1.rb +1 -1
  8. data/lib/kitchen/directions/bake_chapter_references/v1.rb +1 -1
  9. data/lib/kitchen/directions/bake_chapter_solutions/v1.rb +1 -1
  10. data/lib/kitchen/directions/bake_chapter_summary.rb +1 -1
  11. data/lib/kitchen/directions/bake_eoc_section_content/remove_section_title.rb +2 -2
  12. data/lib/kitchen/directions/bake_example.rb +1 -1
  13. data/lib/kitchen/directions/bake_figure.rb +3 -2
  14. data/lib/kitchen/directions/bake_free_response/v1.rb +1 -1
  15. data/lib/kitchen/directions/bake_iframes/v1.rb +2 -0
  16. data/lib/kitchen/directions/bake_injected_exercise/add_injected_exercise_id.rb +16 -0
  17. data/lib/kitchen/directions/{bake_injected_exercise_question.rb → bake_injected_exercise/bake_injected_exercise_question.rb} +0 -0
  18. data/lib/kitchen/directions/bake_learning_objectives.rb +48 -0
  19. data/lib/kitchen/directions/bake_notes/bake_autotitled_notes.rb +36 -4
  20. data/lib/kitchen/directions/bake_notes/bake_numbered_notes/v3.rb +2 -0
  21. data/lib/kitchen/directions/bake_numbered_table/bake_table_body.rb +3 -0
  22. data/lib/kitchen/directions/bake_references/main.rb +7 -9
  23. data/lib/kitchen/directions/bake_references/v1.rb +17 -11
  24. data/lib/kitchen/directions/bake_references/v2.rb +9 -10
  25. data/lib/kitchen/directions/bake_references/v3.rb +32 -0
  26. data/lib/kitchen/directions/bake_stepwise.rb +1 -1
  27. data/lib/kitchen/directions/bake_unnumbered_tables.rb +1 -0
  28. data/lib/kitchen/directions/{eoc_composite_page_container → composite_page_container}/main.rb +1 -1
  29. data/lib/kitchen/directions/composite_page_container/v1.rb +28 -0
  30. data/lib/kitchen/directions/move_custom_section_to_eoc_container/v1.rb +1 -1
  31. data/lib/kitchen/directions/move_solutions_to_answer_key/v1.rb +3 -1
  32. data/lib/kitchen/element_base.rb +10 -18
  33. data/lib/kitchen/element_enumerator_base.rb +35 -0
  34. data/lib/kitchen/example_element.rb +2 -1
  35. data/lib/kitchen/exercise_element.rb +34 -0
  36. data/lib/kitchen/figure_element.rb +1 -1
  37. data/lib/kitchen/metadata_element.rb +6 -1
  38. data/lib/kitchen/note_element.rb +19 -5
  39. data/lib/kitchen/section_element.rb +27 -0
  40. data/lib/kitchen/section_element_enumerator.rb +20 -0
  41. data/lib/kitchen/selectors/base.rb +3 -0
  42. data/lib/kitchen/selectors/standard_1.rb +1 -0
  43. data/lib/kitchen/table_element.rb +8 -0
  44. data/lib/kitchen/templates/composite_page_template.xhtml.erb +10 -0
  45. data/lib/kitchen/version.rb +1 -1
  46. data/lib/locales/en.yml +4 -0
  47. data/lib/locales/es.yml +3 -0
  48. data/lib/locales/pl.yml +3 -0
  49. metadata +14 -8
  50. data/lib/kitchen/directions/bake_page_abstracts.rb +0 -30
  51. data/lib/kitchen/directions/eoc_composite_page_container/v1.rb +0 -19
  52. data/lib/kitchen/templates/eoc_section_template.xhtml.erb +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e366a482a30f5cda88fe3c76731d3f187e727447cfc9ae1c13ff5e8bb99c1daa
4
- data.tar.gz: 97db8d770c708fda67c566157989b0999fe12859eb515d52da73a86136ab9c29
3
+ metadata.gz: b0f1212b9bee542b587323cef1fa5ff8dc7437d47921736f58c9c27ef6ee11b8
4
+ data.tar.gz: ca01c38368dc34a0e637f431caf7873f97d5dd52b465e1ae5411d6f0861b8e58
5
5
  SHA512:
6
- metadata.gz: d1b69721238c536696a265d4419f94944746a8a934f24c2e39d8beebe27b18fbd85b1da1599cf6cf326e2d44053b0927db0ab7edae3e24c1a5bfea44839555d9
7
- data.tar.gz: 2b420da729d4282fc85f7b074c2848f83d7912a5ff75365ba91d6406b245a1442f0c3dd7074cc6744b44ba96cdc8d00a0a872b092f54a3865e0fd21daff3d81d
6
+ metadata.gz: c877a0d30bde86ccc5d0e2191b3e0efe853916294d907c764a088e67a2011f9f3fa03fb018ff8aa9992e1fbaeebb753625b90f593d888d8e8a4473139e9e0f43
7
+ data.tar.gz: f96e5128a718bf1897c65b5b558d2586e6905767e355cf9119c56b536f128bbbf403c658187e6faefc0bb7e7fc3013218353a81d99c1fc8dfc30a9ffed8354db
data/CHANGELOG.md CHANGED
@@ -6,6 +6,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+
10
+ ## [13.0.0] - 2021-10-6
11
+
12
+ * Add `BakeLearningObjectives` v3 (minor)
13
+ * Fix `BakeIframes` to skip already-baked iframes (patch)
14
+ * Add `SectionElement` and `SectionElementEnumerator` classes (minor)
15
+ * Refactor `EocCompositePageContainer` to be used by `EOB` sections as well (major)
16
+ * Refactor `bake_references` `v1, v2 and v3` to use `CompositePageContainer` (major)
17
+
18
+ ## [12.2.0] - 2021-10-1
19
+
20
+ * Add `context_lead_text` to translations (minor)
21
+ * Make `ElementBase#search_with` callable from an `ElementEnumerator` (minor)
22
+ * Support top-titled tables in `BakeUnnumberedTables` (minor)
23
+ * Stop `NoteElement#title` from breaking for empty notes (patch)
24
+ * Add text heavy tables to `BakeTableBody` (minor)
25
+ * Modify `BakeAutotitledNotes` to bake unnumbered exercises with solution (minor)
26
+ * Create `AddInjectedExerciseId` to separate creating ids from `BakeInjectedExerciseQuestion` (minor)
27
+ * Rework `AddInjectedExerciseId` to use loop inside module (minor)
28
+
29
+ ## [12.1.0] - 2021-09-24
30
+
31
+ * Fix `BakeExample#titles_to_rename` to exclude exercise titles (patch)
32
+ * Modify `BakeFigure` to bake unnumbered figures with caption (minor)
33
+ * Fix `NoteElement#title` to be more specific about finding the title (patch)
34
+ * Adds `data-type="slug"` to `metadata_lement` `children_to_keep` method, updates spec helper `metadata_element` and related spec files(minor)
35
+
36
+ ## [12.0.0] - 2021-09-21
37
+
38
+ * Fixes `BakeStepwise` to skip nested lists (patch)
39
+ * Adds an optional selector to `RemoveSectionTitles` (minor)
40
+ * Patches `BakeFreeResponse` to only delete the first h3, not all h3s (patch)
41
+ * Lets `BakeExample` not count titles in lists as commentary titles (minor)
42
+ * Renames `BakePageAbstracts` to `BakeLearningObjectives` and adds optional parameter for titles in `v2` (major)
43
+ * Gets rid of extraneous titles in `BakeAutoTitledNotes` when subtitles are off (minor)
44
+ * Adds `BakeAutotitledExercise` direction and the option to `bake_unclassified_exercises` within `BakeAutotitledNotes`
45
+ * Adds optional numbering for `BakeReferences.v1` (minor)
46
+ * Patches`BakeNumberedNotes.v3` to suppress solutions outside examples when suppress_solutions is true (minor)
47
+
9
48
  ## [11.2.0] - 2021-09-10
10
49
 
11
50
  * Adds `BakeAccessibilityFixes` direction for (minor)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- openstax_kitchen (11.2.0)
4
+ openstax_kitchen (13.0.0)
5
5
  activesupport
6
6
  i18n
7
7
  nokogiri
@@ -68,5 +68,12 @@ module Kitchen
68
68
  search('div[data-type="abstract"]')
69
69
  end
70
70
 
71
+ # Returns an enumerator for the learning objectives
72
+ #
73
+ # @return [ElementEnumerator]
74
+ #
75
+ def learning_objectives
76
+ search('section.learning-objectives')
77
+ end
71
78
  end
72
79
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ module Directions
5
+ module BakeAutotitledExercise
6
+ def self.v1(exercise:, number: nil)
7
+ V1.new.bake(exercise: exercise, number: number)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen::Directions::BakeAutotitledExercise
4
+ class V1
5
+ def bake(exercise:, number:)
6
+ exercise.add_class('unnumbered') unless number
7
+
8
+ # bake problem
9
+ exercise.problem.wrap_children('div', class: 'os-problem-container')
10
+ exercise.problem.prepend(child:
11
+ <<~HTML
12
+ <h4 class="exercise-title" data-type="title">#{exercise.autogenerated_title}</h4>
13
+ HTML
14
+ )
15
+ return unless exercise.solution
16
+
17
+ # bake solution in place
18
+ exercise.solution.wrap_children('div', class: 'os-solution-container')
19
+ exercise.solution.prepend(child:
20
+ <<~HTML
21
+ <h4 class="solution-title" data-type="title">
22
+ <span class="os-text">#{I18n.t(:"exercises.solution")}</span>
23
+ </h4>
24
+ HTML
25
+ )
26
+ end
27
+ end
28
+ end
@@ -41,7 +41,7 @@ module Kitchen::Directions::BakeChapterGlossary
41
41
 
42
42
  content = @glossary.sort.map { |definition| definition.element.paste }.join
43
43
 
44
- Kitchen::Directions::EocCompositePageContainer.v1(
44
+ Kitchen::Directions::CompositePageContainer.v1(
45
45
  container_key: 'glossary',
46
46
  uuid_key: "#{uuid_prefix}glossary",
47
47
  metadata_source: metadata_source,
@@ -11,7 +11,7 @@ module Kitchen::Directions::BakeChapterReferences
11
11
 
12
12
  content = chapter.pages.references.cut.paste
13
13
 
14
- Kitchen::Directions::EocCompositePageContainer.v1(
14
+ Kitchen::Directions::CompositePageContainer.v1(
15
15
  container_key: klass,
16
16
  uuid_key: "#{uuid_prefix}#{klass}",
17
17
  metadata_source: metadata_source,
@@ -23,7 +23,7 @@ module Kitchen::Directions::BakeChapterSolutions
23
23
 
24
24
  content = solutions_clipboard.paste
25
25
 
26
- Kitchen::Directions::EocCompositePageContainer.v1(
26
+ Kitchen::Directions::CompositePageContainer.v1(
27
27
  container_key: 'solutions',
28
28
  uuid_key: "#{uuid_prefix}solutions",
29
29
  metadata_source: metadata_source,
@@ -31,7 +31,7 @@ module Kitchen
31
31
 
32
32
  return if summaries.none?
33
33
 
34
- EocCompositePageContainer.v1(
34
+ CompositePageContainer.v1(
35
35
  container_key: klass,
36
36
  uuid_key: "#{uuid_prefix}#{klass}",
37
37
  metadata_source: metadata_source,
@@ -3,8 +3,8 @@
3
3
  module Kitchen
4
4
  module Directions
5
5
  module RemoveSectionTitle
6
- def self.v1(section:)
7
- section.first('[data-type="title"]')&.trash
6
+ def self.v1(section:, selector: '')
7
+ section.first("#{selector}[data-type=\"title\"]")&.trash
8
8
  end
9
9
  end
10
10
  end
@@ -53,7 +53,7 @@ module Kitchen
53
53
  next unless commentary.present?
54
54
 
55
55
  commentary_title = commentary.titles.first
56
- next unless commentary_title.present?
56
+ next unless commentary_title.present? && commentary_title.parent['data-type'] != 'list'
57
57
 
58
58
  commentary_title.name = 'h4'
59
59
  commentary_title['data-type'] = 'commentary-title'
@@ -4,10 +4,11 @@ module Kitchen
4
4
  module Directions
5
5
  module BakeFigure
6
6
  def self.v1(figure:, number:, cases: false)
7
- return if figure.has_class?('unnumbered') && !figure.has_class?('splash')
7
+ return if figure.has_class?('unnumbered') && !figure.has_class?('splash') && !figure.caption
8
8
 
9
9
  figure.wrap(%(<div class="os-figure#{' has-splash' if figure.has_class?('splash')}">))
10
- if figure.has_class?('unnumbered') && figure.has_class?('splash')
10
+
11
+ if figure.has_class?('unnumbered') && (figure.caption || figure.has_class?('splash'))
11
12
  caption = figure.caption&.cut
12
13
  figure.append(sibling:
13
14
  <<~HTML
@@ -12,7 +12,7 @@ module Kitchen::Directions::BakeFreeResponse
12
12
  free_response_questions = page.free_response
13
13
  next if free_response_questions.none?
14
14
 
15
- free_response_questions.search('h3').trash
15
+ free_response_questions.search('h3')&.first&.trash
16
16
  title = Kitchen::Directions::EocSectionTitleLinkSnippet.v1(page: page)
17
17
  free_response_questions.each do |free_response_question|
18
18
  free_response_question.prepend(child: title)
@@ -7,6 +7,8 @@ module Kitchen::Directions::BakeIframes
7
7
  return unless iframes.any?
8
8
 
9
9
  iframes.each do |iframe|
10
+ next if iframe.has_class?('os-is-iframe')
11
+
10
12
  iframe.wrap('<div class="os-has-iframe" data-type="alternatives">')
11
13
  iframe.add_class('os-is-iframe')
12
14
  link_ref = iframe[:src]
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ module Directions
5
+ # Ids should be added before exercises are moved to EOC,
6
+ # since they're using part of the ancestor page id.
7
+ #
8
+ # In some books exercises are numbered after moving.
9
+ # That's why this step has to be separated from BakeInjectedExerciseQuestion
10
+ module AddInjectedExerciseId
11
+ def self.v1(book:)
12
+ book.pages.injected_questions.each(&:id)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ module Directions
5
+ module BakeLearningObjectives
6
+ def self.v1(chapter:)
7
+ chapter.abstracts.each do |abstract|
8
+ abstract.prepend(child: "<h3 data-type='title'>#{I18n.t(:learning_objectives)}</h3>")
9
+ end
10
+ end
11
+
12
+ def self.v2(chapter:, add_title: true)
13
+ learning_objectives =
14
+ chapter.abstracts.any? ? chapter.abstracts : chapter.learning_objectives
15
+
16
+ learning_objectives.each do |abstract|
17
+ if add_title
18
+ abstract.prepend(child: "<h3 data-type='title'>#{I18n.t(:learning_objectives)}</h3>")
19
+ end
20
+
21
+ ul = abstract.first!('ul')
22
+ ul.add_class('os-abstract')
23
+ ul.search('li').each_with_index do |li, index|
24
+ li.replace_children(with:
25
+ <<~HTML
26
+ <span class="os-abstract-token">#{chapter.count_in(:book)}.#{abstract.count_in(:chapter)}.#{index + 1}</span>
27
+ <span class="os-abstract-content">#{li.children}</span>
28
+ HTML
29
+ )
30
+ end
31
+ end
32
+ end
33
+
34
+ # Wraps & moves abstract under the corresponding chapter objective in the intro page
35
+ def self.v3(chapter:)
36
+ abstracts = chapter.abstracts.map do |abstract|
37
+ abstract.wrap('<div class="learning-objective">')
38
+ abstract.parent
39
+ end
40
+
41
+ chapter.introduction_page.search('div.os-chapter-objective') \
42
+ .each_with_index do |objective, index|
43
+ objective.append(child: abstracts[index].cut.paste)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -3,19 +3,24 @@
3
3
  module Kitchen
4
4
  module Directions
5
5
  module BakeAutotitledNotes
6
- def self.v1(book:, classes:, bake_subtitle: true, cases: false)
6
+ def self.v1(book:, classes:, bake_subtitle: true, cases: false, bake_exercises: false)
7
7
  book.notes.each do |note|
8
8
  next unless (note.classes & classes).any?
9
9
 
10
- bake_note(note: note, bake_subtitle: bake_subtitle, cases: cases)
10
+ bake_note(
11
+ note: note, bake_subtitle: bake_subtitle, cases: cases, bake_exercises: bake_exercises)
11
12
  end
12
13
  end
13
14
 
14
- def self.bake_note(note:, bake_subtitle:, cases:)
15
+ def self.bake_note(note:, bake_subtitle:, cases:, bake_exercises:)
15
16
  Kitchen::Directions::BakeIframes.v1(outer_element: note)
16
17
  note.wrap_children(class: 'os-note-body')
17
18
 
18
- BakeNoteSubtitle.v1(note: note, cases: cases) if bake_subtitle
19
+ if bake_subtitle
20
+ BakeNoteSubtitle.v1(note: note, cases: cases)
21
+ else
22
+ note.title&.trash
23
+ end
19
24
 
20
25
  note.prepend(child:
21
26
  <<~HTML
@@ -24,6 +29,33 @@ module Kitchen
24
29
  </h3>
25
30
  HTML
26
31
  )
32
+
33
+ bake_unclassified_exercises(note: note) if bake_exercises
34
+ end
35
+
36
+ def self.bake_unclassified_exercises(note:)
37
+ note.exercises.each do |exercise|
38
+ exercise.problem.wrap_children('div', class: 'os-problem-container')
39
+
40
+ unless exercise.has_class?('unnumbered')
41
+ exercise.problem.prepend(child:
42
+ <<~HTML
43
+ <span class="os-title-label">#{I18n.t(:"exercises.exercise")} </span>
44
+ <span class="os-number">#{exercise.count_in(:note)}</span>
45
+ HTML
46
+ )
47
+ end
48
+
49
+ next unless exercise.solution
50
+
51
+ exercise.solution.wrap_children('div', class: 'os-solution-container')
52
+
53
+ exercise.solution.prepend(child:
54
+ <<~HTML
55
+ <span class="os-title-label">#{I18n.t(:"exercises.solution")}</span>
56
+ HTML
57
+ )
58
+ end
27
59
  end
28
60
  end
29
61
  end
@@ -32,6 +32,8 @@ module Kitchen::Directions
32
32
  note.injected_questions.each do |question|
33
33
  BakeNumberedNotes.bake_note_injected_question(note: note, question: question)
34
34
  end
35
+
36
+ note.search("div[data-type='solution']").each&.trash if suppress_solution
35
37
  end
36
38
  end
37
39
  end
@@ -62,6 +62,9 @@ module Kitchen
62
62
  elsif table.column_header?
63
63
  custom_table = CustomBody.new(table: table, klass: 'column-header')
64
64
  custom_table.modify_body(has_fake_title: false)
65
+ elsif table.text_heavy?
66
+ custom_table = CustomBody.new(table: table, klass: 'text-heavy')
67
+ custom_table.modify_body(has_fake_title: false)
65
68
  end
66
69
  end
67
70
  end
@@ -5,18 +5,16 @@ module Kitchen
5
5
  # Bake directions for EOB references
6
6
  #
7
7
  module BakeReferences
8
- def self.v1(book:, metadata_source:)
9
- V1.new.bake(
10
- book: book,
11
- metadata_source: metadata_source
12
- )
8
+ def self.v1(book:, metadata_source:, numbered_title: false)
9
+ V1.new.bake(book: book, metadata_source: metadata_source, numbered_title: numbered_title)
13
10
  end
14
11
 
15
12
  def self.v2(book:, metadata_source:)
16
- V2.new.bake(
17
- book: book,
18
- metadata_source: metadata_source
19
- )
13
+ V2.new.bake(book: book, metadata_source: metadata_source)
14
+ end
15
+
16
+ def self.v3(book:, metadata_source:)
17
+ V3.new.bake(book: book, metadata_source: metadata_source)
20
18
  end
21
19
  end
22
20
  end
@@ -4,12 +4,7 @@ module Kitchen::Directions::BakeReferences
4
4
  class V1
5
5
  renderable
6
6
 
7
- def bake(book:, metadata_source:)
8
- @metadata = metadata_source.children_to_keep.copy
9
- @klass = 'reference'
10
- @uuid_prefix = '.'
11
- @title = I18n.t(:references)
12
-
7
+ def bake(book:, metadata_source:, numbered_title:)
13
8
  book.chapters.each do |chapter|
14
9
  chapter.search('[data-type="cite"]').each do |link|
15
10
  link.prepend(child:
@@ -28,21 +23,32 @@ module Kitchen::Directions::BakeReferences
28
23
  end
29
24
 
30
25
  chapter_references = chapter.pages.references.cut
31
- chapter_title_no_num = chapter.title.search('.os-text')
26
+
27
+ chapter_title = if numbered_title
28
+ chapter.title.search('.os-number, .os-divider, .os-text')
29
+ else
30
+ chapter.title.search('.os-text')
31
+ end
32
32
 
33
33
  chapter.append(child:
34
34
  <<~HTML
35
35
  <div class="os-chapter-area">
36
- <h2 data-type="document-title">#{chapter_title_no_num}</h2>
36
+ <h2 data-type="document-title">#{chapter_title}</h2>
37
37
  #{chapter_references.paste}
38
38
  </div>
39
39
  HTML
40
40
  )
41
41
  end
42
+
42
43
  chapter_area_references = book.chapters.search('.os-chapter-area').cut
43
- @content = chapter_area_references.paste
44
- book.body.append(child: render(file:
45
- '../../templates/eob_section_title_template.xhtml.erb'))
44
+
45
+ Kitchen::Directions::CompositePageContainer.v1(
46
+ container_key: 'reference',
47
+ uuid_key: '.reference',
48
+ metadata_source: metadata_source,
49
+ content: chapter_area_references.paste,
50
+ append_to: book.body
51
+ )
46
52
  end
47
53
  end
48
54
  end
@@ -2,14 +2,7 @@
2
2
 
3
3
  module Kitchen::Directions::BakeReferences
4
4
  class V2
5
- renderable
6
-
7
5
  def bake(book:, metadata_source:)
8
- @metadata = metadata_source.children_to_keep.copy
9
- @klass = 'references'
10
- @uuid_prefix = '.'
11
- @title = I18n.t(:references)
12
-
13
6
  book.chapters.each do |chapter|
14
7
 
15
8
  chapter.references.search('h3').trash
@@ -26,10 +19,16 @@ module Kitchen::Directions::BakeReferences
26
19
  HTML
27
20
  )
28
21
  end
22
+
29
23
  chapter_area_references = book.chapters.search('.os-chapter-area').cut
30
- @content = chapter_area_references.paste
31
- book.body.append(child: render(file:
32
- '../../templates/eob_section_title_template.xhtml.erb'))
24
+
25
+ Kitchen::Directions::CompositePageContainer.v1(
26
+ container_key: 'references',
27
+ uuid_key: '.references',
28
+ metadata_source: metadata_source,
29
+ content: chapter_area_references.paste,
30
+ append_to: book.body
31
+ )
33
32
  end
34
33
  end
35
34
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen::Directions::BakeReferences
4
+ class V3
5
+ def bake(book:, metadata_source:)
6
+ return unless book.references.any?
7
+
8
+ book.chapters.pages.each do |page|
9
+ page.references.each do |reference|
10
+ reference.titles.trash
11
+ reference.prepend(child:
12
+ Kitchen::Directions::EocSectionTitleLinkSnippet.v1(
13
+ page: page,
14
+ title_tag: 'h2',
15
+ wrapper: nil
16
+ )
17
+ )
18
+ end
19
+ end
20
+
21
+ chapter_area_references = book.chapters.references.cut
22
+
23
+ Kitchen::Directions::CompositePageContainer.v1(
24
+ container_key: 'references',
25
+ uuid_key: '.references',
26
+ metadata_source: metadata_source,
27
+ content: chapter_area_references.paste,
28
+ append_to: book.body
29
+ )
30
+ end
31
+ end
32
+ end
@@ -8,7 +8,7 @@ module Kitchen
8
8
  ol.remove_class('stepwise')
9
9
  ol.add_class('os-stepwise')
10
10
 
11
- ol.search('li').each_with_index do |li, ii|
11
+ ol.search('> li').each_with_index do |li, ii|
12
12
  li.wrap_children('span', class: 'os-stepwise-content')
13
13
  li.prepend(child:
14
14
  <<~HTML
@@ -9,6 +9,7 @@ module Kitchen
9
9
  table.remove_attribute('summary')
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
+ table.parent.add_class('os-top-titled-container') if table.top_titled?
12
13
  end
13
14
  end
14
15
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Kitchen
4
4
  module Directions
5
- module EocCompositePageContainer
5
+ module CompositePageContainer
6
6
  # Creates a wrapper for the given content & appends it to the given element
7
7
  #
8
8
  # @param container_key [String] Appended to 'eoc.' to form the I18n key for the container title; also used as part of a class on the container.
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen::Directions::CompositePageContainer
4
+ class V1
5
+ renderable
6
+
7
+ def bake(container_key:, uuid_key:, metadata_source:, content:, append_to:)
8
+ @in_composite_chapter = append_to.is?(:composite_chapter)
9
+ @is_eoc = append_to.is?(:chapter) || @in_composite_chapter
10
+ @section = @is_eoc ? 'eoc' : 'eob'
11
+ @title = I18n.t(:"#{@section}.#{container_key}")
12
+ @uuid_key = uuid_key
13
+ @container_class_type = container_key
14
+ @metadata = metadata_source.children_to_keep.copy
15
+ @content = content
16
+ @main_title_tag = 'h1'
17
+
18
+ if @in_composite_chapter
19
+ @main_title_tag = 'h3'
20
+ elsif @is_eoc
21
+ @main_title_tag = 'h2'
22
+ end
23
+
24
+ append_to.append(child: render(file:
25
+ '../../templates/composite_page_template.xhtml.erb'))
26
+ end
27
+ end
28
+ end
@@ -30,7 +30,7 @@ module Kitchen::Directions::MoveCustomSectionToEocContainer
30
30
  section_clipboard.paste
31
31
  end
32
32
 
33
- Kitchen::Directions::EocCompositePageContainer.v1(
33
+ Kitchen::Directions::CompositePageContainer.v1(
34
34
  container_key: container_key,
35
35
  uuid_key: uuid_key,
36
36
  metadata_source: metadata_source,
@@ -38,7 +38,9 @@ module Kitchen::Directions::MoveSolutionsToAnswerKey
38
38
  </div>
39
39
  HTML
40
40
  )
41
- strategy.bake(chapter: chapter, append_to: append_to.first("[data-uuid-key='#{uuid_key}']"))
41
+ strategy.bake(
42
+ chapter: chapter, append_to: append_to.first("div[data-uuid-key='#{uuid_key}']")
43
+ )
42
44
  end
43
45
  # rubocop:enable Metrics/ParameterLists
44
46
  end
@@ -211,6 +211,14 @@ module Kitchen
211
211
  self[:id] = value
212
212
  end
213
213
 
214
+ # Returns the element's data-type
215
+ #
216
+ # @return [String]
217
+ #
218
+ def data_type
219
+ self[:'data-type']
220
+ end
221
+
214
222
  # A way to set values and chain them
215
223
  #
216
224
  # @param property [String, Symbol] the name of the property to set
@@ -419,23 +427,6 @@ module Kitchen
419
427
  )
420
428
  end
421
429
 
422
- # Searches for elements handled by a list of enumerator classes. All element that
423
- # matches one of those enumerator classes are iterated over.
424
- #
425
- # @param enumerator_classes [Array<ElementEnumeratorBase>]
426
- # @return [TypeCastingElementEnumerator]
427
- #
428
- def search_with(*enumerator_classes)
429
- block_error_if(block_given?)
430
- raise 'must supply at least one enumerator class' if enumerator_classes.empty?
431
-
432
- factory = enumerator_classes[0].factory
433
- enumerator_classes[1..-1].each do |enumerator_class|
434
- factory = factory.or_with(enumerator_class.factory)
435
- end
436
- factory.build_within(self)
437
- end
438
-
439
430
  # Removes the element from its parent and places it on the specified clipboard
440
431
  #
441
432
  # @param to [Symbol, String, Clipboard, nil] the name of the clipboard (or a Clipboard
@@ -762,7 +753,8 @@ module Kitchen
762
753
  # Returns a pages enumerator
763
754
  def_delegators :as_enumerator, :pages, :chapters, :terms, :figures, :notes, :tables, :examples,
764
755
  :metadatas, :non_introduction_pages, :units, :titles, :exercises, :references,
765
- :composite_pages, :composite_chapters, :solutions, :injected_questions
756
+ :composite_pages, :composite_chapters, :solutions, :injected_questions,
757
+ :search_with, :sections
766
758
 
767
759
  # Returns this element as an enumerator (over only one element, itself)
768
760
  #
@@ -318,6 +318,24 @@ module Kitchen
318
318
  css_or_xpath: css_or_xpath, only: only, except: except)
319
319
  end
320
320
 
321
+ # Returns an enumerator that iterates through sections within the scope of this enumerator
322
+ #
323
+ # @param css_or_xpath [String] additional selectors to further narrow the element iterated over;
324
+ # a "$" in this argument will be replaced with the default selector for the element being
325
+ # iterated over.
326
+ # @param only [Symbol, Callable] the name of a method to call on an element or a
327
+ # lambda or proc that accepts an element; elements will only be included in the
328
+ # search results if the method or callable returns true
329
+ # @param except [Symbol, Callable] the name of a method to call on an element or a
330
+ # lambda or proc that accepts an element; elements will not be included in the
331
+ # search results if the method or callable returns false
332
+ #
333
+ def sections(css_or_xpath=nil, only: nil, except: nil)
334
+ block_error_if(block_given?)
335
+ chain_to(SectionElementEnumerator,
336
+ css_or_xpath: css_or_xpath, only: only, except: except)
337
+ end
338
+
321
339
  # Returns an enumerator that iterates within the scope of this enumerator
322
340
  #
323
341
  # @param css_or_xpath [String] additional selectors to further narrow the element iterated over
@@ -327,6 +345,23 @@ module Kitchen
327
345
  chain_to(ElementEnumerator, css_or_xpath: css_or_xpath, only: only, except: except)
328
346
  end
329
347
 
348
+ # Searches for elements handled by a list of enumerator classes. All element that
349
+ # matches one of those enumerator classes are iterated over.
350
+ #
351
+ # @param enumerator_classes [Array<ElementEnumeratorBase>]
352
+ # @return [TypeCastingElementEnumerator]
353
+ #
354
+ def search_with(*enumerator_classes)
355
+ block_error_if(block_given?)
356
+ raise 'must supply at least one enumerator class' if enumerator_classes.empty?
357
+
358
+ factory = enumerator_classes[0].factory
359
+ enumerator_classes[1..-1].each do |enumerator_class|
360
+ factory = factory.or_with(enumerator_class.factory)
361
+ end
362
+ factory.build_within(self)
363
+ end
364
+
330
365
  # Returns an enumerator that iterates through elements within the scope of this enumerator
331
366
  #
332
367
  # @param enumerator_class [ElementEnumeratorBase] the enumerator to use for the iteration
@@ -33,7 +33,8 @@ module Kitchen
33
33
  title.parent.has_class?('os-caption-container') || \
34
34
  title.parent.has_class?('os-caption') || \
35
35
  title.parent.name == 'caption' || \
36
- title.parent[:'data-type'] == 'note'
36
+ title.parent.data_type == 'note' || \
37
+ title.parent.data_type == 'exercise'
37
38
  end
38
39
  )
39
40
  end
@@ -54,5 +54,39 @@ module Kitchen
54
54
  def baked?
55
55
  search('div.os-problem-container').any?
56
56
  end
57
+
58
+ # Returns true if the exercise's title is autogenerated
59
+ #
60
+ # @return [Boolean]
61
+ #
62
+ def indicates_autogenerated_title?
63
+ detected_exercise_title_key != 0 && detected_exercise_title_key.present?
64
+ end
65
+
66
+ # Get the autogenerated title for this note
67
+ #
68
+ # @return [String]
69
+ #
70
+ def autogenerated_title
71
+ if indicates_autogenerated_title?
72
+ I18n.t(:"exercises.#{detected_exercise_title_key}")
73
+ else
74
+ "unknown title for exercise with classes #{classes}"
75
+ end
76
+ end
77
+
78
+ def detected_exercise_title_key
79
+ @detected_exercise_title_key ||= begin
80
+ return 0 if classes.empty? || !I18n.t('.').key?(:exercises)
81
+
82
+ possible_keys = I18n.t(:exercises).keys.map(&:to_s)
83
+ keys = possible_keys & classes
84
+
85
+ raise("too many translation keys: #{keys.join(', ')}") if keys.many?
86
+ return 0 if keys.empty?
87
+
88
+ keys.first
89
+ end
90
+ end
57
91
  end
58
92
  end
@@ -53,7 +53,7 @@ module Kitchen
53
53
  # @return [Boolean]
54
54
  #
55
55
  def figure_to_bake?
56
- return false if subfigure? || (has_class?('unnumbered') && !has_class?('splash'))
56
+ return false if subfigure? || (has_class?('unnumbered') && !has_class?('splash') && !caption)
57
57
 
58
58
  true
59
59
  end
@@ -27,7 +27,12 @@ module Kitchen
27
27
  # @return [ElementEnumerator]
28
28
  #
29
29
  def children_to_keep
30
- search(%w(span[data-type='revised'] div.authors div.publishers div.print-style div.permissions
30
+ search(%w(span[data-type='revised']
31
+ span[data-type='slug']
32
+ div.authors
33
+ div.publishers
34
+ div.print-style
35
+ div.permissions
31
36
  div[data-type='subject']))
32
37
  end
33
38
  end
@@ -29,16 +29,30 @@ module Kitchen
29
29
  #
30
30
  def title
31
31
  block_error_if(block_given?)
32
- note_body = first('div.os-note-body')
33
- first_child = note_body ? note_body.element_children[0] : element_children[0]
32
+ # An element with data-type="title" is ambiguous; it is only the note's title if:
33
+ # 1. it is the note body's first child
34
+ # 2. it is the first child's first child and the first child is a paragraph
35
+ first_child = first_note_body_child
36
+ return unless first_child
37
+
38
+ first_grandchild = get_first_grandchild_for_title(first_child)
34
39
 
35
- if first_child[:'data-type'] == 'title'
40
+ if first_child.data_type == 'title'
36
41
  first_child
37
- elsif first_child&.element_children&.[](0)&.[](:'data-type') == 'title'
38
- first_child.element_children[0]
42
+ elsif first_grandchild&.data_type == 'title'
43
+ first_grandchild
39
44
  end
40
45
  end
41
46
 
47
+ def first_note_body_child
48
+ note_body = first('div.os-note-body')
49
+ note_body ? note_body.element_children[0] : element_children[0]
50
+ end
51
+
52
+ def get_first_grandchild_for_title(first_child)
53
+ first_child&.element_children&.[](0) if first_child.name == 'p'
54
+ end
55
+
42
56
  # Returns true if the note's title is autogenerated
43
57
  #
44
58
  # @return [Boolean]
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ # An element for an example
5
+ #
6
+ class SectionElement < ElementBase
7
+
8
+ # Creates a new +SectionElement+
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: SectionElementEnumerator)
17
+ end
18
+
19
+ # Returns the short type
20
+ # @return [Symbol]
21
+ #
22
+ def self.short_type
23
+ :section
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kitchen
4
+ # An enumerator for table elements
5
+ #
6
+ class SectionElementEnumerator < ElementEnumeratorBase
7
+ # Returns a factory for this enumerator
8
+ #
9
+ # @return [ElementEnumeratorFactory]
10
+ #
11
+ def self.factory
12
+ ElementEnumeratorFactory.new(
13
+ default_css_or_xpath: Selector.named(:section),
14
+ sub_element_class: SectionElement,
15
+ enumerator_class: self
16
+ )
17
+ end
18
+
19
+ end
20
+ end
@@ -62,6 +62,9 @@ module Kitchen
62
62
  # Selector for an injected question
63
63
  # @return [String]
64
64
  attr_accessor :injected_question
65
+ # Selector for a section
66
+ # @return [String]
67
+ attr_accessor :section
65
68
 
66
69
  # Override specific selectors
67
70
  #
@@ -29,6 +29,7 @@ module Kitchen
29
29
  self.solution = "div[data-type='solution'], " \
30
30
  "div[data-type='question-solution']"
31
31
  self.injected_question = "div[data-type='exercise-question']"
32
+ self.section = 'section'
32
33
  end
33
34
 
34
35
  end
@@ -97,6 +97,14 @@ module Kitchen
97
97
  has_class?('column-header')
98
98
  end
99
99
 
100
+ # Returns true if the table is text heavy
101
+ #
102
+ # @return [Boolean]
103
+ #
104
+ def text_heavy?
105
+ has_class?('text-heavy')
106
+ end
107
+
100
108
  # Returns an element for the table caption, if present
101
109
  #
102
110
  # @return [Element, nil]
@@ -0,0 +1,10 @@
1
+ <div class="os-<%= @section%> os-<%=@container_class_type%>-container" data-type="composite-page" data-uuid-key="<%= @uuid_key %>">
2
+ <<%= @main_title_tag %> data-type="<%= @in_composite_chapter ? 'title' : '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
+ <%= @content %>
10
+ </div>
@@ -3,5 +3,5 @@
3
3
  # A library for modifying the structure of OpenStax book XML.
4
4
  #
5
5
  module Kitchen
6
- VERSION = '11.2.0'
6
+ VERSION = '13.0.0'
7
7
  end
data/lib/locales/en.yml CHANGED
@@ -27,6 +27,7 @@ en:
27
27
  section_exercises: ! 'Section %{number} Exercises'
28
28
  iframe_link_text: Click to view content
29
29
  handbook_outline_title: Outline
30
+ context_lead_text: 'Refer to '
30
31
  eoc:
31
32
  glossary: Key Terms
32
33
  key-equations: Key Equations
@@ -39,5 +40,8 @@ en:
39
40
  folio:
40
41
  preface: Preface
41
42
  access_for_free: Access for free at openstax.org
43
+ eob:
44
+ references: References
45
+ reference: References
42
46
  index:
43
47
  main: Index
data/lib/locales/es.yml CHANGED
@@ -35,5 +35,8 @@ es:
35
35
  folio:
36
36
  preface: Prefacio
37
37
  access_for_free: Acceso gratis en openstax.org
38
+ eob:
39
+ references: Referencias
40
+ reference: Referencias
38
41
  index:
39
42
  main: Índice
data/lib/locales/pl.yml CHANGED
@@ -67,6 +67,9 @@ pl:
67
67
  key-equations: Najważniejsze wzory
68
68
  summary: Podsumowanie
69
69
  references: Bibliografia
70
+ eob:
71
+ references: Bibliografia
72
+ reference: Bibliografia
70
73
  index:
71
74
  name: Skorowidz nazwisk
72
75
  term: Skorowidz rzeczowy
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: 11.2.0
4
+ version: 13.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-09-10 00:00:00.000000000 Z
11
+ date: 2021-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -247,6 +247,8 @@ files:
247
247
  - lib/kitchen/directions/bake_annotation_classes/main.rb
248
248
  - lib/kitchen/directions/bake_annotation_classes/v1.rb
249
249
  - lib/kitchen/directions/bake_appendix.rb
250
+ - lib/kitchen/directions/bake_autotitled_exercise/main.rb
251
+ - lib/kitchen/directions/bake_autotitled_exercise/v1.rb
250
252
  - lib/kitchen/directions/bake_chapter_glossary/main.rb
251
253
  - lib/kitchen/directions/bake_chapter_glossary/v1.rb
252
254
  - lib/kitchen/directions/bake_chapter_introductions/bake_chapter_objectives.rb
@@ -292,8 +294,10 @@ files:
292
294
  - lib/kitchen/directions/bake_index/v1.rb
293
295
  - lib/kitchen/directions/bake_index/v1.xhtml.erb
294
296
  - lib/kitchen/directions/bake_injected_exercise.rb
295
- - lib/kitchen/directions/bake_injected_exercise_question.rb
297
+ - lib/kitchen/directions/bake_injected_exercise/add_injected_exercise_id.rb
298
+ - lib/kitchen/directions/bake_injected_exercise/bake_injected_exercise_question.rb
296
299
  - lib/kitchen/directions/bake_inline_lists.rb
300
+ - lib/kitchen/directions/bake_learning_objectives.rb
297
301
  - lib/kitchen/directions/bake_link_placeholders.rb
298
302
  - lib/kitchen/directions/bake_lists_with_para.rb
299
303
  - lib/kitchen/directions/bake_math_in_paragraph.rb
@@ -311,12 +315,12 @@ files:
311
315
  - lib/kitchen/directions/bake_numbered_table/main.rb
312
316
  - lib/kitchen/directions/bake_numbered_table/v1.rb
313
317
  - lib/kitchen/directions/bake_numbered_table/v2.rb
314
- - lib/kitchen/directions/bake_page_abstracts.rb
315
318
  - lib/kitchen/directions/bake_preface/main.rb
316
319
  - lib/kitchen/directions/bake_preface/v1.rb
317
320
  - lib/kitchen/directions/bake_references/main.rb
318
321
  - lib/kitchen/directions/bake_references/v1.rb
319
322
  - lib/kitchen/directions/bake_references/v2.rb
323
+ - lib/kitchen/directions/bake_references/v3.rb
320
324
  - lib/kitchen/directions/bake_stepwise.rb
321
325
  - lib/kitchen/directions/bake_suggested_reading.rb
322
326
  - lib/kitchen/directions/bake_toc.rb
@@ -331,8 +335,8 @@ files:
331
335
  - lib/kitchen/directions/chapter_review_container/chapter_review.xhtml.erb
332
336
  - lib/kitchen/directions/chapter_review_container/main.rb
333
337
  - lib/kitchen/directions/chapter_review_container/v1.rb
334
- - lib/kitchen/directions/eoc_composite_page_container/main.rb
335
- - lib/kitchen/directions/eoc_composite_page_container/v1.rb
338
+ - lib/kitchen/directions/composite_page_container/main.rb
339
+ - lib/kitchen/directions/composite_page_container/v1.rb
336
340
  - lib/kitchen/directions/eoc_section_title_link_snippet.rb
337
341
  - lib/kitchen/directions/move_custom_section_to_eoc_container/main.rb
338
342
  - lib/kitchen/directions/move_custom_section_to_eoc_container/v1.rb
@@ -390,14 +394,16 @@ files:
390
394
  - lib/kitchen/references_element_enumerator.rb
391
395
  - lib/kitchen/search_history.rb
392
396
  - lib/kitchen/search_query.rb
397
+ - lib/kitchen/section_element.rb
398
+ - lib/kitchen/section_element_enumerator.rb
393
399
  - lib/kitchen/selector.rb
394
400
  - lib/kitchen/selectors/base.rb
395
401
  - lib/kitchen/selectors/standard_1.rb
396
402
  - lib/kitchen/solution_element_enumerator.rb
397
403
  - lib/kitchen/table_element.rb
398
404
  - lib/kitchen/table_element_enumerator.rb
405
+ - lib/kitchen/templates/composite_page_template.xhtml.erb
399
406
  - lib/kitchen/templates/eob_section_title_template.xhtml.erb
400
- - lib/kitchen/templates/eoc_section_template.xhtml.erb
401
407
  - lib/kitchen/templates/eoc_section_template_old.xhtml.erb
402
408
  - lib/kitchen/term_element.rb
403
409
  - lib/kitchen/term_element_enumerator.rb
@@ -459,7 +465,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
459
465
  - !ruby/object:Gem::Version
460
466
  version: '0'
461
467
  requirements: []
462
- rubygems_version: 3.0.3
468
+ rubygems_version: 3.0.3.1
463
469
  signing_key:
464
470
  specification_version: 4
465
471
  summary: OpenStax content baking library
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kitchen
4
- module Directions
5
- # Adds learning objectives header to abstracts
6
- module BakePageAbstracts
7
- def self.v1(chapter:)
8
- chapter.abstracts.each do |abstract|
9
- abstract.prepend(child: "<h3 data-type='title'>#{I18n.t(:learning_objectives)}</h3>")
10
- end
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.children}</span>
23
- HTML
24
- )
25
- end
26
- end
27
- end
28
- end
29
- end
30
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kitchen::Directions::EocCompositePageContainer
4
- class V1
5
- renderable
6
-
7
- def bake(container_key:, uuid_key:, metadata_source:, content:, append_to:)
8
- @title = I18n.t(:"eoc.#{container_key}")
9
- @uuid_key = uuid_key
10
- @container_class_type = container_key
11
- @metadata = metadata_source.children_to_keep.copy
12
- @content = content
13
- @in_composite_chapter = append_to.is?(:composite_chapter)
14
-
15
- append_to.append(child: render(file:
16
- '../../templates/eoc_section_template.xhtml.erb'))
17
- end
18
- end
19
- end
@@ -1,11 +0,0 @@
1
- <% main_title_tag = @in_composite_chapter ? 'h3' : 'h2' %>
2
- <div class="os-eoc os-<%=@container_class_type%>-container" data-type="composite-page" data-uuid-key="<%= @uuid_key %>">
3
- <<%= main_title_tag %> data-type="<%= @in_composite_chapter ? 'title' : 'document-title' %>">
4
- <span class="os-text"><%= @title %></span>
5
- </<%= main_title_tag %>>
6
- <div data-type="metadata" style="display: none;">
7
- <h1 data-type="document-title" itemprop="name"><%= @title %></h1>
8
- <%= @metadata.paste %>
9
- </div>
10
- <%= @content %>
11
- </div>