Skip to content

Instantly share code, notes, and snippets.

@bolinfest
Created October 28, 2013 16:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bolinfest/7200441 to your computer and use it in GitHub Desktop.
Save bolinfest/7200441 to your computer and use it in GitHub Desktop.
This is the script that I used to convert Appendix B of Closure: The Definitive Guide from the DocBook XML from the Manuscript to HTML.
import cgi
import re
import xml.dom.minidom
# Omit trailing slash.
HOST = 'http://www.bolinfest.com'
STYLE = """
body {
width: 825px;
margin: 5px auto;
}
body, textarea {
font-family: Arial;
font-size: 13px;
}
h1 {
font-size: 1.5em;
}
h2 {
font-size: 15px;
}
code, pre {
color: green;
}
pre.prettyprint {
border-style: none;
}
.cursor, .character-offset {
color: red;
}
.cursor, .cursor1, .cursor2 {
font-weight: bold;
}
.cursor1 {
color: red;
}
.cursor2 {
color: blue;
}
.figure {
text-align: center;
}
.caption {
margin-top: 16px;
width: 500px;
display: inline-block;
font-style: italic;
}
.aside {
padding: 8px;
background-color: #FFFCCC;
border-radius: 4px;
}
.wrapping-example {
height: 36px;
width: 190px;
}
blockquote, .wrapping-example {
margin-left: 40px;
}
.has-byline {
margin: 0;
}
.byline {
margin-bottom: 1em;
font-style: italic;
}
.article {
width: 600px;
}
#info-column {
float: right;
width: 225px;
}
#abstract, #toc {
padding-bottom: 8px;
}
.cover-container {
font-size: 11px;
}
.cover-container, .sidebar {
margin-left: 30px;
}
.cover, .sidebar {
border: 1px solid #ccc;
width: 194px;
}
.sidebar {
background-color: #f7f7f7;
}
.sidebar a {
color: #1C51A8;
font-size: 11px;
text-decoration: none;
}
.sidebar a:hover {
text-decoration: underline;
}
.sidebar-header {
font-weight: bold;
border-bottom: 1px solid #ccc;
padding-bottom: 2px;
}
.sidebar-header-inner {
padding: 2px 0 2px 4px;
}
.sidebar-content {
padding: 4px;
}
.sidebar-prose {
font-size: 11px;
}
.sidebar-list {
margin: 0;
padding-left: 1em;
list-style-position: inside;
text-indent: -1em;
}
"""
ABSTRACT = """
<div id="abstract">
<div class="sidebar">
<div class="sidebar-header">
<div class="sidebar-header-inner">Abstract</div>
</div>
<div class="sidebar-content">
<div class="sidebar-prose">%s</div>
</div>
</div>
</div>
"""
ABSTRACT_TEXT = """
Discusses common misconceptions about JavaScript that trip up developers,
both old and new.
"""
TOC = """
<div id="toc">
<div class="sidebar">
<div class="sidebar-header">
<div class="sidebar-header-inner">Table of contents</div>
</div>
<div class="sidebar-content">
<div>
<ul class="sidebar-list">
%s
</ul>
</div>
</div>
</div>
</div>
"""
PROMO = """
<div id="promo">
<div class="cover-container">
This article is an excerpt from
<em>
<a href="http://www.amazon.com/gp/product/1449381871?ie=UTF8&amp;tag=bolinfestcom-20&amp;link_code=as3&amp;camp=211189&amp;creative=373489&amp;creativeASIN=1449381871" target="_blank">Closure: The Definitive Guide</a></em>, which discusses many aspects of JavaScript in the course of detailing how to leverage
the Google Closure Tools to build large-scale JavaScript applications.
<p>
<a href="http://www.amazon.com/gp/product/1449381871?ie=UTF8&amp;tag=bolinfestcom-20&amp;link_code=as3&amp;camp=211189&amp;creative=373489&amp;creativeASIN=1449381871" target="_blank"><img class="cover" src="http://bolinfest.com/plovr/cover_big.png"></a>
</p>
</div>
</div>
"""
INTRO = """
<em>This is a complete "reprint" of Appendix B from my book,</em>
</em><a href="http://www.amazon.com/gp/product/1449381871?ie=UTF8&amp;tag=bolinfestcom-20&amp;link_code=as3&amp;camp=211189&amp;creative=373489&amp;creativeASIN=1449381871" target="_blank">Closure: The Definitive Guide</a></em><em>.
Even though my book was designed to focus on Closure rather than JavaScript in general,
there were a number of pain
points in the language that I did not think were covered well in other popular JavaScript books,
such as </em><a href="http://www.amazon.com/gp/product/0596517742/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596517742&linkCode=as2&tag=bolinfestcom-20">JavaScript: The Good Parts</a><em> or
</em><a href="http://www.amazon.com/gp/product/0596805527/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596805527&linkCode=as2&tag=bolinfestcom-20">JavaScript: The Definitive Guide</a><em>.
So that the book did not lose its focus, I relegated this and my essay,
<a href="%(host)s/javascript/inheritance.php">"Inheritance Patterns in JavaScript,"</a>
to the back of the book among the appendices.
However, many people have told me anecdotally that Appendix B
was the most valuable part of the book for them, so it seemed like this was worth sharing
more broadly in hopes that it helps demystify a language that I have enjoyed so much.
</em><hr>
""" % {'host': HOST}
FOOTER = """
<script type="text/javascript">
var _sf_async_config={uid:22053,domain:"bolinfest.com"};
(function(){
function loadChartbeat() {
window._sf_endpt=(new Date()).getTime();
var e = document.createElement('script');
e.setAttribute('language', 'javascript');
e.setAttribute('type', 'text/javascript');
e.setAttribute('src',
(("https:" == document.location.protocol) ? "https://a248.e.akamai.net/chartbeat.download.akamai.com/102508/" : "http://static.chartbeat.com/") +
"js/chartbeat.js");
document.body.appendChild(e);
}
var oldonload = window.onload;
window.onload = (typeof window.onload != 'function') ?
loadChartbeat : function() { oldonload(); loadChartbeat(); };
})();
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1213368-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<script src="%(host)s/javascript/prettify/src/prettify.js"></script>
<script>
prettyPrint();
</script>""" % {'host': HOST}
def esc(str):
return cgi.escape(str).encode('ascii', 'xmlcharrefreplace')
def transform(document, date, abstract):
html_chunks = []
sections = []
create_content(document.documentElement, title_count=[0], out=html_chunks, sections=sections)
out = '<!doctype html>'
out += '<html>'
out += '<head>'
out += '<script type="text/javascript">var _sf_startpt=(new Date()).getTime()</script>'
title = document.getElementsByTagName('title')[0].firstChild.nodeValue
out += '<title>%s</title>' % esc(title)
out += '<link rel="stylesheet" type="text/css" href="%s/javascript/prettify/src/prettify.css">' % HOST
out += '<link rel="SHORTCUT ICON" href="/bolinfest.png">'
out += '<style>%s</style>' % STYLE
out += '</head>'
out += '<body>'
out += '<div id="info-column">'
out += create_info_column(abstract, sections)
out += '</div>'
out += '<div id="content">'
out += '<div class="article">'
out += create_byline(title, date)
out += INTRO
out += ''.join(html_chunks)
out += '</div>' # class="article"
out += '</div>' # id="content"
out += FOOTER
out += '</body>'
out += '</html>'
return out
def create_byline(title, date):
return """\
<div>
<img src="%(host)s/javascript/Michael_Bolin.png" style="float: right" width="60">
<h1 class="has-byline">%(title)s</h1>
<div class="byline">by <a rel="author" href="https://profiles.google.com/u/0/107176920289865686893">Michael Bolin</a>, %(date)s</div>
</div>
<br>""" % {'host': HOST, 'title': title, 'date': date}
def create_info_column(abstract, sections):
out = ABSTRACT % abstract
items = ''
for section in sections:
items += '<li><a href="#%s">%s</a></li>' % (section['id'], esc(section['title']))
out += TOC % items
out += PROMO
return out
def create_content(node, title_count, out, sections):
tag = None
class_name = None
id_attr = None
node_type = node.nodeType
if node_type == xml.dom.minidom.Node.ELEMENT_NODE:
node_name = node.nodeName
if node_name in ['appendix', 'sect1']:
# Ignore these, so do not set `tag`.
None
elif node_name == 'para':
tag = 'p'
elif node_name == 'programlisting':
tag = 'pre'
class_name = 'prettyprint'
elif node_name == 'code':
tag = 'code'
elif node_name == 'emphasis':
tag = 'em'
elif node_name == 'xref':
linkend = node.getAttributeNode('linkend').nodeValue
if linkend == 'advanced_compilation':
out.append('Chapter 13')
elif linkend == 'prototype_chain':
out.append('Figure B-1')
elif linkend == 'utilities':
out.append('Chapter 4')
elif linkend == 'goog-global':
out.append('"goog.global"')
else:
raise Exception('Unrecognized linkend: ' + linkend)
# <xref> is a leaf node, so just return.
return
elif node_name == 'title':
if title_count[0] >= 2:
tag = 'h1'
title_text = node.firstChild.nodeValue
id_attr = title_text
id_attr = re.sub(r'[^A-Za-z]', '-', id_attr)
id_attr = re.sub(r'-+', '-', id_attr)
id_attr = id_attr.lower()
sections.append({"id": id_attr, "title": title_text})
else:
# Record that we have a title element.
title_count[0] += 1
return
elif node_name == 'figure' and node.getAttributeNode('id').nodeValue == 'prototype_chain':
out.append('<img src="%(host)s/javascript/appendix_b_box_and_arrow.png" style="width: 600px">' % {'host': HOST})
return
else:
raise Exception('Unexpected node type: ' + node_name)
elif node_type == xml.dom.minidom.Node.TEXT_NODE:
out.append(esc(node.nodeValue))
if tag:
if class_name:
out.append('<%s class="%s">' % (tag, class_name))
elif id_attr:
out.append('<%s id="%s">' % (tag, id_attr))
else:
out.append('<%s>' % tag)
for child in node.childNodes:
create_content(child, title_count, out, sections)
if tag:
out.append('</%s>' % tag)
def main():
document = xml.dom.minidom.parse('js_concepts.xml')
html = transform(document, date='October 28, 2013', abstract=ABSTRACT_TEXT)
print html
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment