Twitter Email
subspace (/ˈsʌbspɛɪs/)
A Jekyll playground site

Control jemoji with a front matter variable

Last modified: , 483 Words
04:46 on Friday, 08. October 2021 | by Admin in Jekyll

This is a very minor modification of the Jekyll jemoji plugin. It allows to set a front matter variable emjoi: false to disable emoji parsing for the entire document. The plugin is fairly simple and consists of only a single Ruby source code file with the name jemoji.rb.

The relevant change(s) can be found in the emojiable? method between lines 65 to 68. It checks for the presence of a emoji variable in the document’s data (frontmatter) and returns false when the variable is present with a value of false. This can be useful for pages that contain source code or similar content that might contain emoji character sequences when it is not desirable to parse them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# frozen_string_literal: true

require "jekyll"
require "html/pipeline"

module Jekyll
  class Emoji
    GITHUB_DOT_COM_ASSET_HOST_URL = "https://github.githubassets.com"
    ASSET_PATH = "/images/icons/"
    BODY_START_TAG = "<body"
    OPENING_BODY_TAG_REGEX = %r!<body(.*?)>\s*!m.freeze

    class << self
      def emojify(doc)
        return unless doc.output&.match?(HTML::Pipeline::EmojiFilter.emoji_pattern)

        doc.output = if doc.output.include? BODY_START_TAG
                       replace_document_body(doc)
                     else
                       src = emoji_src(doc.site.config)
                       filter_with_emoji(src).call(doc.output)[:output].to_s
                     end
      end

      # Public: Create or fetch the filter for the given  asset root.
      #
      # src - the asset root URL (e.g. https://github.githubassets.com/images/icons/)
      #
      # Returns an HTML::Pipeline instance for the given asset root.
      def filter_with_emoji(src)
        filters[src] ||= HTML::Pipeline.new([
          HTML::Pipeline::EmojiFilter,
        ], :asset_root => src, :img_attrs => { :align => nil })
      end

      # Public: Filters hash where the key is the asset root source.
      # Effectively a cache.
      def filters
        @filters ||= {}
      end

      # Public: Calculate the asset root source for the given config.
      # The custom emoji asset root can be defined in the config as
      # emoji.src, and must be a valid URL (i.e. it must include a
      # protocol and valid domain)
      #
      # config - the hash-like configuration of the document's site
      #
      # Returns a full URL to use as the asset root URL. Defaults to the root
      # URL for assets provided by an ASSET_HOST_URL environment variable,
      # otherwise the root URL for emoji assets at assets-cdn.github.com.
      def emoji_src(config = {})
        if config.key?("emoji") && config["emoji"].key?("src")
          config["emoji"]["src"]
        else
          default_asset_root
        end
      end

      # Public: Defines the conditions for a document to be emojiable.
      #
      # doc - the Jekyll::Document or Jekyll::Page
      #
      # Returns true if the doc is written & is HTML and does not forbid
      # emoji parsing via front matter variable emoji: false.
      def emojiable?(doc)       
        (doc.is_a?(Jekyll::Page) || doc.write?) && doc.data["emoji"] != false &&
          doc.output_ext == ".html" || (doc.permalink&.end_with?("/"))
      end

      private

      def default_asset_root
        if !ENV["ASSET_HOST_URL"].to_s.empty?
          # Ensure that any trailing "/" is trimmed
          asset_host_url = ENV["ASSET_HOST_URL"].chomp("/")
          "#{asset_host_url}#{ASSET_PATH}"
        else
          "#{GITHUB_DOT_COM_ASSET_HOST_URL}#{ASSET_PATH}"
        end
      end

      def replace_document_body(doc)
        src                 = emoji_src(doc.site.config)
        head, opener, tail  = doc.output.partition(OPENING_BODY_TAG_REGEX)
        body_content, *rest = tail.partition("</body>")
        processed_markup    = filter_with_emoji(src).call(body_content)[:output].to_s
        String.new(head) << opener << processed_markup << rest.join
      end
    end
  end
end

Jekyll::Hooks.register [:pages, :documents], :post_render do |doc|
  Jekyll::Emoji.emojify(doc) if Jekyll::Emoji.emojiable?(doc)
end