use(require(“atomy”)) use(require(“io”)) use(require(“dynamic”))
require(“json”) require(“fileutils”)
use(require(“anatomy/html”)) data = require(“anatomy/data”)
omit-aux-var? = dynamic(false)
def(omit-aux?):
omit-aux-var?
fn(tag-url(t)):
t target match: .anchor(x): url(t part, x) .self: url(t part) .url(x): x
fn(block-style(style, content)):
style match: .tt: <pre: over(content) .verbatim: <pre(.verbatim): over(content) .class(*classes): <div(class = classes join(" ")): over(content) .classed(style, *classes): h = block-style(style, content) h attributes[.class] = classes join(" ") h .with-data(style, attrs): h = block-style(style, content) attrs each [key, val]: h attributes[i"data-#{key}"] = val h .id(style, id): h = block-style(style, content) h attributes[.id] = id h .unordered-list: <ul: over(content) .list-item: <li: over(content) .header(depth): <"h#{depth}": over(content) .inset: <div(style = "margin: 0 2em 1em"): over(content) .centered: <div(style = "text-align: center"): over(content) .margin-note: <blockquote: over(content) nil: <div: over(content)
fn(element-style(style, content)):
style match: .italic: <em: over(content) .bold: <strong: over(content) .tt: <code: over(content) .superscript: <sup: over(content) .subscript: <sub: over(content) .smaller: <span(style = "font-size: 80%"): over(content) .larger: <span(style = "font-size: 120%"): over(content) .strike: <span(style = "text-decoration: line-through"): over(content) .class(*classes): <span(class = classes join(" ")): over(content) .classed(style, *classes): h = element-style(style, content) h attributes[.class] = classes join(" ") h .id(style, id): h = element-style(style, content) h attributes[.id] = id h .with-data(style, attrs): h = element-style(style, content) attrs each [key, val]: h attributes[i"data-#{key}"] = val h .button: <button: over(content) .hyperlink(url): <a(href = url): over(content) .image(file): <img(src = file, alt = over(content)) .image(file, width): <img(src = file, alt = over(content), width = width) .font-awesome(*classes): <i(class = (["fa"] + classes) join(" ")): over(content) .svg(file): <object(data = file, type = "image/svg+xml", width = "100%", height = "100%"): <param(name = "src", value = file) .script-src(url): <script(src = url) {} .async-script-src(url): <script(async = true, defer = true, src = url) {} .aux: unless(^(omit-aux?)): over(content) .newline: <br .picture(default, mapping): sources = mapping collect [media, src]: <source(srcset = src, media = media) <picture: sources + [<img(src = default, alt = over(content))]
def(over(i & data Itemization)):
i elements collect [name, body]: <dl: [ <dt: over(name) <dd: over(body) ]
def(over(l & data OrderedList)):
<ol: l elements collect [body]: <li: over(body)
def(over(l & data List)):
<ul: l elements collect [body]: <li: over(body)
def(over(p & data Paragraph)):
<p: over(p content)
def(over(b & data Block)):
block-style(b style, b content)
def(over(t & data Target)):
<a(name = t name): nil
def(over(p & data Reference)):
if(p tag) then: <a(href = tag-url(p tag)): with(omit-aux? = true): over(p content) else: <a(.undefined): over(p content)
def(over(r & data ResolveElement)):
error(.did-not-resolve(r))
def(over(e & data Element)):
element-style(e style, e content)
def(over(nil)): nil def(over(s & String)): s def(over(a & Array)):
a collect [x]: over(x)
def(filename(p)): p tag name + “.html”
def(top(p)):
condition: p parent: if(p parent split-sections? && !(p parent inlined?)) then: p else: top(p parent) otherwise: p
def(url(p, anchor = nil)):
condition: (top(p) != p): (url(top(p)) + "#") + (anchor || p tag name) anchor: (filename(p) + "#") + anchor otherwise: filename(p)
def(toc-leaf(current-part, part)):
classes = [] when(part == current-part): classes << "current" when(part contains-part?(current-part)): classes << "active" <li(class = classes join(" ")): <a(href = url(part)): over(part title) unless(part omit-children-from-table-of-contents? || part parts empty?): <ol: part parts collect &.(Self toc-leaf(current-part, _))
def(render(part, out = “.”, done = Set new)):
when(done include?(part)): return done << part tags-file = i"#{Dir tmpdir}/#{part top tag name}-tags.js" unless(part parent): tags = search-tags(part) collect [t, d, u]: [t, d to-s, u] File open(tags-file, "w") [f]: f write(i"var SEARCH_TAGS = #{tags to-json};") part js-additions << tags-file -- call this early so the template can register its own assets/etc template = render-part-template(part, out, done) class = if(part style properties empty?) then: "normal" else: part style properties collect &.to-s join(" ") File open(i"#{out}/#{filename(part)}", "w") [f]: f write("<!DOCTYPE html>") f write( <html { <head: <meta("http-equiv" = "Content-Type", content = "text/html; charset=UTF-8") <title: StrippedTags new(over(part title)) when(part mobile-optimized?): <meta(name = "viewport", content = "width=device-width, initial-scale=1") all-css-additions(part) collect [addition]: <link(type = "text/css", rel = "stylesheet", href = addition) all-js-additions(part) collect [addition]: <script(type = "text/javascript", src = addition) {} <body(class = class): template when(analytics-id = ENV["ANALYTICS_ID"]): <script: UnescapedString new(i" (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', '#{analytics-id}', 'auto'); ga('send', 'pageview'); ") }) -- now that everything's generated, copy all recorded assets over (note that -- templates may register their own assets) unless(part parent): copy-all-assets(part, out)
def(render-part-template(part, out = “.”, done = Set new)):
(part template || Self) template-for(part, out, done)
def(all-part-assets(part)):
assets = Set new(part assets) assets += part css-additions assets += part js-additions part parts collect [sub]: assets += all-part-assets(sub) assets
def(copy-all-assets(part, out)):
all-part-assets(part) each [a]: sync-asset-to(a, out)
def(search-js-additions):
Set new( [ File expand-path("../js/jquery.js", __FILE__) File expand-path("../js/search.js", __FILE__) ])
def(template-for(part, out, done)):
part css-additions << File expand-path("../css/anatomy.css", __FILE__) part css-additions << File expand-path("../css/highlight.css", __FILE__) part js-additions += search-js-additions <div(#page): <div(#main): <div(#content): render-part(part, out, done) <div(.search): <form(action = "javascript:void(0)"): <input( type = "text" placeholder = "Search…" autocomplete = "off" #search) <ul(.search-results) {} with(omit-aux? = true): <div(#sidebar): <h2: <a(href = url(part top)): over(part top title) <ol(.toc): part top parts collect [p]: toc-leaf(part, p)
def(render-part(part, out = “.”, done = Set new)):
<div(.section, id = i"section_#{part tag name}"): over(part body) if(part split-sections? && !(part inlined?)) then: part parts collect [sub]: render(sub, out, done) when(part toc?): <ol(.toc, #table-of-contents): part parts collect [sub]: toc-leaf(part, sub) else: part parts collect [sub]: render-part(sub, out, done)
def(sync-asset-to(path, outdir)):
if(File directory?(path)) then: subdir = File join(outdir, File basename(path)) Dir entries(path) each [entry]: when((entry != ".") && (entry != "..")): sync-asset-to(File join(path, entry), subdir) else: FileUtils mkdir_p(outdir) FileUtils cp(path, File join(outdir, File basename(path)))
def(search-tags(p)):
tags = [ [ data contents-of(p title) <span(.title): <a(href = url(p)): over(p title) url(p) ] ] p tags each-key [tag-name]: tag = p find-tag(tag-name) url = tag-url(tag) tags << [ tag name if(tag display) then: <a(href = url): over(tag display) else: <span(.tag): <code: <a(href = url): tag name url ] p parts each [sub]: tags += search-tags(sub) collect [t, d, u]: [ t if(d is-a?(HTMLElement) && (d attributes[.class] == "with-parent")) then: d else: <span(.with-parent): d <span(.parent): " in " <a(href = url(p)): over(p title) u ] tags
def(all-css-additions(p)):
all-assets = Set new p css-additions each [file]: all-assets << File basename(file) all-assets += p css-url-additions p parts each [sub]: -- exclude parts that have their own page unless(top(sub) == sub): all-assets += all-css-additions(sub) all-assets
def(all-js-additions(p)):
all-assets = Set new p js-additions each [file]: all-assets << File basename(file) p parts each [sub]: -- exclude parts that have their own page unless(top(sub) == sub): all-assets += all-js-additions(sub) all-assets