Skip to content
This repository has been archived by the owner on Jun 11, 2024. It is now read-only.

Commit

Permalink
Add dependencies for ascidoc extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
Tschakki committed Oct 16, 2019
1 parent 96f0a28 commit 30d91cc
Show file tree
Hide file tree
Showing 8 changed files with 649 additions and 22 deletions.
373 changes: 373 additions & 0 deletions lib/LICENSE

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions lib/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
= Asciidoctor Extensions for Antora

This repository contains Asciidoctor extensions for use in sites generated using Antora.

== Copyright and License

Copyright (C) 2018 by OpenDevise Inc. and the individual contributors to Antora.

Use of this software is granted under the terms of the https://www.mozilla.org/en-US/MPL/2.0/[Mozilla Public License Version 2.0] (MPL-2.0).
See link:LICENSE[] to find the full license text.
44 changes: 44 additions & 0 deletions lib/inline-man-macro/extension.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const { posix: path } = require('path')

/**
* Extends the AsciiDoc syntax to add support for the inline man macro.
* This macro creates a link to a man(ual) page that is suitable for
* the output format.
*
* Usage:
*
* man:grep[1]
*
* The target must be located in the same directory as the source.
*
* To use this extension, register the extension.js file with Antora (i.e.,
* list it as an AsciiDoc extension in the Antora playbook file).
*
* @author Dan Allen <dan@opendevise.com>
*/
const InlineManMacro = (() => {
const $context = Symbol('context')
const superclass = Opal.module(null, 'Asciidoctor').Extensions.InlineMacroProcessor
const scope = Opal.klass(Opal.module(null, 'Antora'), superclass, 'InlineManMacro', function () {})

Opal.defn(scope, '$initialize', function initialize (name, config, context) {
Opal.hash_put(config, 'pos_attrs', ['volnum'])
Opal.send(this, Opal.find_super_dispatcher(this, 'initialize', initialize), [name, config])
this[$context] = context
})

Opal.defn(scope, '$process', function (parent, target, attrs) {
const volnum = Opal.hash_get(attrs, 'volnum')
const content = volnum ? `${target} (${volnum})` : target
const pageId = path.join(path.dirname(this[$context].file.src.relative), target)
// NOTE the value of the path attribute is never used, so the value is arbitrary
const attributes = Opal.hash2(['refid', 'path'], { refid: pageId, path: pageId })
return this.createInline(parent, 'anchor', content, { type: 'xref', target, attributes })
})

return scope
})()

module.exports.register = (registry, context) => {
registry.inlineMacro(InlineManMacro.$new('man', Opal.hash(), context))
}
50 changes: 50 additions & 0 deletions lib/tabs-block/behavior.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
;(function () {
'use strict'

var hash = window.location.hash
find('.tabset').forEach(function (tabset) {
var active
var tabs = tabset.querySelector('.tabs')
if (tabs) {
var first
find('li', tabs).forEach(function (tab, idx) {
var id = (tab.querySelector('a[id]') || tab).id
if (!id) return
var pane = getPane(id, tabset)
if (!idx) first = { tab: tab, pane: pane }
if (!active && hash === '#' + id && (active = true)) {
tab.classList.add('is-active')
if (pane) pane.classList.add('is-active')
} else if (!idx) {
tab.classList.remove('is-active')
if (pane) pane.classList.remove('is-active')
}
tab.addEventListener('click', activateTab.bind({ tabset: tabset, tab: tab, pane: pane }))
})
if (!active && first) {
first.tab.classList.add('is-active')
if (first.pane) first.pane.classList.add('is-active')
}
}
tabset.classList.remove('is-loading')
})

function activateTab (e) {
var tab = this.tab
var pane = this.pane
find('.tabs li, .tab-pane', this.tabset).forEach(function (it) {
it === tab || it === pane ? it.classList.add('is-active') : it.classList.remove('is-active')
})
e.preventDefault()
}

function find (selector, from) {
return Array.prototype.slice.call((from || document).querySelectorAll(selector))
}

function getPane (id, tabset) {
return find('.tab-pane', tabset).find(function (it) {
return it.getAttribute('aria-labelledby') === id
})
}
})()
76 changes: 76 additions & 0 deletions lib/tabs-block/extension.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* Extends the AsciiDoc syntax to support a tabset element. The tabset is
* created from a dlist that is enclosed in an example block marked with the
* tabs style.
*
* Usage:
*
* [tabs]
* ====
* Tab A::
* +
* --
* Contents of tab A.
* --
* Tab B::
* +
* --
* Contents of tab B.
* --
* ====
*
* To use this extension, register the extension.js file with Antora (i.e.,
* list it as an AsciiDoc extension in the Antora playbook file), combine
* styles.css with the styles for the site, and combine behavior.js with the
* JavaScript loaded by the page.
*
* @author Dan Allen <dan@opendevise.com>
*/
const IdSeparatorChar = '-'
const InvalidIdCharsRx = /[^a-zA-Z0-9_]/g
const List = Opal.const_get_local(Opal.module(null, 'Asciidoctor'), 'List')
const ListItem = Opal.const_get_local(Opal.module(null, 'Asciidoctor'), 'ListItem')

const generateId = (str, idx) => `tabset${idx}_${str.toLowerCase().replace(InvalidIdCharsRx, IdSeparatorChar)}`

function tabsBlock () {
this.onContext('example')
this.process((parent, reader, attrs) => {
const createHtmlFragment = (html) => this.createBlock(parent, 'pass', html)
const tabsetIdx = parent.getDocument().counter('idx-tabset')
const nodes = []
nodes.push(createHtmlFragment('<div class="tabset is-loading">'))
const container = this.parseContent(this.createBlock(parent, 'open'), reader)
const sourceTabs = container.getBlocks()[0]
if (!(sourceTabs && sourceTabs.getContext() === 'dlist' && sourceTabs.getItems().length)) return
const tabs = List.$new(parent, 'ulist')
tabs.addRole('tabs')
const panes = {}
sourceTabs.getItems().forEach(([[title], details]) => {
const tab = ListItem.$new(tabs)
tabs.$append(tab)
const id = generateId(title.getText(), tabsetIdx)
tab.text = `[[${id}]]${title.text}`
let blocks = details.getBlocks()
const numBlocks = blocks.length
if (numBlocks) {
if (blocks[0].context === 'open' && numBlocks === 1) blocks = blocks[0].getBlocks()
panes[id] = blocks.map((block) => (block.parent = parent) && block)
}
})
nodes.push(tabs)
nodes.push(createHtmlFragment('<div class="content">'))
Object.entries(panes).forEach(([id, blocks]) => {
nodes.push(createHtmlFragment(`<div class="tab-pane" aria-labelledby="${id}">`))
nodes.push(...blocks)
nodes.push(createHtmlFragment('</div>'))
})
nodes.push(createHtmlFragment('</div>'))
nodes.push(createHtmlFragment('</div>'))
parent.blocks.push(...nodes)
})
}

module.exports.register = (registry, context) => {
registry.block('tabs', tabsBlock)
}
61 changes: 61 additions & 0 deletions lib/tabs-block/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
.tabs ul {
display: flex;
flex-wrap: wrap;
list-style: none;
margin: 0 -0.25rem 0 0;
padding: 0;
}

.tabs li {
align-items: center;
border: 1px solid black;
border-bottom: 0;
cursor: pointer;
display: flex;
font-weight: bold;
height: 2.5rem;
line-height: 1;
margin-right: 0.25rem;
padding: 0 1.5rem;
position: relative;
}

.tabs.ulist li {
margin-bottom: 0;
}

.tabs li + li {
margin-top: 0;
}

.tabset.is-loading .tabs li:not(:first-child),
.tabset:not(.is-loading) .tabs li:not(.is-active) {
background-color: black;
color: white;
}

.tabset.is-loading .tabs li:first-child::after,
.tabs li.is-active::after {
background-color: white;
content: "";
display: block;
height: 3px; /* Chrome doesn't always paint the line accurately, so add a little extra */
position: absolute;
bottom: -1.5px;
left: 0;
right: 0;
}

.tabset > .content {
border: 1px solid gray;
padding: 1.25rem;
}

.tabset.is-loading .tab-pane:not(:first-child),
.tabset:not(.is-loading) .tab-pane:not(.is-active) {
display: none;
}

.tab-pane > :first-child {
margin-top: 0;
}
Loading

0 comments on commit 30d91cc

Please sign in to comment.