Module: VivlioStarter::CLI::PostProcessCommands::BodyClassInjector

Defined in:
lib/vivlio_starter/cli/post_process/body_class_injector.rb

Overview

================================================================

Module: BodyClassInjector

【役割】

  • HTMLファイルの タグにファイルタイプクラスを付与

【処理内容】

  • ファイル名から chapter/preface/appendix などを判定
  • を に置換
  • 最初の本文章には chapter-first クラスを追加(pageカウンタリセット用)

================================================================

Class Method Summary collapse

Class Method Details

.detect_first_main_chapterString?

catalog.yml から最初の本文章を検出

Returns:

  • (String, nil)

    最初の本文章の basename、または nil



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/vivlio_starter/cli/post_process/body_class_injector.rb', line 81

def detect_first_main_chapter
  @detect_first_main_chapter ||= begin
    require_relative '../build/catalog_loader'
    catalog = Build::CatalogLoader.load_catalog
    chapters = catalog['CHAPTERS']
    return nil if chapters.nil? || chapters.empty?

    # CHAPTERSセクションの最初のエントリを取得
    first_item = chapters.first
    case first_item
    when String
      first_item.sub(/\.md\z/, '')
    when Hash
      # 部タイトルの場合は配下の最初の章を取得
      sub_items = first_item.values.first
      sub_items.is_a?(Array) && sub_items.first ? sub_items.first.to_s.sub(/\.md\z/, '') : nil
    end
  rescue StandardError
    nil
  end
end

.first_main_chapter?(html_file) ⇒ Boolean

最初の本文章かどうかを判定

Parameters:

  • html_file (String)

    HTMLファイルのパス

Returns:

  • (Boolean)


71
72
73
74
75
76
77
# File 'lib/vivlio_starter/cli/post_process/body_class_injector.rb', line 71

def first_main_chapter?(html_file)
  basename = File.basename(html_file, '.html')
  first_chapter = detect_first_main_chapter
  return false unless first_chapter

  basename == first_chapter
end

.header_mode_class(kind) ⇒ String?

ヘッダ切替(方式A)用の body クラスを種別ごとに決める。

  • chapter : theme.style(image 既定 / simple 明示)に従う
  • appendix: 常に simple(appendix.css は simple-header.css を単独 import)
  • その他 : ヘッダ CSS を import しないため付与不要(nil)

Parameters:

  • kind (Symbol)

    entry.kind

Returns:

  • (String, nil)


59
60
61
62
63
64
65
66
# File 'lib/vivlio_starter/cli/post_process/body_class_injector.rb', line 59

def header_mode_class(kind)
  case kind
  when :chapter
    Common::CONFIG.theme.style.to_s.strip.downcase == 'simple' ? 'vs-header-simple' : 'vs-header-image'
  when :appendix
    'vs-header-simple'
  end
end

.inject_body_class(html_file, entry) ⇒ Boolean

HTMLファイルの タグにファイルタイプクラスを付与

Parameters:

  • html_file (String)

    HTMLファイルのパス

  • entry (TokenResolver::Entry)

    章情報を持つ Entry オブジェクト

Returns:

  • (Boolean)

    変更があったかどうか



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/vivlio_starter/cli/post_process/body_class_injector.rb', line 26

def inject_body_class(html_file, entry)
  content = File.read(html_file, encoding: 'utf-8')
  file_type = entry.kind.to_s
  classes = [file_type]

  # ヘッダ切替(方式A・P3-3): chapter.css / appendix.css が simple/image の
  # 両ヘッダを import し、この body クラスで相互排他に有効化する。
  # 注入は literal `<body>` の gsub なので、必ずこの同一注入内で classes に足す
  # (後付けの別パスは `<body class=...>` に一致せず失敗する)。
  header_class = header_mode_class(entry.kind)
  classes << header_class if header_class

  # 最初の本文章には chapter-first クラスを追加
  classes << 'chapter-first' if entry.kind == :chapter && first_main_chapter?(html_file)

  class_attr = classes.join(' ')

  # 単純置換で <body> にクラスを付与
  # - 既存 class 属性が無いテンプレ構成を前提に、文字列置換で高速に処理
  updated = content.gsub('<body>', "<body class=\"#{class_attr}\">")

  return if updated == content

  File.write(html_file, updated, encoding: 'utf-8')
  Common.log_info("#{html_file}: <body>→class追加(#{class_attr})")
end