Introduce custom Jekyll tags for better glossary integration

This commit is contained in:
Jessica Yao
2017-10-17 18:23:17 -07:00
committed by Andrew Chen
parent 8ff083b0f3
commit 46d9cbe5ae
51 changed files with 546 additions and 197 deletions
+75
View File
@@ -0,0 +1,75 @@
# Custom Jekyll Plugins
This directory contains `*.rb` files that extend the original Jekyll classes and provide custom formatting for the docs site:
### `glossary_tags.rb`
A full list of glossary terms is available on the [Standardized Glossary](https://kubernetes.io/docs/reference/glossary/?fundamental=true) page. For further information about term schemas, see the [README](../_includes/templates/glossary/README.md) and the provided [`_example.yml`](../_data/glossary/_example.yml).
*NOTE: The "tags" referenced here are Liquid tags like `{% include %}`, **not** the glossary canonical tags that are used to categorize terms.*
#### (1) `glossary_definition` tag
This renders the definition of the glossary term inside a `<div>`, preserving Markdown formatting where possible. It uses the [`snippet.md` template](../_includes/templates/glossary/snippet.md).
**Usage:**
```
{% glossary_definition term_id="helm-chart" length="all" %}
```
**Parameters:**
| Name | Default | Description |
| --- | --- | --- |
| `term_id` | N/A (Required) | The `id` of the glossary term whose definition will be used. (This `id` is the same as the filename of the term, i.e. `_data/glossary/<ID>.yml`.) |
| `length` | "short" | Specifies which term definition should be used ("short" for the `short-definition`, "long" for `long-description`, "all" when both should be included). |
#### (2) `glossary_tooltip` tag
This renders the glossary term with a tooltip--when the term is moused over by the user, its definition is displayed above.
**Usage:**
```
{% glossary_tooltip text="Helm Charts" term_id="helm-chart" %}
```
This renders the following:
![glossary-tooltip](../images/metadocs/jekyll-tags-glossary-tooltip.png)
**Parameters:**
| Name | Default | Description |
| --- | --- | --- |
| `text` | the `name` of the glossary term | The text that the user will hover over to display the glossary definition. **You should include this if using the tooltip inside of a glossary term's YAML short-definition.** |
| `term_id` | N/A (Required) | The `id` of the associated glossary term. (This `id` is the same as the filename of the term, i.e. `_data/glossary/<ID>.yml`.) |
#### (3) `glossary_injector` tag
This takes the definition of the term specified by the `term_id` and uses it to populate the contents of another HTML element specified by `placeholder_id`.
**Usage:**
```
{% glossary_injector term_id="kubectl" placeholder_id="def-container" length="short" %}
```
This renders the following:
![glossary-injector](../images/metadocs/jekyll-tags-glossary-injector.gif)
*NOTE: Neither the placeholder nor the term's styling/CSS is determined by this Jekyll tag. You will need to specify this yourself in your Markdown/HTML files, i.e. by assigning a custom class.*
**Parameters:**
| Name | Default | Description |
| --- | --- | --- |
| `text` | the `name` of the glossary term | The text that the user will hover over to display the glossary definition. |
| `term_id` | N/A (Required) | The `id` of the glossary term whose definition will be used. (This `id` is the same as the filename of the term, i.e. `_data/glossary/<ID>.yml`.) |
| `placeholder_id` | N/A (Required) | The `id` of the HTML element whose contents will be populated with the definition of `term_id` |
| `length` | "short" | Specifies which term definition should be used ("short" for the `short-definition`, "long" for `long-description`, "all" when both should be included). |
+122
View File
@@ -0,0 +1,122 @@
# See /_plugins/README.md for full documentation of these custom Jekyll tags
module Jekyll
module GlossaryTags
# Base class for tags (not to be instantiated)
class Base < Liquid::Tag
VALID_PARAM_NAMES = []
LENGTH_SHORT = "short"
LENGTH_LONG = "long"
SNIPPET_TEMPLATE = "templates/glossary/snippet.md"
def initialize(tag_name, markup, options)
super
@args = {}
@markup.scan(/([\S]+=['"][^=]+["'])+/).each do |arg|
key, val = arg.first.split("=")
key = key.to_sym
next unless val
if self.class::VALID_PARAM_NAMES.include?(key)
@args[key] = val.gsub("\"", "")
end
end
end
# "abstract" method
def render(context)
raise NotImplementedError
end
protected
def glossary_term_info(context)
global_glossary_hash = context.registers[:site].data["glossary"]
unless global_glossary_hash.keys.to_set.include?(@args[:term_id])
raise StandardError,
"#{@args[:term_id]} is not a valid glossary term id. Please " \
"see ./_data/glossary/* for the complete list."
end
global_glossary_hash[@args[:term_id]]
end
def include_snippet(context)
@args[:length] ||= LENGTH_SHORT
clean_markup = @args.keys.map { |k| "#{k}=\"#{@args[k]}\"" }.join(" ")
Jekyll::Tags::IncludeTag.parse(
"include",
"#{SNIPPET_TEMPLATE} #{clean_markup}",
nil,
@parse_context
).render(context)
end
end
# Tag for displaying a glossary term's definition inline
class Definition < Base
VALID_PARAM_NAMES = [
:term_id,
:length
].freeze
def render(context)
include_snippet(context)
end
end
# Tag to display a tooltip for a specific glossary term
class Tooltip < Base
VALID_PARAM_NAMES = [
:text,
:term_id
].freeze
GLOSSARY_HOME = "/docs/reference/glossary/?all=true"
NESTED_TOOLTIPS = /{% (.*?text="(.*?)".*?) %}/
NESTED_MARKDOWN_LINKS = /(\[(.*?)\]\(.*?\))/
def render(context)
term_info = glossary_term_info(context)
external_link =
term_info["full-link"] ||
"#{GLOSSARY_HOME}#term-#{term_info["id"]}"
tooltip = term_info["short-description"].
gsub(NESTED_TOOLTIPS, '\2').
gsub(NESTED_MARKDOWN_LINKS, '\2').
strip
"<a class='glossary-tooltip' href='#{external_link}'>" \
"#{@args[:text] || term_info["name"]}" \
"<span class='tooltip-text'>" \
"#{tooltip}" \
"</span>" \
"</a>"
end
end
# Tag to inject a glossary term definition into another HTML element
class Injector < Base
VALID_PARAM_NAMES = [
:text,
:term_id,
:placeholder_id,
:length
].freeze
RENDERED_DESCRIPTION_BLOCK = /.*<p>(.+)<\/p>.*/
def render(context)
term_info = glossary_term_info(context)
description = RENDERED_DESCRIPTION_BLOCK.match(include_snippet(context))[1]
"<span class='glossary-injector' data-placeholder-id='#{@args[:placeholder_id]}'>" \
"#{@args[:text] || term_info["name"]}" \
"<span class='injector-def hide'>" \
"#{description}" \
"</span>" \
"</span>"
end
end
end
end
Liquid::Template.register_tag('glossary_definition', Jekyll::GlossaryTags::Definition)
Liquid::Template.register_tag('glossary_tooltip', Jekyll::GlossaryTags::Tooltip)
Liquid::Template.register_tag('glossary_injector', Jekyll::GlossaryTags::Injector)
+10
View File
@@ -0,0 +1,10 @@
# Filter to force liquid parsing
module Jekyll
module LiquifyFilter
def liquify(input)
Liquid::Template.parse(input).render(@context)
end
end
end
Liquid::Template.register_filter(Jekyll::LiquifyFilter)