blob: 225360772b840cc1c77c39b0027238b74d7d4ca0 [file] [log] [blame]
= Working with HTML Templates
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
The Solr Ref Guide uses Jekyll to build the HTML version of the site.
== What is Jekyll?
Jekyll is a static site generator, meaning that it takes some set of documents and produces HTML pages. It allows for templating of the pages, so each page has the same look and feel without having to code headers, footers, logos, etc., into every page.
Jekyll is an open source project written in Ruby, online at https://jekyllrb.com/.
== How We Use Jekyll
The following sections describe the main features of Jekyll that you will encounter while working with the Solr Ref Guide.
=== Jekyll-Asciidoctor Plugin
We use a plugin for Jekyll from the Asciidoctor project to integrate Jekyll with Asciidoc formatted content. The source for the plugin is available at https://github.com/asciidoctor/jekyll-asciidoc.
This plugin allows us to use Asciidoctor-style variables with Jekyll.
=== _config.yml
The `_config.yml` is a global configuration file that drives many of the options used when building the site (particularly in our use of Jekyll).
We have template-ized `_config.yml`, so in our use of Jekyll you will find it in `solr/solr-ref-guide/src` as `_config.yml.template`. This allows us to define some variables during the build and use common Lucene/Solr build parameters (such as project versions).
=== Front Matter
Front matter for Jekyll is similar to a header that defines the title of the page, and other variables that may be helpful (or even required) when rendering the page.
Every document that will be converted to HTML *must* include at least the page title at the top of the page. Page titles are defined with a single equal sign (`=`) followed by the title that will appear at the top of the page (such as `= Topic of the Page`).
Many guides to Jekyll also say that defining the `layout` in the front matter is required. However, since we only use one layout for all pages, we have defined this as a default.
The Solr Ref Guide uses the front matter to define some custom attributes on a per-page basis:
* `page-children` - ordered list of child pages, this is used to build the site navigation menu that appears to the left of each page's content.
Other page-level elements can also be defined, such as an Asciidoctor attribute that should apply only to that page, but are not needed on a regular basis.
The format for adding any parameter to the front matter is to use colons on both sides of the parameter, followed by the value for the parameter (such as `:page-toc: false`).
==== Table of Contents
There are some optional custom attributes that can be defined in pages to affect the Table of Contents presentation in Jekyll:
`toclevels`::
Changes how "deep" the TOC will be in terms of nested section/sub-section titles (default = `2`). Example: `:toclevels: 1`.
`page-show-toc`::
If this is `false`, then no TOCs will be generated for the page at all. The default is `true`, so can usually be left undefined. Example `:page-show-toc: false`.
=== Layouts
Layouts define the "look and feel" of each page. Jekyll uses https://shopify.github.io/liquid/[Liquid] for page templates.
For our implementation of Jekyll, layouts are found in `solr-ref-guide/src/_layouts`.
We currently use the `_layouts/default.html` layout for overall page structure, for almost all pages and `_layouts/page.html` for the page-level content.
The `page.html` layout is inserted into the `default.html` layout.
The main page (`index.html`) of the Ref Guide uses the `_layouts/home.html` layout.
It also still uses `_layouts/page.html` for the page-level content.
This is done because `index.html` has some special formatting and rules for how to define the page.
=== Includes
Include files are (usually) small HTML files that are pulled into a layout when a page is being built.
They are Liquid templates that define an area of the page.
This allows flexibility across layouts - all pages can have the same header without duplicating code, but different pages could have different menu options.
Include files that we use define the top navigation, the page header, and the page footer.
For our implementation of Jekyll, include files are found in `solr-ref-guide/src/_includes`.
=== Data Files
Data files include data such as lists that should be included in each page.
The left-hand navigation menu is an example of a data file.
However, in our build, the navigation is built from the `page-children` hierarchies defined on parent pages.
For our implementation of Jekyll, data files are found in `solr-ref-guide/src/_data`.
=== Asciidoctor Slim Templates
Jekyll creates all of the page elements we do not define in each `.adoc` file: the header, footer, top nav, sidebar nav, and other parts of the page that we don't worry about as we write the content of a page.
Asciidoctor converts the content in each `.adoc` file into HTML and inserts it into the Jekyll page layout we have defined (see <<Layouts>>) to make the individual HTML files that make up the Ref Guide.
While we have unlimited control over styling page content via CSS, without creating custom Asciidoctor-specific plugins or templates there is little out-of-the-box control over the elements, classes, etc. that make up the HTML pages.
In order to better support HTML5, we have customized Asciidoc's default conversion with templates found in the `_templates` directory. These templates use http://slim-lang.com/[Slim] as the template engine.
Since these templates dictate the very structure of the HTML of our content, customizing these should only be attempted in rare instances and with extensive testing for unforeseen impacts.
=== Using Bootstrap
The HTML files include https://getbootstrap.com/docs/4.1/[Bootstrap] (v4.1.3 as of April 2020, see `_includes/head.html` to confirm the Bootstrap version currently being used), so all of the components of Bootstrap are available.
The design of the Ref Guide makes extensive use of Bootstrap classes to layout the page via the Liquid templates and our customized Asciidoctor templates.
When we want to use additional components of Boostrap that require specific HTML constructs, we must define those within the page content itself (using either `<div>` elements in the content or with Asciidoctor's roles, discussed in the section).
==== Asciidoctor Roles
Asciidoctor helpfully provides a way to define custom `<div>` classes in `.adoc` files, as long as we understand how to use it.
Asciidoctor does not call these "divs" or "classes", but instead "_roles_". We can give any content a role - to images, content blocks (such as `[source]` or `[NOTE]`, etc.), even a word in the middle of a sentence.
Because roles are so flexible, they only apply to the thing - the word, content block, image, etc. - they are directly applied to. This means that if we want an entire section of content to be given a specific role in the HTML (i.e., enclosed in a `<div>`), then we need to put the content in a block.
TIP: For more on Roles in Asciidoctor, see https://asciidoctor.org/docs/user-manual/#role[Role] in the Asciidoctor User Guide.
==== Creating Tabbed Sections
Hopefully a little bit of background on roles is helpful to understanding the rest of what we'll do to create a tabbed section in a page.
See the Bootstrap docs on https://getbootstrap.com/docs/4.1/components/navs/#tabs[nav tabs] for details on how to use tabs and pills with Bootstrap. As a quick overview, tabs in Bootstrap are defined like this:
[source,html]
----
<ul class="nav nav-pills"> <--1-->
<li class="active"><a data-toggle="pill" href="#sec1">Section 1</a></li>
<li><a data-toggle="pill" href="#sect2">Section 2</a></li>
</ul>
<div class="tab-content"> <--2-->
<div id="sect1" class="tab-pane active"> <--3-->
<h3>Section 1</h3>
<p>Some content.</p>
</div>
<div id="sect2" class="tab-pane">
<h3>Section 2</h3>
<p>Some other content.</p>
</div>
</div>
----
<1> This section creates an unordered list with a line item for each tab. The `data-toggle` and `class` parameters are what tell Bootstrap how to render the content.
<2> Note the class defined here: `<div class="tab-content">`. This defines that what follows is the content that will make up the panes of our tabs. We will need to define these in our document.
<3> In our document, we need to delineate the separate sections of content that will make up each pane.
We have created some custom JavaScript that will do part of the above for us if we assign the proper roles to the blocks of content that we want to appear in the tab panes. To do this, we can use Asciidoctor's block delimiters to define the tabbed content, and the content between the tab.
. Define an "open block" (an unformatted content block), and give it the role `.dynamic-tabs`. An open block is defined by two hyphens on a line before the content that goes in the block, and two hyphens on a line after the content to end the block. We give a block a role by adding a period before the role name, like this:
+
[source,text]
----
[.dynamic-tabs]
--
The stuff we'll put in the tabs will go here.
--
----
. Next we need to define the content for the tabs between the open block delimiters.
.. We enclose each tab pane in another type of block, and "example" block. This allows us to include any kind of content in the block and be sure all of the various types of elements (heading, text, examples, etc.) are included in the pane.
.. We give the example block another role, `tab-pane`, and we must make sure that each pane has a unique ID. We assign IDs with a hash mark (\#) followed by the ID value (`#sect1`).
.. We also need to define a label for each tab. We do this by adding another role, `tab-label` to the content we want to appear as the name of the tab.
.. In the end one pane will look like this:
+
[source,text]
----
[example.tab-pane#sect1] <--1-->
==== <--2-->
[.tab-label]*Section 1* <--3-->
My content...
====
----
<1> When we define the example block with `[example]`, it's followed by `.tab-pane#sect1` as the class (each class separated by a period `.`) and the ID defined in the tab definition earlier. Those will become the classes (`class="tab-pane active"`) and ID (`id="sect1"`) in the resulting HTML.
<2> Example blocks are delimited by 4 equal signs (`====`) before and after the enclosed content.
<3> The words "Section 1" will appear in the HTML page as the label for this tab.
.. Create `[example.tab-pane#id]` sections for each tab, until you finally end up with something that looks like this:
+
[source,text]
----
[.dynamic-tabs]
--
[example.tab-pane#sect1]
====
[.tab-label]*Section 1*
My content...
====
[example.tab-pane#sect2]
====
[.tab-label]*Section 2*
My content...
====
--
----
== Building the HTML Site
An Ant target `ant build-site` when run from the `solr/solr-ref-guide` directory will build the full HTML site (found in `solr/build/solr-ref-guide/html-site`).
This target builds the navigation for the left-hand menu, and converts all `.adoc` files to `.html`, including navigation and inter-document links.
Building the HTML has several dependencies that will need to be installed on your local machine. Review the `README.adoc` file in the `solr/solr-ref-guide` directory for specific details.
Using the Gradle build does not require any local dependencies. Simply use `./gradlew buildSite` to generate the HTML files using Gradle (these will be found in `solr/solr-ref-guide/build/html-site`).
=== Build Validation
When you run `ant build-site` to build the HTML, several additional validations occur during that process. See `solr-ref-guide/tools/CheckLinksAndAnchors.java` for details of what that tool does to validate content.