class Jekyll::Mathifier
Run Jekyll
documents through MathJax's node engine, transform style attributes into inline style tags and compute their hashes
Constants
- FIELDS
- MATH_TAG_REGEX
Attributes
csp_hashes[RW]
Public Class Methods
compileStyleElement(parsed_doc, style_attributes)
click to toggle source
Compile all style attributes into CSS classes in a single <style> element in the head
# File lib/jekyll-mathjax-csp.rb, line 79 def compileStyleElement(parsed_doc, style_attributes) style_content = "" style_attributes.each do |digest, style_attribute| style_content += ".mathjax-inline-#{digest}{#{style_attribute}}" end style_tag = parsed_doc.at_css("head").add_child("<style>#{style_content}</style>")[0] hashStyleTag(style_tag) end
extractStyleAttributes(parsed_doc)
click to toggle source
Extract all style attributes from SVG and container elements and replace them with a new CSS class with a deterministic name
# File lib/jekyll-mathjax-csp.rb, line 56 def extractStyleAttributes(parsed_doc) style_attributes = {} styled_tags = parsed_doc.css("svg[style],mjx-container[style]") for styled_tag in styled_tags do style_attribute = styled_tag["style"] digest = Digest::MD5.hexdigest(style_attribute)[0..15] style_attributes[digest] = style_attribute digest_class = "mathjax-inline-#{digest}" styled_tag["class"] = "#{styled_tag["class"] || ""} #{digest_class}" styled_tag.remove_attribute("style") end return style_attributes end
hashStyleTag(style_tag)
click to toggle source
Compute a CSP hash source (using SHA256)
# File lib/jekyll-mathjax-csp.rb, line 72 def hashStyleTag(style_tag) csp_digest = "'sha256-#{Digest::SHA256.base64digest(style_tag.content)}'" style_tag.add_previous_sibling("<!-- #{csp_digest} -->") @csp_hashes.add(csp_digest) end
mathable?(doc)
click to toggle source
# File lib/jekyll-mathjax-csp.rb, line 157 def mathable?(doc) (doc.is_a?(Jekyll::Page) || doc.write?) && doc.output_ext == ".html" || (doc.permalink && doc.permalink.end_with?("/")) end
mathify(docs, config)
click to toggle source
Render math in batch for all documents
# File lib/jekyll-mathjax-csp.rb, line 112 def mathify(docs, config) docs = docs.select { |d| Jekyll::Mathifier.mathable?(d) } # can be mathified? .select { |d| MATH_TAG_REGEX.match?(d.output) } # needs mathifying? .reduce({}) { |h, d| h.merge!(d.path => d) } # use #path to identify a doc return if docs.empty? Jekyll.logger.info "mathjax_csp:", "Found #{docs.length} documents." docs.each do |path, doc| Jekyll.logger.info "Checking math:", path parsed_doc = Nokogiri::HTML::Document.parse(doc.output) # Ensure that all styles we pick up weren't present before MathJax ran unless parsed_doc.css("svg[style],mjx-container[style]").empty? Jekyll.logger.error "mathjax_csp:", "Inline style on <svg> or <mjx-container> element present" Jekyll.logger.error "", "before rendering math due to misconfiguration or server-side" Jekyll.logger.abort_with "", "style injection." end end mathjaxify_input = docs.reduce({}) { |h, (path, doc)| h.merge!(path => doc.output) } .to_json mathified_docs = JSON.parse(run_mathjaxify(config, mathjaxify_input)) mathified_docs.each do |path, mathified_html| parsed_doc = Nokogiri::HTML::Document.parse(mathified_html) last_child = parsed_doc.at_css("head").last_element_child() if last_child.name == "style" # Set strip_css to true in _config.yml if you load the styles MathJax adds to the head # from an external *.css file if config["strip_css"] Jekyll.logger.info "", "Remember to <link> in external stylesheet!" last_child.remove else hashStyleTag(last_child) end end style_attributes = extractStyleAttributes(parsed_doc) compileStyleElement(parsed_doc, style_attributes) docs[path].output = parsed_doc.to_html end Jekyll.logger.info "mathjax_csp:", "Mathified #{mathified_docs.length} documents." end
run_mathjaxify(config, input)
click to toggle source
Run the MathJax node backend on a JSON input containing an file: HTML map
# File lib/jekyll-mathjax-csp.rb, line 89 def run_mathjaxify(config, input) mathified = "" exit_status = 0 command = "node #{Gem.bin_path("jekyll-mathjax-csp", "mathjaxify")}" FIELDS.each do |name, flag| unless config[name].nil? if [true, false].include? config[name] command << " " << flag else command << " " << flag << " " << config[name].to_s end end end node_path = Dir.pwd + "/node_modules" Jekyll.logger.info "mathjax_csp:", "starting node #{command}" mathified, status = Open3.capture2({"NODE_PATH" => node_path}, command, stdin_data: input) return mathified unless status != 0 Jekyll.logger.abort_with "mathjax_csp:", "Failed to execute 'bin/mathjaxify'" end