This is a list:
- One.
- Two.
- Three.
Miguel A. Gabriel - magabriel@gmail.com
Version 2019.1.915 - 202112111841
ALL RIGHTS RESERVED. This book contains material protected under International and Federal Copyright Laws and Treaties. Any unauthorized reprint or use of this material is prohibited. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording, or by any information storage and retrieval system without express written permission from the author and/or publisher.
This is the documentation of trefoil, a project conceived as an extension to easybook (https://easycorp.io/EasyBook).
trefoil extends easybook to provide additional features for publication of ebooks, both fiction and non-fiction.
This documentation is a trefoil book itself, intended to be published into one of the supported formats.
To create the documentation, go to the directory where trefoil is installed and run one of the following commands:
To get the epub version:
book publish trefoil-doc ebook
To get the kindle version (please ensure you have the kindlegen
application
installed):
book publish trefoil-doc kindle
To get the pdf version:
book publish trefoil-doc print
To get the doc-website version:
book publish trefoil-doc doc-website
Other formats may be supported, so look at
<trefoil-dir>/doc/trefoil-doc/config.yml
to see all the options available.
Application Code
Copyright (c) 2014 Miguel Angel Gabriel magabriel@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Libraries and packages used
See their own license files in
vendor/
directoryResources used
See their own license files in
app/Resources/
directory
The whats, whys and hows of trefoil.
This project aims to provide a great tool for creating ebooks. It does that by extending the already superb easybook (https://easycorp.io/EasyBook) to provide additional features specifically targeted towards generation of ebooks.
1.- Clone the trefoil repository:
mkdir trefoil git clone http://github.com/magabriel/trefoil trefoil/
2.- Download the vendors and dependencies:
cd trefoil/ php composer.phar install
You should really be familiar with the easybook documentation https://easycorp.io/EasyBook to understand what’s going on here ;)
The basic usage is the same as easybook:
book publish my-book-slug my-edition
trefoil adds a new optional argument --themes_dir
that allows using
custom themes stored in whatever location in the file system:
book publish my-book-slug my-edition --themes_dir=../my/themes/directory
Example:
book publish the-origin-of-species ebook --themes_dir=~/themes/trefoil
If you are reading this, it is assumed that you are familiar with easybook documentation. If you are not, please go to http://easybook-project.org and read it. You can even install a test version of easybook and play with it a little to gain first-hand knowledge of its capabilities. When you are done with it you should return to this document and continue reading.
trefoil is not a fork of easybook but an extension.
trefoil has been developed as an extension of easybook, so it is fully backwards compatible with easybook. That means that any book prepared to be published by easybook should publish under trefoil without alterations.
easybook is a wonderful project that really eases auto-publishing work, making possible to get professional results with limited knowledge or resources. But it is primarily focused on the technical writer, lacking some features needed by non-technical works, both fiction and non-fiction. While these features could of course be implemented into easybook itself, the extension approach was chosen because of the progressive nature of the development (the features were being developed as needed, during preparation of a real book that was eventually published to Amazon Kindle Store). As such, it would have been highĺy impractical trying to influence easybook project to go the way we needed (and cope with the numerous mistakes that were made all over the road).
Looking at the final result, it becomes evident that some features could (or even may or should) be integrated into easybook. As on any other open source project, only time will tell.
The biggest part of trefoil functionality is implemented into the included plugins.
Plugins are the core of easybook extensibilty. But considerably more flexibility was needed in order to allow implementation of all the needed functionality, so the first task was to extend the plugins system.
The first things to be enhanced were:
There are no way of reusing user-created plugins other than copying the code from one book to another.
Plugins are not namespaced, precluding autoloading and extensibility.
All of trefoil
plugins are namespaced. The optional plugins (more on
that later) are under the namespace (you guess) Trefoil\Plugins\Optional
.
So a typical plugin now looks like:
<?php // trefoil\src\Trefoil\Plugins\Optional\AwesomePlugin.php namespace Trefoil\Plugins\Optional; use ...; class AwesomePlugin extends BasePlugin implements EventSubscriberInterface { public static function getSubscribedEvents() { //.... } //... }
BasePlugin
is a base class that provides some utility methods and
properties to plugins:
<?php // trefoil\src\Trefoil\Plugins\BasePlugin.php namespace Trefoil\Plugins; use Trefoil\Util\Toolkit; use Easybook\Events\BaseEvent; /** * Base class for all plugins * */ abstract class BasePlugin { protected $app; protected $output; protected $edition; protected $format; protected $theme; protected $item; /** * Do some initialization tasks. * Must be called explicitly for each plugin at the begining * of each event handler method. * * @param BaseEvent $event */ public function init(BaseEvent $event) { $this->event = $event; $this->app = $event->app; $this->output = $this->app->get('console.output'); $this->edition = $this->app['publishing.edition']; $this->format = Toolkit::getCurrentFormat($this->app); $this->theme = ucfirst($this->app->edition('theme')); $this->item = $event->getItem(); } //... more methods }
The init()
method defines a bunch of useful properties to make them
available for the plugins.
trefoil introduces the concept of optional plugins: each book’s edition can enable only certain plugins (easybook standard plugins, on the other hand, are always enabled).
book: .... editions: <edition-name> plugins: enabled: [ plugin1, plugin2, ...] options: ...
enabled
is a list of all the enabled plugins without the Plugin
suffix,
so if you wanted to enable plugins DropCapsPlugin
and TableExtraPlugin
for edition ebook
you would write:
book: .... editions: ebook: plugins: enabled: [ DropCaps, TableExtra ]
This chapter describes the book formatting plugins. These plugins provide functionalities to enhance the book’s appearance or to ease applying advanced formatting.
This plugin handles adding drop caps to the book, either automatically or manually.
This plugin is available for all editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ DropCaps ] options: DropCaps: levels: [1] mode: letter length: 1 elements: ['chapter']
where the options are:
levels
: The heading levels to add drop caps after. Values 1 to 6 (default: 1).mode
: Values letter
or word
(default: letter
).length
: Number of letters or words to turn into drop caps (default: 1).elements
: Array of book elements to process (default: [‘chapter’]).There are several ways to add drop caps to the book:
Drop caps can be automatically added to the first paragraph after a heading.
This behaviour can be influenced on a per-edition base setting options in
the plugins
configuration section inside the book’s config.yml
.
This book has automatic drop caps applied with the default options.
HTML can be freely mixed into Markdown. So a way to manually add drop caps to the text is:
<span class="dropcaps">T</span>his is a paragraph that starts with a manually-added drop cap.
trefoil will produce the following HTML code that can be easily styled:
<p class="has-dropcaps"><span class="dropcaps">T</span>his is a paragraph that starts with a manually-added drop cap.</p>
Besides adding the HTML markup directly, a Markdown-like markup is provided for greater convenience.
[[T]]his text has first-letter drop caps. [[But]] this text has first-word drop caps.
will produce the following HTML:
<p class="has-dropcaps"><span class="dropcaps">T</span>his text has first-letter drop caps.</p> <p class="has-dropcaps"><span class="dropcaps">But</span> this text has first-word drop caps.</p>
and will be shown in the book as (with some dummy text added):
This text has first-letter drop caps. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumyeirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diamvoluptua.
But this text has first-word drop caps. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumyeirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diamvoluptua.
This plugin processes footnotes generated by the Markdown parser and transform them into endnotes (i.e. at the end of the book).
This plugin is available for all editions.
This plugin is deprecated. Use FootnotesExtendPlugin instead
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ FootnotesExtra ]
The Markdown parser converts footnotes into hyperlinks, where the link target is the note text at the bottom of the document.
While this behavior is adequate for printed books, ebooks are a different mattter. The “footnotes at the end of the chapter” approach does not work well for electronic reading devices or applications because the notes stand in the way of the normal reading flow.
This plugin collects all footnotes markup generated by the Markdown parser (at the end of each book element) and then generates a consolidated footnotes list element with all the book’s footnotes.
As this plugin is deprecated, it is not active for this book. Use FootnotesExtendPlugin instead.
The plugin will generate a report in the output directory called report-FootnotesPlugin.txt
with a summary of terms processed and problems found.
This plugin extends footnotes to support several formats.
This plugin is available for all editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ FootnotesExtend ] options: FootnotesExtend: type: end # (end, inject, item, inline)
where the options are:
type
: Type of footnotes to render.
end
: Normal Markdown-rendered footnotes.inject
: Inject footnotes in text.item
: Use a separated footnotes
book item.inline
: Use inline footnotes (i.e. for PrinceXML).A footnote is a short clarification text wich is associated to a certain position in the main text but without interrupting the normal reading flow.
The footnote text will be shown in another part of the text (normally the page footer, hence its name) but it could also be shown at the end of the chapter or even the end of the book.
A footnote can be created in Markdown by inserting [^note1]
at the desired
text position, where note1 is just a key1 which will not be shown to
the user and that it is only used to associate the footnote to its text.
The footnote’s text can be defined2 with a paragraph containing:
[^note1]: This the footnote's text.
which can be placed anywhere in the same document.
The Markdown parser converts footnotes into hyperlinks, where the link target
is the note text at the bottom of the document (for easybook
and trefoil
books that means the end of the edition item). The user can “click” in the
footnote and the footnote will be show. The user needs to “click” in another
link to return to the footnote’s position and continue reading.
While the default Markdown parser’s footnotes implementation could be adequate in certain situations, several problems arise specific to the edition format being produced:
For ebooks (epub
and mobi
formats), the “footnotes at the end of the chapter”
approach does not work well because, in electronic reading devices or applications,
the notes stand in the way of the normal reading flow.
For PDF books (which normally will be printed), it would be desirable being able to use the traditional footnotes’ rendering, while each footnote appears at the bottom of the page where it is referred. This type of rendering is called “inline footnotes” and is supported by PrinceXML rendering tool.
This plugin provides a comprehensive solution to these problems by defining four types of footnotes:
end
: This is the normal Markdown-rendered footnotes.
They will be rendered at the end of each book item, separated by an <hr/>
tag.
This is the default.
inject
: This is a variant of type end
, where each item’s footnotes will be
injected at a certain injection point inside the item itself.
Just write <div class="footnotes"></div>
at the point where where the
footnotes should be injected.
item
: All the footnotes in the book will be collected and rendered in a separated
item called ‘footnotes’ that need to exist in the book.
inline
: PrinceXML supports inline footnotes, where the full text of the note must
be inlined into the text, instead of just a reference. PrinceXML will manage the
numbering.
PrinceXML natively manages footnotes as:
some text<span class="fn">Text of the footnote</span> more text
This plugin will take care of the rendering, but one limitation is that the footnote
text cannot contain block elements (as paragraphs, tables, lists). The plugin overcomes
this partially by replacing paragraph tags with <br/>
tags.
You can see an example of footnotes in this section (look at the source text).
This plugin provides a way to tweak the book HTML after it has been generated. It works modifying the HTML code produced by the Markdown processor or by the theme templates, so the final HTML code can meet specific requirements.
This plugin is available for all editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ HtmlTweaks ]
The actual tweaks definitions are read from a separate yaml
file:
# <book-dir>/Contents/html-tweaks.yml # or # <current-theme>/<format>/Config/html-tweaks.yml # or # <current-theme>/Common/Config/html-tweaks.yml tweaks: # replacements to be made at onPreParse time onPreParse: tweak-name-free: # just a name tag: 'tag name' # tag name to find class: 'class-name' # OPTIONAL class name of tag # either one of 'insert', 'surround' or 'replace' operations insert: # insert HTML code inside the tag (surround content) open: 'some html text' # opening text close: 'more html text' # closing text surround: # surround tag with HTML code (surround the tag) open: 'some html text' # opening text close: 'more html text' # closing text replace: # replace tag with another one tag: 'another html tag' # replacement tag # replacements to be made at onPostParse time onPostParse: another-tweak-name: tag: 'tag name' # same options than onPreParse # ...
The Markdown processor generates fixed HTML structures for each Markdown tag that cannot be configured or parameterized. In occasisons could be desireable to customize the generated HTML to meet certain requierements.
Examples:
<pre>...</pre>
tags with <div class="box">...</div>
.<hr>
tag to each <h2>
tag.Instead of having to write a dedicated plugin for that task, this plugin provides the funcionality to resolve some simple cases.
This plugin uses a separate configuration file html-tweaks.yml
to provide the
tweaks’ definitions. This file can be loaded from the theme in use or from the
book contents directory.
The tweaks’ definitions are read from file html-tweaks.yml
, that can be located:
/Contents
directory/<format>/Config
directory/Common/Config
directoryThe first one found will be used. This allows distributing the tweaks as part of the theme, or customizing them for an specific book.
The onPreParse
tweaks will be made before the Markdown parser has processed the item
(so they can easyly pick any raw HTML embedded into the Markdown text), while the onPostParse
tweaks will work on the HTML produced by the Markdown processor.
# <book-dir>/Contents/html-tweaks.yml # or # <current-theme>/<format>/Config/html-tweaks.yml # or # <current-theme>/Common/Config/html-tweaks.yml tweaks: onPreParse: # enclose contents of all divs of class "one" with box1 tweak-div-one: tag: 'div' class: 'one' insert: open: '<div class="box1" markdown="1">' close: '</div>' # surround all divs of class "two" with box2 tweak-div-two: tag: 'div' class: 'two' surround: open: '<div class="box2">' close: '</div>' # replace all spans with divs tweak-span-three: tag: 'span' replace: tag: 'div' onPostParse: # enclose contents of 'pre' tags between lines tweak-pre: tag: 'pre' insert: open: '======\n' close: '\n------' # surround tables with box1 tweak-table: tag: 'table' surround: open: '<div class="box1">' close: '</div>' # convert all unordered lists into ordered lists tweak-ul: tag: 'ul' replace: tag: 'ol'
This plugin will manage the illustrations in the book.
An illustration is a delimited block which can be styled and automatically numbered.
When enabled, this plugin will take over the normal “tables” numbering
and listing of easybook
. If a table is needed as an illustration it will
need to be done with this new markup.
Ordinary tables (outside an illustration markup) will be ignored and just
parsed as Markdown tables, not easybook
tables
This plugin is available for all editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ Illustrations ]
Out of the box, easybook
provides the functionality to automatically number
figures (images) and tables (real Markdown tables). But sometimes it would be
preferrable to use some text as a figure (instead of an image) or to mix a
table with some text (as a caption, for example). This plugin provides such
functionality with a simple syntax:
{@ ======== illustration_begin("This is the illustration caption" ".optional-class") @} . . . whatever Markdown or HTML content {@ ======== illustration_end() @}
where illustration_begin()
and illustration_end()
are trefoil markers.
The .optional-class
is one or several CSS classes to be applied to style the illustration.
Trefoil markers are a kind of function call wich produces HTML code to be
processed later. They are similar to Twig
function calls but are enclosed
between {@ ... @}
delimiters.
The “======” series between the opening {@
and the function name is an optional
delimiter to help visually identifiying the block in the text.
Old syntax (deprecated)
<< ========= "This is the illustration caption" ========= {.optional-class} . . . whatever Markdown or HTML content <</ =================
ATX-style headers can be used inside the illustration content and will not be parsed by easybook (i.e. not added labels and ignored in the TOC).
The rendering of illustrations can be customized with the illustration.twig
template,
but the plugin will apply a default rendering if the template is not present.
{@ ======== illustration_begin("A list as an illustration", ".class1 .class2") @} This is a list: - One. - Two. - Three. {@ ======== illustration_end() @} {@ ======== illustration_begin("A table as an illustration", ".class1 .class2") @} This is a table: | Header 1 | Header 2 | --------- | ---------- | One | One text. | Two | Two text. {@ ======== illustration_end() @}
Will be rendered as:
This is a list:
- One.
- Two.
- Three.
This is a table:
Header 1 Header 2 One One text. Two Two text.
This plugin provides an extended image syntax to allow more precise styling of images.
This plugin is available for all editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ ImageExtra ]
Features:
Some Markdown editors provide a live preview of the rendered HTML result. Some of them even provide live preview for images (like the fabulous MdCharm), but for this to work the image path must point to the relative location of the image:
# This is the easybook way, # but the preview won't work: ![This is image 1](image1.jpeg) # You can write it this way, # an the preview will work: ![This is image 1](images/image1.jpeg)
Both ways will render exactly the same, but only the second one will produce a preview in editors like MdCharm.
trefoil extends the Markdown syntax for images providing a class
and style
arguments
with similar syntax than the HTML counterparts.
The included trefoil templates are ready to make use the extended markup. The standard easybook templates, on the other hand, are not.
![caption](image.name?class="myclass"&style="any_css_style_specification")
Example:
![Lorem ipsum](php.jpg?class="half my-class"&style="background: #cde; padding-right: 2em;")
Standard easybook image alignment syntax still works:
![ Left aligned](php.jpg?class="narrower")
trefoil themes come with some predefined image classes:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam sit amet velit a libero congue molestie. Integer ipsum massa, posuere nec massa eu, dapibus volutpat justo. Nullam enim dolor, scelerisque non dui et, ornare ultricies enim. Mauris sed felis sem. Praesent aliquam quam nec diam mollis ultrices. Nunc mattis pretium tellus, et luctus augue commodo sed. Interdum et malesuada fames ac ante ipsum primis in faucibus. Ut orci tortor, malesuada ac mauris sit amet, ornare sollicitudin massa.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam sit amet velit a libero congue molestie. Integer ipsum massa, posuere nec massa eu, dapibus volutpat justo. Nullam enim dolor, scelerisque non dui et, ornare ultricies enim. Mauris sed felis sem. Praesent aliquam quam nec diam mollis ultrices. Nunc mattis pretium tellus, et luctus augue commodo sed. Interdum et malesuada fames ac ante ipsum primis in faucibus. Ut orci tortor, malesuada ac mauris sit amet, ornare sollicitudin massa.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam sit amet velit a libero congue molestie. Integer ipsum massa, posuere nec massa eu, dapibus volutpat justo. Nullam enim dolor, scelerisque non dui et, ornare ultricies enim. Mauris sed felis sem. Praesent aliquam quam nec diam mollis ultrices. Nunc mattis pretium tellus, et luctus augue commodo sed. Interdum et malesuada fames ac ante ipsum primis in faucibus. Ut orci tortor, malesuada ac mauris sit amet, ornare sollicitudin massa.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam sit amet velit a libero congue molestie. Integer ipsum massa, posuere nec massa eu, dapibus volutpat justo. Nullam enim dolor, scelerisque non dui et, ornare ultricies enim. Mauris sed felis sem. Praesent aliquam quam nec diam mollis ultrices. Nunc mattis pretium tellus, et luctus augue commodo sed. Interdum et malesuada fames ac ante ipsum primis in faucibus. Ut orci tortor, malesuada ac mauris sit amet, ornare sollicitudin massa.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam sit amet velit a libero congue molestie. Integer ipsum massa, posuere nec massa eu, dapibus volutpat justo. Nullam enim dolor, scelerisque non dui et, ornare ultricies enim. Mauris sed felis sem. Praesent aliquam quam nec diam mollis ultrices. Nunc mattis pretium tellus, et luctus augue commodo sed. Interdum et malesuada fames ac ante ipsum primis in faucibus. Ut orci tortor, malesuada ac mauris sit amet, ornare sollicitudin massa.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam sit amet velit a libero congue molestie. Integer ipsum massa, posuere nec massa eu, dapibus volutpat justo. Nullam enim dolor, scelerisque non dui et, ornare ultricies enim. Mauris sed felis sem. Praesent aliquam quam nec diam mollis ultrices. Nunc mattis pretium tellus, et luctus augue commodo sed. Interdum et malesuada fames ac ante ipsum primis in faucibus. Ut orci tortor, malesuada ac mauris sit amet, ornare sollicitudin massa.
This plugin provides several tweaks to make the ebook more compatible with Kindle MOBI format.
This is only needed for the old MOBI format, not the new KF8 format, so if you are not targeting old Kindle devices you may not need this plugin.
This plugin is available for Epub
and Mobi
editions.
The provided tweaks are specificaly targeted to Kindle readers, but could also
be useful for some EPUB reader devices or applications. That is the reason why
the plugin is available also for Epub
editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ KindleTweaks ]
The plugin provides the following tweaks:
The Markdown processor allows two kinds of markup to generate a list:
A list without blank lines between elements: - One. - Two. - Three. The same list but element "Two" has a second line: - One. - Two. This is second line of "Two" element. - Three.
The generated HTML will look like:
<p>A list without blank lines between elements:</p> <ul> <li>One.</li> <li>Two.</li> <li>Three.</li> </ul> <p>The same list but element "Two" has a second line:</p> <ul> <li>One.</li> <li><p>Two.</p> <p>This is second line of "Two" element.</p></li> <li><p>Three.</p></li> </ul>
In the second list, elements “One” and “Three” are still rendered “as is”, but element “Two” has paragraph tags enclosing each “paragraph”. This could cause rendering issues with older Kindles, making element “Two” look different than elements “One” and “Three”.
When this plugin is activated all elements will be rendered without the extra paragraph tags, and all internal paragraph tags will be replaced by a line break tag:
<p>The same list but element "Two" has a second line:</p> <ul> <li>One.</li> <li>Two.<br/> This is second line of "Two" element.</li> <li>Three.</li> </ul>
Table cell alignment assigned via CSS classes doesn’t work in older Kindles. This plugin will assign explicit alignment via HTML attributes to the table cells.
This plugin adds support for literal lists, a kind of ordered lists where the list elements can be some literals instead of numbers.
This plugin is available for all editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ LiteralLists ]
A literal list is an ordered list using literals other than numbers.
The list literal can be one of the following:
The plugin detects the list by the type of starting literal of the first item in an unordered list, and adds the class “list-literal” to the `
<
ul>’ tag to alow styling.
At the HTML level, the following input:
<ul> <li>a) First item.</li> ... <li>x) Last item.</> </ul>
Is transformed into the following output which can be CSS styled
to look like a real list with a)...n)
literals.
<ul class="list-literal"> <li>a) First item.</li> ... <li>x) Last item.</> </ul>
Type a)
- a) The first item. - b) The second item. - c) The third item.
Will be rendered as:
Type I)
- I) The first item. - II) The second item. - II) The third item.
Will be rendered as:
Type 1º
- 1º The first item. - 2º The second item. - 3º The third item.
Will be rendered as:
Type 1ª
- 1ª The first item. - 2ª The second item. - 3ª The third item.
Will be rendered as:
This plugin allows adding manual title labels to book items.
This plugin is available for all editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ ManualTitleLabels ]
Item labels are rendered with different markup than the title, creating a nice effect,
like Chapter 1 - The first chapter title
(where Chapter 1
is the label while The
first chapter title
is the title).
Automatic labels can be added to item titles by easybook using its labeling mechanism, but sometimes it could be useful having a way to manually specify labels using markup in the source file.
This plugin provides simple markup to achieve just this, just enclosing the label part
in [[..]]
.
Example:
# [[Chapter 1]] The first chapter title
This plugin provides extra functionality to Markdown tables:
Ability to “colspan” or “rowspan” cells.
Multiline cells.
Automatic header cells for headless tables.
This plugin is available for all editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ TableExtra ]
Markdown syntax for tables is pretty limited:
Column 1 | Column 2 | Column 3 ----------|-----------|------------ 1.One | 1.Two | 1.Three 2.One | 2.Two | 2.Three
will render as:
Column 1 | Column 2 | Column 3 |
---|---|---|
1.One | 1.Two | 1.Three |
2.One | 2.Two | 2.Three |
A cell containig only "
or '
(a double or single quote) will be joined with the
above cell in the previous row:
Column 1 | Column 2 | Column 3 ----------|-----------|------------ 1.One | 1.Two | 1.Three " | 2.Two | 2.Three 1.One | 1.Two | 1.Three ' | 2.Two | 2.Three
This will render as:
Column 1 | Column 2 | Column 3 |
---|---|---|
1.One | 1.Two | 1.Three |
2.Two | 2.Three | |
1.One top | 1.Two | 1.Three |
2.Two | 2.Three |
Usin single quote instead of double quote will make the rowspanned cell contents align to the cell top of instead than the middle.
An empty cell will be joined whith the preceding cell in the same row:
Column 1 | Column 2 | Column 3 ----------|-----------|------------ 1.One || 1.Three 2.One | 2.Two | 2.Three
This will render as:
Column 1 | Column 2 | Column 3 |
---|---|---|
1.One | 1.Three | |
2.One | 2.Two | 2.Three |
To avoid a blank cell to be interpreted as colspanned, enter
as its contents, as in the following example.
Column 1 | Column 2 | Column 3 |
---|---|---|
1.One | 1.Three | |
2.One | 2.Two | 2.Three |
The following example mixes rowspanned and colspanned cells and makes use of table column alignment syntax:
Column 1 | Column 2 | Column 3 ---------:|:----------|:----------: 1.One || 1.Three " || 2.Three 3.One | 3.Two | 3.Three 4.One | 4.Two | 4.Three
The rendered result will be:
Column 1 | Column 2 | Column 3 |
---|---|---|
1.One | 1.Three | |
2.Three | ||
3.One | 3.Two | 3.Three |
4.One | 4.Two | 4.Three |
This is a table with multiline cells:
Column 1 | Column 2 | Column 3 ----------|-----------|------------ One | Two | Tree: + | | - Three + | | - Three continued + | | - Three continued 2 One | Two | Three
Which will be rendered as:
Column 1 | Column 2 | Column 3 |
---|---|---|
One | Two | Tree:
|
One | Two | Three |
This is a headless table:
| | | ----------|-----------|------------ One 1 | Two 1 | Three 1 One 2 | Two 2 | Three 2
Normally rendered as:
One 1 | Two 1 | Three 1 |
One 2 | Two 2 | Three 2 |
By adding strong emphasis to some cells we have:
| | | ----------|-----------|------------ **One 1** | Two 1 | Three 1 One 2 | Two 2 | Three 2 **One 3** | Two 3 | Three 3
One 1 | Two 1 | Three 1 |
---|---|---|
One 2 | Two 2 | Three 2 |
One 3 | Two 3 | Three 3 |
This can lead to interesting effects:
| | | ----------|-----------|------------ **One 1** | | One 2 | Two 2 | Three 2 **One 3** | | One 4 | Two 4 | Three 4
One 1 | ||
---|---|---|
One 2 | Two 2 | Three 2 |
One 3 | ||
One 4 | Two 4 | Three 4 |
This plugin adds support for tabular lists, funcionality, which represents a list that can be alternatively shown as a table without loosing information (and vice versa).
Its intended use is providing an adequate representation of tables in ebooks (where wide tables are not appropriate) while maintaining the table as-is for wider formats like PDF.
This plugin is available for all editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ TabularLists ]
To activate this feature for a certain list, it must be enclosed between the following markup:
{@ ========== tabularlist_begin() @} ...the markdown list definition {@ ========== tabularlist_end() @}
where tabularlist_begin()
and tabularlist_end()
are trefoil markers.
Trefoil markers are a kind of function call wich produces HTML code to be
processed later. They are similar to Twig
function calls but are enclosed
between {@ ... @}
delimiters.
The “======” series between the opening {@
and the function name is an optional
delimiter to help visually identifiying the block in the text.
Tables are always problematic in ebooks because they do not work well in such a narrow screen (think of a table with 3 or more columns). The clasical solutions are:
Convert the table to image. This is often far from ideal and it can also become work-intensive and tedious. On the plus side, the result will also work unmodified in wider editions types, like PDF.
Convert the table to a list (“linearize” the table). This will provide better usability in an ebook reader but at the cost of losing readability on wider edition types.
So the problem we want to solve is: How to render a table as a list or a list as a table in such a way that it remains readable both in ebook (or HTML) and PDF editions?
The plugin uses the pragmatic approach of accepting the list version of the table (which works in all formats as is) and providing the transformation to table to meet the requirements of the format being rendered.
The target table looks like that:
CategoryA | CategoryB | Attribute 1 | Attribute 2 |
---|---|---|---|
A1 | B1 | A1.B1.1.1 | A1.B1.2.1 |
B2 | A1.B2.1.2 | A1.B2.2.2 | |
A2 | B3 | A2.B3.1.3 | A1.B3.2.3 |
B4 | A2.B4.1.4 | A1.B4.2.4 |
There are two categories and two attributes for each category. The representation as HTML table uses rowspan and colspan to show the relations.
This can be linearized as:
We call the above list a tabularlist, because it is a list which can be tabularized (converted to table) and get the following results:
CategoryA | CategoryB | Attribute 1 | Attribute 2 |
---|---|---|---|
A1 | B1 | A1.B1.1.1 | A1.B1.2.1 |
B2 | A1.B2.1.2 | A1.B2.2.2 | |
A2 | B3 | A2.B3.1.3 | A2.B3.2.3 |
B4 | A2.B4.1.4 | A2.B4.2.4 |
…wich is exactly the target table. But the source for the above rendering is just our input list surrounded with the appropriate markup:
{@ tabularlist_begin() @} - **CategoryA**: A1 - **CategoryB**: B1 - **Attribute 1**: A1.B1.1.1 - **Attribute 2**: A1.B1.2.1 - **CategoryB**: B2 - **Attribute 1**: A1.B2.1.2 - **Attribute 2**: A1.B2.2.2 - **CategoryA**: A2 - **CategoryB**: B3 - **Attribute 1**: A2.B3.1.3 - **Attribute 2**: A2.B3.2.3 - **CategoryB**: B4 - **Attribute 1**: A2.B4.1.4 - **Attribute 2**: A2.B4.2.4 {@ tabularlist_end() @}
The above tabularlist is using a default number of columns (by not specifying it). The plugin will infer the number of columns by adding the list deep (the number of nested lists, 3 in the example) to the number of items in the most inner list (2 in the example) minus one. So the default number of columns in the example will be 4.
The tabularlist can also be rendered with any number of columns between 0 and the maximum of 4.
This is achieved passing an optional argument to the tabularlist_begin()
with a list of pairs
of the form {key:value, ... ,key:value}
, where each key can be:
all
to represent all the cases.And the value
is the number of columns to use. Example:
{@ tabularlist_begin( {all:2} ) @}
: The table is rendered with two columns for all the
editions and formats.
{@ tabularlist_begin( {ebook:1, pdf:3} ) @}
: The table is rendered with 1 column for the
ebook
editions and three columns for all the editions with pdf
format. All other cases
are rendered with the default number of columns.
{@ tabularlist_begin( {ebook:1, pdf:3, all:2} ) @}
: The table is rendered with 1 column for the
ebook
editions and three columns for all the editions with pdf
format. All other cases
are rendered with two columns.
Rendering examples:
0 columns:
1 column:
CategoryA |
---|
A1
|
A2
|
2 columns:
CategoryA | CategoryB |
---|---|
A1 | B1
|
B2
| |
A2 | B3
|
B4
|
3 columns:
CategoryA | CategoryB | Attribute 1 |
---|---|---|
A1 | B1 | A1.B1.1.1 |
A1.B1.2.1 | ||
B2 | A1.B2.1.2 | |
A1.B2.2.2 | ||
A2 | B3 | A2.B3.1.3 |
A2.B3.2.3 | ||
B4 | A2.B4.1.4 | |
A2.B4.2.4 |
4 columns, same as the default:
CategoryA | CategoryB | Attribute 1 | Attribute 2 |
---|---|---|---|
A1 | B1 | A1.B1.1.1 | A1.B1.2.1 |
B2 | A1.B2.1.2 | A1.B2.2.2 | |
A2 | B3 | A2.B3.1.3 | A2.B3.2.3 |
B4 | A2.B4.1.4 | A2.B4.2.4 |
The plugin tries its best to produce a readable table which is consistent with the input tabularlist.
This plugin replaces certain symbols with its typographic equivalents.
It makes use of the SmartyPants
library: http://daringfireball.net/projects/smartypants/
This plugin is available for all editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ TypographyPlugin ] options: Typography: checkboxes: true fix_spanish_style_dialog: false
The following symbols are replaced with its typographic equivalents whenever appropriate:
".."
) and backtick quotes (``
..''
) are converted to typograhic double quotes (“..”)....
) are converted to the ellipsis typographic symbol (…).--
) are converted to em-dash (—).<<
and >>
) are converted to angle quotes («..»).Option checkboxes
allows writing a checkbox-like sign, both unchecked and checked.
Option fix_spanish_style_dialog
fixes the usage of dash (‘-‘) instead of em-dash (‘—’) for dialog
transcription in Spanish.
The correct way of writing dialogs between characters in Spanish books is using the em-dash symbol (“—”, called “raya” in Spanish) instead of using quotes like the English written dialogs. That is only the more obvious difference, but there are several other typographic conventions and rules that must be followed when writing dialogs in Spanish books.
The following example is extracted from “The Adventures of Sherlock Holmes: A scandal in Bohemia”:
Original dialog in English:
“Wedlock suits you,” he remarked. “I think, Watson, that you have put on seven and a half pounds since I saw you.”
“Seven!” I answered.
Spanish translation:
—El matrimonio le sienta bien —comentó—. Yo diría, Watson, que ha engordado usted siete libras y media desde la última vez que le vi.
—Siete —respondí.
This plugin extends Twig to provide some useful functionalities:
This plugin is available for all editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ TwigExtension ] options: TwigExtension: itemtoc: deep: 2 # defaults to <edition>.toc.deep + 1
The funcionalities provided are:
trefoil adds the ability to write Twig code in content:
{# this is a Twig comment inside a content item #} **Lorem ipsum** dolor sit amen. {% if 1 == 2 %} **Awesome,** it seems that 1 equals 2!!! {% else %} No, definitely 1 does not equal 2. {% endif %}
The above piece of text will render as:
Lorem ipsum dolor sit amen.
No, definitely 1 does not equal 2.
But why in the world would you want to mix Twig code or functions with your content? Some complex pieces of content could benefit from having some logic applied (example: using some book configuration option value to hide or show some section). And the ability to mix Twig comments in the text is definitely a good thing (example: to write some TODO note so you remember to change some part of the text in a future revision).
easybook only allows configuration options in templates but not in content. But thanks to the “Twig in content” functonality now you can do it:
**This will not work without this plugin:** > The title of this book is "*{{ book.title }}*".
This plugin provides such functionality, allowing the use of any configuration option in the content.
With this plugin activated, it works:
The title of this book is “Trefoil documentation”.
Large ebooks with lots of sections and subsections could benefit from having a table of contents at the begining of each chapter (think of a text book, where each lesson is a book chapter).
This plugin provides a Twig function itemtoc()
that can be inserted anywhere in the item content
(thanks to the “configuration options in content” functionality).
It uses de itemtoc.twig
template that must be available either as a local or global template.
Usage:
{{ itemtoc() }}
You can see an example at the begining of each chapter of the epub
or kindle
editions
of this book.
Sometimes it could be useful to divide a large chapter into smaller pieces, and then including all the pieces into the chapter’s content.
This plugin provides a fragment()
Twig function that works pretty much like PHP’s include()
function,
allowing the inclusion of another file.
Usage:
{{ fragment(filename, variables, options) }}
where “variables” and “options” are optional hash tables where you can pass variables to the
included file as in {'variable': 'value'}
, or options that affect the rendering.
The available options are:
{'pagebreak': true}
: insert a page break after the included file (false
by default)You can see an example in the source text of this chapter. Pagebreaks will only work on Kindle
readers and certain epub
readers.
Deprecation notice: The former file()
function is deprecated. Please use fragment()
instead.
This chapter describes the utility plugins. These plugins provide functionalities that, while not related to the book’s appearance, bring useful and convenient enhancements to the publication workflow.
This plugin copies the generated file book.<ext>
to <new-name>.<ext>
.
The original book.<ext>
file can be optionally kept.
This plugin is available for all editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ EbookRename ] options: EbookRename: schema: '{publishing.book.slug}-{book.version}' keep_original: true
The naming schema is derived from Twig syntax but with single curly brackets.
Allowed variables are:
publishing.book.slug
(the book slug).book
or edition
config variable.This plugin checks the generated epub ebook using the EpubCheck
utility.
See https://github.com/IDPF/epubcheck for download options and more
information.
This plugin is available for epub
editions.
# <book-dir>/config.yml easybook: parameters: epubcheck.path: '/path/to/epubcheck.jar' epubcheck.command_options: '' book: .... editions: <edition-name> plugins: enabled: [ EpubCheck ]
EpubCheck
is a tool to validate epub
files (version 2.0 and later).
To use it, download the relevant .jar
file to some directory on your computer
and configure that path in the epubcheck.path
option of config.yml
as shown above.
You can also pass some options via the epubcheck.command_options
option.
The plugin will generate a report in the output directory called report-EpubCheckPlugin.txt
.
This plugin uncompresses the geneated book.epub
file to make it easy looking
at its contents.
This can be useful when debugging templates, to make it sure the final HTML inside the EPUB file is correct.
This plugin is available for epub
editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ EpubUncompress ]
The uncompressed contents are left into the same directory where the book.epub
file is generated.
This plugin checks all the internal and external links in the book.
This plugin is available for all editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ LinkCheckPlugin ] options: LinkCheck: check_external_links: true
Internal links are checked by looking for a valid link target, i.e. an html element whith id=”the-link-target” in the whole book. This is useful for manually inserted links or anchors in the text (remember that you can freely insert pure HTML into Markdown).
This is valid:
#### My section {anchor-to-my-section} I can link to [my section](#anchor-to-my-section). <div id="other-anchor"></div> Lorem ipsum... And also can link to [other anchor](#other-anchor)
External links are (optionally) checked for existence by performing a network lookup. This behaviour is off by default because could be very time consuming if the book has a large number of external links. To turn it on, set the following option in the book’s `config.yml’ .
The plugin will generate a report in the output directory called report-LinkCheckPlugin.txt
.
This plugin checks the book for common problems or mistakes.
This plugin is available for all editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ QualityControl ]
The checks performed are:
Unused images: Any unused image in the final book can cause problems, like adding extra
size to the generated file or even failing a validation (like the EpubCheck
utility for
epub
editions).
Emphasis marks not processed: The Markdown makes and excelent work but sometimes it can get confused with some edge cases, leaving emphasis marks slip unprocessed into the final book text.
Consider the following example, where the writer intended to add bold emphasis to word “dolor” but left an extra espace after the word inside the closing “**” (word “sadipscing”, on the other hand, is correctly emphasized):
Lorem ipsum **dolor ** sit amet, consetetur **sadipscing** elitr.
This will be rendered as:
Lorem ipsum dolor ** sit amet, consetetur **sadipscing elitr
Instead of the intended:
Lorem ipsum dolor sit amet, consetetur sadipscing elitr
The plugin will report the problem so it can be easily spotted and fixed.
The plugin will generate a report in the output directory called report-QualityCheckPlugin.txt
.
This plugin updates an optional version string from config.yml
.
The format of the version string must be "<version>.<revision>"
,
where each component is an integer and the separator is a single dot.
This plugin is available for all editions.
# <book-dir>/config.yml book: version: '1.0' # This is the version string editions: <edition-name> plugins: enabled: [ VersionUpdater ] options: VersionUpdater: increment_ver: false # don't increment the version (default) increment_rev: true # increment the revision (default)
Having a version string in book.yml
is useful because it can be used in
the templates (for example in title.twig
) to make it easy to distinguish
between two different versions of the book. Also, if you have the
TwigExtensionPlugin
enabled, you can also use its contents in any content
element.
This plugin performs an automatic update of the version string in config.yml
so you don’t have to remember incrementing the revision after each time the
book is generated.
The version is updated after the book is generated. This way is easy
to know the value of the next version of the book just looking into config.yml
.
The arguments allow selectively incrementing any of the components.
When the version
component is incremented, the revision
component is reset to 0.
You could set a normal ebook
edition that only increments the revision
component each time you produce a new “work in progress” ebook, and another
separate edition ebook-ok
to increment the version
part each time you want
to generate a “ready to publish” ebook.
Taking advantage of the editions inheritance make it even more convenient.
This chapter describes the interactive plugins. These plugins provide some interactive capabilities to ebooks, making them more appealing for textbooks or technical publications.
The auto-glossary plugin handles the generation of a glossary of terms that are automatically hyperlinked to its definitions.
This plugin is available for all editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ AutoGlossary ] options: AutoGlossary: pagebreaks: true # use pagebreaks between defined terms
The terms’ definitions are read from two files:
The global glossary definition is called auto-glossary.yml
:
# <book-dir>/Contents/auto-glossary.yml # Global glossary definitions glossary: options: # 'all': all ocurrences # 'item': (default) only first ocurrence # into an item (i.e. chapter) # 'first': first ocurrence in the whole book coverage: 'item' # Elements to process (default: "chapter") elements: ["chapter"] #### # Global definitions of terms: # # "term": Term definition # # Variants are allowed (singular, plural) # # "term[s]": Definition which is applied # to "term" and "terms" # "term [one|two]": Definition which is # applied to "term one" and "term two" #### terms: "term": Definition
The glossary definitions for each book item are named after the item it applies to
(so the glossary for chapter1.md
item should be chapter1-auto-glossary.yml
)
# <book-dir>/Contents/chapter1-auto-glossary.yml # Glossary definitions for chapter 1 glossary: #### # Definitions of terms for chapter-1: # # "term": Term definition # # Variants are allowed (singular, plural) # # "term[s]": Definition which is applied # to "term" and "terms" # "term [one|two]": Definition which is # applied to "term one" and "term two" #### terms: "term": Definition
Depending on the coverage options, each ocurrence (or only the first one) of a defined term is replaced by an hyperlink to its definition.
The glossary term definitions are of the form "term": Term definition
, where each
“term” can be either a literal expresion or a variant expression:
glossary: terms: # literal expression "Lorem ipsum": Pseudo-latin text used as filler or dummy text. # variant expressions "car[s]": Definition which is applied to "car" and "cars" "orange [car|truck]": Definition which is applied to "orange car" and "orange truck"
Using variants is possible to create defintitions that cover several cases (like singular and plural of a word or expression).
The global glossary definitions file also have an options
section with several values
that affect how the glossary terms are processed:
glossary.options.coverage
defines how many ocurrences of a term will be converted into
glossary items links:
all
: all ocurrences in the book.item
: (default) only the first ocurrence inside a content item.first
: only the first ocurrence in the whole book.elements
is a list of all element types to be processed. By default only chapter
items
are processed.
Example:
While this autoglossary implementation can potentially work for every edition type, whether it really does work depends mostly on the reader platform capabilities:
But, as this implementation is mostly focused on ebooks, even if it produces a clickable autoglossary it may not give the best results on a printed edition.
The version of the autoglossary in this documentation is not the same than the one you will get
for an epub
or mobi
ebook because of the limited capabilities of the format. Moreover,
as this documentation uses Twitter Bootstrap 3
, it has some additional differences:
epub
or mobi
versions are rendered using only HTML.Please generate the epub
or mobi
versions of this documentation
to fully appreciate the differences.
The plugin will generate a report in the output directory called report-AutoGlossaryPlugin.txt
with a summary of terms processed and problems found.
The auto-index plugin handles the generation of an index of terms which are automatically hyperlinked to its occurrences in the text. It also allows manual index entries.
This plugin is available for all editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ AutoIndex ]
This plugin replicates the “back of the book index” functionality of written books (an alphabetized, cross-referenced list of meaningful terms which helps the reader finding where in the book a topic is written about).
The index definition file is called auto-index.yml
and has the following format.
# <book-dir>/Contents/auto-index.yml index: options: # optional section # items where the auto index terms should be applied elements: [chapter] # default # definitions for automatically-added terms terms: # A simple term definition: term: text (optional) # A complex term definition (group): term: text: "Term text" (optional) terms: "subterm 1": "subterm 1 text" (optional) # ... "subterm n": "subterm n text" (optional) # definitions for manually-added terms manual-terms: # A simple term definition: term-key-1: text (optional) #A complex term definition (group): group-name: text: "Term text for group" (optional) terms: subterm-key-1: "subterm 1 text" (optional) # ... subterm-key-n: "subterm n text" (optional)
The index definitions has the following sections:
Values that affect how the index terms are processed:
elements
is a list of all element types to be processed. By default only chapter
items
are processed.The terms definitions to be included automatically in the index whenever they are found in
the book text (contolled by the options.elements
value).
A simple term has the form:
terms: term: some text
where term
is the word or expression to be indexed if found in the book text, and
some text
is the optional text to be used in the index entry as a replacement for the term
.
Example:
terms: JSON: yaml: YAML file format
Terms can include variants in their definitions, which makes it possible to create index entries that cover several cases (like singular and plural forms of a word or expression).
terms: telephone[s]: # "telephone" or "telephones" media [file|document]: # "media file" or "media document"
A complex term or group has the following form:
terms: term: text: "Term text" # optional terms: "subterm 1": "subterm 1 text" # optional # ... "subterm n": "subterm n text" # optional
Each term groups other subterms which will be indexed as part of the main term.
It is possible to add index entries by marking them explicitly (a.k.a. “the tradditional way”). To achiveve this there are two methods:
Method 1.- Using an index mark
This is a **markdown**|@| text where the previous occurrence of the word 'markdown' is marked for indexing.
The term to index is marked by inserting |@|
next to it.
Rules for manual indexing:
|@|
must be immediately following the term to index.**the term**
or _the term_
). The mark must be placed outside the closing mark.Method 2.- Enclosing the term
This is a |markdown text| where the previous occurrence of the words 'markdown text' are marked for indexing.
The term to index is marked by enclosing it between |
.
Both methods can potentially render the same results.
If the indexed term exists in the manual-terms
section of the auto-index.yml
file, its definition will be
taken into account when creating the index. If the term does not exist, it will be indexed with default values.
manual-terms
definition sectionThe definition file can optionally contain something similar to:
# manual terms definition manual-terms: term1: This is a term # A complex term definition (group): term2-group: text: "Term text for group" (optional) terms: subterm-key-1: "subterm 1 text" (optional) # ... subterm-key-n: "subterm n text" (optional)
Example:
The following paragraphs contain example index terms. You can go directly to the index section to check it out, and then click on the term link to return here.
This paragraph contains the expressions “example index term 1” and “example index term 2” which should be automatically converted into index entries.
This paragraph contains “example index term 3” which is manually marked as index term.
This paragraph has example index term 4 which is manually marked as index term. And also, a second time bold marking: the example index term 4.
While this autoindex implementation can potentially work for every edition type, whether it really does work depends mostly on the reader platform capabilities:
But, as this implementation is mostly focused on ebooks, even if it produces a clickable autoindex it may not give the best results on a printed edition.
The plugin will generate a report in the output directory called report-AutoIndexPlugin.txt
with a summary of terms processed and problems found.
The quiz plugin allows adding interactive test functionality to an ebook (mainly for epub or mobi formats, read below note on compatibility).
This plugin is available for all editions (read below note on compatibility).
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ EbookQuiz ] options: EbookQuiz: ynb: yes: [ "Yes", "True" ] no: [ "No", "False" ] both: [ "Both" ]
This plugin allows creating an ebook with some interactive functions, like a question-response test where the user is presented with a set of questions, each one with a number of predefined responses in the form of hyperlinks. The user “cliks” on one response and the “system” tells him if he has selected the right answer.
First of all, lets define the scope of our solution:
The solution MUST work on Amazon Kindle readers compatible with the new KF8 format. It MAY also work in another platforms (even with reduced functionality), but the Amazon Kindle readers are the main target.
The problem is that the KF8 format does not allow any kind of interactivity other than plain-old hyperlinks (no javascript or another client-side language), so we need to circumvent the limitation and find another way to do it.
A “Quiz” is an interactive test. There are two types of quizes:
Multiple questions / single answer, like “A: first response”, “B: second response” and so on. An especial subtype is a “True/False” test, where the only allowed responses are either “True” of “False” (with an optional “Both”). These types will be referred to as “ABC” and “YNB” respectively.
Questionnaire, where the user is presented with a series of questions that do not have a predefined set of responses but require elaboration or reasoning. When the user has created its own response he can select an option to “reveal” the right answer.
As the main target is the Amazon Kindle readers that use KF8 format (basically, a subset of EPUB3, more information here: http://wiki.mobileread.com/wiki/KF8) the solution must stick to be just HTML + CSS (without any scripting language).
Another self-imposed constraint is that the solution must respect the Markdown spirit, where the unparsed text is readable by humans. So no extraneous or made-up syntax will be used, only standard Markdown features.
All types of quizes will be implemented as standard Markdown syntax with a predefined structure. This structure is also easily readable and just “makes sense”, so even if the book doesn’t enable this plugin the resulting ebook will be valid (but without the interactive features, of course).
The different quiz types share a common syntax, with the following remarks:
The whole quiz markup is enclosed in an HTML <div>
block. This is totally allowed
by Markdown and allows the quiz to be parsed effectively by the plugin:
<div markdown="1" class="quiz-xxxxx" data-id="xxxxx">...</div>
The markdown="1"
attribute is needed in order for the contents to be processed by
the Markdown parser.
The class="quiz-xxxxx"
tells the plugin parser the quiz type that follows. Allowed
values are quiz-activity
and quiz-questionnaire
. The parser will automatically
decide if a “quiz-activity” is of type “ABC” or “YBN” (more on that later).
The data-id="xxxxx"
attribute assigns an unique id to this quiz.
The markup itself has a few optional parts. If not provided they will be left blank in the quiz rendering or assigned sensible defaults.
The questions are represented by an ordered list, and the responses with another embedded ordered list. The correct response to each question must be denoted with bold format.
Please note that the quiz markup MUST be correctly parsable by Markdown or the plugin will be unable to process it.
For the interactive solutions to be rendered, a book element of type “ebook-quiz-solution” must be present at the end of the book.
The generated quizes will only work on Amazon Kindle devices or applications with KF8 capabilities (this includes the Kindle 4 devices onwards).
KindleTweaksPlugin
interferes with this plugin. Do not enable it if you use
this plugin.
<div markdown="1" class="quiz-activity" data-id="quiz-id-1"> ##### Activity 1 heading ###### Activity subheading (optional). Activity description (optional). Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam non umyeirmod. 1. First question. 1. **First response.** 2. Second response. 3. Third response. 2. Second question. 1. First response. 2. **Second response**. This is an optional explanation. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumyeirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diamvoluptua. 3. Third response. 4. Fourth response. </div>
<div markdown="1" class="quiz-activity" data-id="quiz-id-2"> ##### Activity 2 heading ###### Activity subheading (optional). Activity description (optional). Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam non umyeirmod. 1. First question. 1. **True** This is the correct response (true). 2. False 2. Second question. 1. True 2. **False** This is the correct response (false). </div>
<div markdown="1" class="quiz-questionnaire" data-id="quiz-id-3" > ##### Questionnaire 1 heading ###### Questionnaire subheading (optional). Questionnaire description (optional). Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam non umyeirmod. 1. First question. ###### Solution The solution to the first question (optional). 2. Second question. 3. Third question. ###### Solution The solution to the third question (optional). </div>
The quizes shown above as examples will render as follows:
The following rendered version of the examples is not the same
than the one you will get for an epub
or mobi
ebook
because of the limited capabilities of the format.
Main differences are:
epub
or mobi
versions are rendered using only HTML.Please generate the epub
or mobi
versions of this documentation
to fully appreciate the differences.
Activity description (optional). Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam non umyeirmod.
First question.
First response.
Second response.
Third response.
Second question.
First response.
Second response.
Third response.
Fourth response.
Activity description (optional). Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam non umyeirmod.
First question.
Second question.
Questionnaire description (optional). Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam non umyeirmod.
First question.
Second question.
Ask your teacher to provide the solution.
Third question.
This chapter describes the content generation plugins. These plugins provide a way to automatically generate content for your book.
This plugin allows generating wordsearch puzzles automatically, like the following one:
F | Y | S | U | N | D | A | Y | Y | P |
J | A | A | W | M | E | D | Y | W | W |
Q | D | H | D | H | P | A | M | E | L |
Y | S | H | P | S | D | E | D | E | B |
U | E | B | L | R | R | N | E | Z | A |
E | U | F | U | P | E | U | I | I | R |
C | T | T | U | S | E | X | H | G | Z |
E | A | V | D | X | K | N | L | T | Z |
S | T | A | S | Y | A | D | N | O | M |
I | Y | Y | A | D | I | R | F | M | Z |
This plugin is available for all editions.
# <book-dir>/config.yml book: editions: <edition-name> plugins: enabled: [ WordSearch ] options: WordSearch: grid_size: 20 solution_grid_size: 10 highlight_type: shadow word_files: - { label: my_label_1, name: my/words/file/path/and/name_1.txt } - { label: my_label_n, name: my/words/file/path/and/name_n.txt } default: filler: "ABCDEFGHIJKLMNOPQRSTUVWXYZ" difficulty: "medium" strings: title: "" solution_title: "" text: "" text2: "" difficulty: easy: "Dificulty: Easy" medium: "Dificulty: Medium" hard: "Dificulty: Hard" very-hard: "Dificulty: Very Hard"
This is a complex plugin with lots of options to allow extensive customization. All of them are optional and have sensible defaults that are shown in the previous YAML block.
grid_size
: Size of the puzzle grid in pixels.solution_grid_size
: Size of the solution grid in pixels.highlight_type
: The highlight type of the solution. Either line
or shadow
.word_files
: Labels for the word files to use with the automatic word selection feature. The name can include a path
and its relative to the book’s Content
directory.default
: Some default values to use.
filler
: A string with all the letters or signs to use as filler for empty puzzle places.difficulty
: The puzzle difficulty. Either easy
, medium
, hard
, or very-hard
.string
: Some string used on the puzzle and solution rendering.
easy
: Text for easy puzzles.medium
: Text for medium puzzles.hard
: Text for hard puzzles.very-hard
: Text for very hard puzzles.This feature uses several trefoil markers to achieve it complex functionality.
Trefoil markers are a kind of function call wich produces HTML code to be
processed later. They are similar to Twig
function calls but are enclosed
between {@ ... @}
delimiters.
The “======” series between the opening {@
and the function name is an optional
delimiter to help visually identifiying the block in the text.
{@ wordsearch_begin(id, {options} ) @} ...list of words... {@ wordsearch_end() @} {@ wordsearch_wordlist(id, {options} ) @} {@ wordsearch_solution(id, {options} ) @}
Arguments for wordsearch_begin()
id
: A numeric identifier for a particular puzzle. It is used to link all the other trefoil marker calls together.options
: A list of argument in the form {key:value, … ,key:value}. They are:
rows
: The number of rows of the puzzle.cols
: The number of columns of the puzzle.filler
: A string with all the letters or signs to use as filler for empty puzzle places.title
: The title of the puzzle.
<span>%s</span>Puzzle<span>%s</span>
text
: A text to show before the puzzle. It can include HTML markup.text2
: Another text. It can include HTML markup.difficulty
: Difficulty of the puzzle. Either easy
, medium
, hard
, or very-hard
.seed
: The seed used for the pseudo-random numbers generator (see explanation below). If not provided, the
pluting will generate a different puzzle on each run, so it is better to set a specific seed to get repeatable
results.list of words
is a list with the words to use in the puzzle.
The puzzle difficulty can be graduated as follows:
easy
: Not very long words, never reversed.
medium
: Not very long words, with a few of them reversed.
hard
: Longer words, with a few of them reversed.
very-hard
: Longer words, always reversed.
Arguments for wordsearch_wordlist()
id
: The id of the puzzle to show the wordlist.options
A list of argument in the form {key:value, … ,key:value}. They are:
sorted
: Whether the list should be shown sorted or unsorted. Default is unsorted.chunks
: The number of parts that the wordlist should be divided into. Useful for styling the list in columns.
Default is 1.Arguments for wordsearch_solution()
id
: The id of the puzzle to show the wordlist.options
A list of argument in the form {key:value, … ,key:value}. They are:
This plugin uses a pseudo-random number generator to generate all the needed variations.
The difference with a true random numbers generator is that, while the true random generator
will generate a true random sequence, the pseudo-random one will generate a repeatable sequence
that is only apparently random.
Pseudo-random number generators use a “seed” to start the sequence. Two sequences using the
same seed will be identical.
Example
{@ wordsearch_begin( 100, { seed: 1, rows: 10, cols: 10, title: 'This is the puzzle', text: 'Days of the week in Spanish.', text2: 'Find the words hidden between the letters.', difficulty: 'hard' }) @} - Lunes - Martes - Miércoles - Jueves - Viernes - Sábado - Domingo {@ wordsearch_end() @} {@ wordsearch_wordlist( 100 ) @} {@ wordsearch_solution( 100, { title: 'This is the solution'} ) @}
This will render as follows:
S | D | O | M | I | N | G | O | M | L |
F | E | W | Z | Q | P | N | G | C | D |
O | K | V | L | J | S | E | E | M | D |
J | W | V | E | E | F | N | Y | J | B |
Z | D | E | N | U | N | K | K | E | O |
O | Q | U | E | Y | J | T | T | C | D |
X | L | S | E | N | R | E | I | V | A |
S | E | L | O | C | R | E | I | M | B |
G | D | S | E | T | R | A | M | I | A |
U | N | D | E | F | A | K | H | N | S |
S
|
D
|
O
|
M
|
I
|
N
|
G
|
O
|
M
|
L
|
F
|
E
|
W
|
Z
|
Q
|
P
|
N
|
G
|
C
|
D
|
O
|
K
|
V
|
L
|
J
|
S
|
E
|
E
|
M
|
D
|
J
|
W
|
V
|
E
|
E
|
F
|
N
|
Y
|
J
|
B
|
Z
|
D
|
E
|
N
|
U
|
N
|
K
|
K
|
E
|
O
|
O
|
Q
|
U
|
E
|
Y
|
J
|
T
|
T
|
C
|
D
|
X
|
L
|
S
|
E
|
N
|
R
|
E
|
I
|
V
|
A
|
S
|
E
|
L
|
O
|
C
|
R
|
E
|
I
|
M
|
B
|
G
|
D
|
S
|
E
|
T
|
R
|
A
|
M
|
I
|
A
|
U
|
N
|
D
|
E
|
F
|
A
|
K
|
H
|
N
|
S
|
{@ wordsearch(id, {options} ) @} {@ wordsearch_wordlist(id, {options} ) @} {@ wordsearch_solution(id, {options} ) @}
Arguments for wordsearch()
This marker accepts the same arguments as wordsearch_begin()
but needs additional arguments:
options
:
word_file
: The label of a file with words to choose from, as specified in the plugin options. If no file is
specified the marker will generate a puzzle with a default content (useful for quick testing);number_of_words
: The number of words to randomly select from the file.Arguments for wordsearch_wordlist()
Same usage as in the previous case.
Arguments for wordsearch_solution()
Same usage as in the previous case.
Example
Assuming that config.yml
contains:
# <book-dir>/config.yml book: ... plugins: ... options: WordSearch: ... word_files: - { label: word_file_1, name: word_file_1.txt } ...
And the following code:
{@ wordsearch( 101, { seed: 1, rows: 10, cols: 10, title: 'This is the puzzle number %s', text: 'Days of the week in Spanish.', text2: 'Find the words hidden between the letters.', difficulty: 'hard', word_file: 'word_file_1', number_of_words: 10 }) @} {@ wordsearch_wordlist( 101 ) @} {@ wordsearch_solution( 101, { title: 'Solution %s'} ) @}
This will render as follows:
A | D | E | Q | U | A | T | E | S | F |
S | C | I | H | N | X | T | C | E | M |
B | Z | C | T | K | U | W | N | R | N |
V | P | S | O | L | C | O | A | I | U |
A | F | F | O | R | D | I | V | U | P |
S | K | S | W | S | D | B | D | Q | S |
A | B | R | O | A | D | I | A | C | K |
A | D | D | I | T | I | O | N | A | L |
A | D | D | R | E | S | S | X | G | N |
A | D | V | E | N | T | U | R | E | O |
A
|
D
|
E
|
Q
|
U
|
A
|
T
|
E
|
S
|
F
|
S
|
C
|
I
|
H
|
N
|
X
|
T
|
C
|
E
|
M
|
B
|
Z
|
C
|
T
|
K
|
U
|
W
|
N
|
R
|
N
|
V
|
P
|
S
|
O
|
L
|
C
|
O
|
A
|
I
|
U
|
A
|
F
|
F
|
O
|
R
|
D
|
I
|
V
|
U
|
P
|
S
|
K
|
S
|
W
|
S
|
D
|
B
|
D
|
Q
|
S
|
A
|
B
|
R
|
O
|
A
|
D
|
I
|
A
|
C
|
K
|
A
|
D
|
D
|
I
|
T
|
I
|
O
|
N
|
A
|
L
|
A
|
D
|
D
|
R
|
E
|
S
|
S
|
X
|
G
|
N
|
A
|
D
|
V
|
E
|
N
|
T
|
U
|
R
|
E
|
O
|
trefoil greatly enhances the functionality of easybook themes.
Themes functionality has been greatly enhanced in trefoil, making them more flexible and easy to customize. Also, trefoil themes can provide not only CCS styles and HTML templates but also images and fonts.
trefoil comes with some standard themes:
TrefoilOne
is a classic-looking theme, suitable for novels,
essays and other literary works.
TrefoilTwo
is a modern theme.
TrefoilDoc
is used for generating this documentation. It is
based on TrefoilTwo
but adds an HTML edition doc-website
that
uses Twitter Bootstrap 3
.
To use them, as always, just put the name of the theme in the
book’s config.yml
:
# <book-dir>/config.yml book: editions: <edition-name> theme: TrefoilTwo
The theme definitions will be looked up into <trefoil-dir>/app/Resources/Themes
.
If the theme is not found there, trefoil will try to use an
standard easybook theme of the same name. If that is also missing,
the standard Base
theme will be used, which is likely to cause
problems if you activated some plugin that requires a non-standard template.
trefoil themes are backwards-compatible with easybook themes, meaning that any book that can be published by easybook can also be published by trefoil. Of course, you will need to use an trefoil theme to make use of its new features.
trefoil allows creating custom themes. Their structure is the same than
the standard trefoil themes but can be created anywhere in the file system,
allowing the creation of a personal theme library without the need to modify
the trefoil app/Resources
directory.
To use a custom theme you just need to invoke the book publish
command with
the new optional argument --themes_dir
:
book publish my-book-slug my-edition --themes_dir=../my/themes/directory
Example:
book publish the-origin-of-species ebook --themes_dir=~/themes/trefoil
A theme, whether standard or custom, must follow this structure:
<themes-dir> └─ <theme-name> ├─ Common <== Common definitions │ ├─ Contents │ ├─ Resources │ │ ├─ Fonts │ │ └─ images │ └─ Templates ├─ <edition-type1> <== For edition type 1 │ ├─ Contents │ ├─ Resources │ │ ├─ images │ │ └─ Translations │ └─ Templates │ ... └─ <edition-typeN> <== For edition type N ├─ Contents ├─ Resources │ ├─ images │ └─ Translations └─ Templates
Standard trefoil themes do not support all the edition types,
but epub
and mobi
are available in each theme (please
look at each theme directory to find out which ones are available).
But you are free to implement support for other edition types in your
custom themes.
Common\Contents
directory contains default content for book items that
are common to all editions.
<edition-type>\Contents
directory contain content that is specific to
that edition.
If a content file is not found into one of these directories it will be
looked up into the standard easybook content directories (most likely,
the Base
theme).
Common\Resources\Fonts
directory contains additional font files for the book.There is no per-edition font directory, but you can select which fonts are packed into the final book for a given edition with the following configuration:
book: editions: edition-name: include_fonts: true fonts: - Inconsolata-Regular - Inconsolata-Bold
Only the listed font files will be included into the final ebook (i.e. book.epub
).
This is a useful technique for limiting the final size of an edition output by only
including the needed fonts.
Common\Templates
directory contains templates that are common to all editions.<edition-type>\Templates
directory contain templates specific to that edition.Common\Resources\images
directory contains images that are common to all editions.<edition-type>\Resources\images
directory contain images specific to that edition.You can organize the image files into whatever subdirectories structure inside the
images
directories. Upon book publishing, all of them will be copied to a flat
images
files into the book contents (so beware of duplicated names). Images
per-edition type overwrite common images of the same name.
Common\Resources\Translations
directory contains label files that are common
to all editions.
<edition-type>\Resources\Translations
directory contain label files specific to
that edition.
As usual, per-edition translations overwrite common translations.
Other enhancements and extra functionality in trefoil.
Some kinds of contents do not make sense for certain edition formats. They will be automatically excluded:
epub
ebooks usually do not include a visible table of contents (HTML TOC),
as reader apps and devices heavily rely on the navigational TOC. But it could
make sense to include it on certain situations, so a config.yml
parameter
could be added to explicitly request it:# config.yml book: editions: ebook: format: epub include_html_toc: true # An HTML TOC will be included
For books with several editions may be convenient to have a way to include some content in just one of them and not in the others, or to include an item based on the format of the edition.
Example:
Item ebook-usage-instructions.md
must only be included in ebook
and
kindle
edition.
Item pdf-print-instruccions.md
must be excluded from all editions whose
output format is not pdf
, regarding of the edition name.
To achieve that we can use content filtering. Consider the following book definition:
# config.yml book: contents: - { element: edition } - { element: toc } - { element: usage-instructions, content: usage-instructions.md, editions: [ebook, kindle] } - { element: print-instructions, content: print-instructions.md, formats: [pdf] } - { element: chapter, number: 1, content: chapter1.md }
For a content item, the following options can be added:
editions
: an array of the edition names which will contain that item.
formats
: an array of the allowed formats for that item. Only editions with these formats will
contain the item.
Prefixing the edition or format value with not-
will negate it.
In previous versions the negation prefix was ‘!’. This was changed because of a conflict with the new “custom tags” feature of the Yaml parser.
Example:
editions: [ebook, kindle]
==> only ebook
and kindle
editions.editions: [not-print]
==> all editions except print
.formats: [epub, mobi]
==> only editions with epub
or mobi
format.formats: [not-pdf]
==> all editions except those with pdf
format.If both editions
and formats
are used in the same item, it will only be included
in editions that fulfill both sets of conditions.
In some cases may be convenient to being able to somehow “import” some book config definitions into our book config, to avoid repeating common values.
Example:
Assume we are producing a series of ten books (i.e. lessons of a course) and all of them will have the same editions: ‘ebook’, ‘kindle’ and ‘print’.
We want to avoid defining again and again the same editions’ definitions in all of
ten books’ config.yml
.
This functionality allows just that:
# my_series/config.yml easybook: # all of easybook parameters book: editions: ebook: # definition of ebook edition kindle: # definition of kindle edition print: # definition of print edition
And then:
# my_series/book1/config.yml import: - ".." book: title: '...' # no 'editions' definitions!
The import
value is an array of all the directories where a suitable config.yml
file will
be looked up for inclusion. The first one will be used, and used as the base definition
in which the “local” definitions will be merged in.
The next pages contain the footnotes referred from the text.
To return to the text, please “click” on the return link of each note.
This is the book index. Each term has one or more links to its usages in the contents.
The automatic index functionality is intended for printed media (pdf
format).
While it still works in epub
, mobi
and html
editions, the results may not
be optimal because it can produce a lot of backlinks to the indexed terms.