Navigation Menu

Skip to content

Commit

Permalink
Created the ultimate TOC generator in javascript, build stylesheet fr…
Browse files Browse the repository at this point in the history
…om sass, improve rakefile by using rules
  • Loading branch information
manveru committed Apr 16, 2009
1 parent 5a37661 commit fbbdde3
Show file tree
Hide file tree
Showing 3 changed files with 429 additions and 78 deletions.
45 changes: 30 additions & 15 deletions Rakefile
Expand Up @@ -28,6 +28,7 @@ file JTR_XML => [JTR_TXT, *CHAPTER_FILES] do
end end


namespace :build do namespace :build do
# the formats going over docbook format
formats.each do |format| formats.each do |format|
jtr_dir = "#{format}/" jtr_dir = "#{format}/"
jtr_base = "journey_to_ramaze.#{format}" jtr_base = "journey_to_ramaze.#{format}"
Expand Down Expand Up @@ -56,16 +57,24 @@ namespace :build do
file(jtr_dir){ mkdir(jtr_dir) } file(jtr_dir){ mkdir(jtr_dir) }
end end


# the asciidoc-xhtml

jtr_scripts = File.expand_path('javascripts')
jtr_styles = File.expand_path('stylesheets')
jtr_css = 'stylesheets/xhtml11.css'
jtr_dir = 'asciidoc-xhtml/' jtr_dir = 'asciidoc-xhtml/'
jtr_base = 'journey_to_ramaze.html' jtr_base = 'journey_to_ramaze.html'
jtr_path = File.join(jtr_dir, jtr_base) jtr_path = File.join(jtr_dir, jtr_base)
CLOBBER.include(jtr_dir)
jtr_depends = [jtr_dir, JTR_TXT, jtr_css] + CHAPTER_FILES + XMP_FILES

CLOBBER.include(jtr_dir, File.join(jtr_styles, '**/*.css'))


file(jtr_dir){ mkdir(jtr_dir) } file(jtr_dir){ mkdir(jtr_dir) }
file jtr_path => [jtr_dir, JTR_TXT, *(CHAPTER_FILES + XMP_FILES)] do file jtr_path => jtr_depends do
scripts_dir = File.expand_path('javascripts')
sh('asciidoc', sh('asciidoc',
'--attribute', "scriptsdir=#{scripts_dir}", '--attribute', "scriptsdir=#{jtr_scripts}",
'--attribute', "stylesdir=#{jtr_styles}",
'--attribute', 'toc', '--attribute', 'toc',
'--backend', 'xhtml11', '--backend', 'xhtml11',
'--doctype', 'book', '--doctype', 'book',
Expand All @@ -89,21 +98,20 @@ namespace :xmp do
'--interpreter', RUBY '--interpreter', RUBY
] ]


SOURCE_FILES.each do |source_file| rule('.xmp' => ['.rb']) do |t|
xmp_file = source_file.sub(/\.rb$/, '.xmp') source_file = t.source
xmp_file = t.name


file xmp_file => [source_file] do invocation = (xmp_invocation + [source_file]).join(' ')
invocation = (xmp_invocation + [source_file]).join(' ')


puts "Converting #{source_file} to xmp => #{xmp_file}" puts "Converting #{source_file} to xmp => #{xmp_file}"
puts invocation puts invocation
original_source = File.read(source_file).strip original_source = File.read(source_file).strip
xmp_source = `#{invocation}`.strip xmp_source = `#{invocation}`.strip


fail("XMP failed for #{source_file}") if xmp_source == original_source fail("XMP failed for #{source_file}") if xmp_source == original_source


File.open(xmp_file, 'w+'){|xmp| xmp.write(xmp_source) } File.open(xmp_file, 'w+'){|xmp| xmp.write(xmp_source) }
end
end end


CHAPTER_FILES.each do |chapter_file| CHAPTER_FILES.each do |chapter_file|
Expand All @@ -114,3 +122,10 @@ namespace :xmp do
end end
end end
end end

rule('.css' => ['.sass']) do |t|
sh('sass',
'--style', 'compressed', # nested, compact, compressed, expaned
t.source,
t.name)
end
201 changes: 138 additions & 63 deletions javascripts/toc.js
@@ -1,70 +1,145 @@
/* Author: Mihai Bazon, September 2002 TOCCreator = {
* http://students.infoiasi.ro/~mishoo Header: function(level, text, visible, id){
* var obj = {
* Table Of Content generator level: level,
* Version: 0.4 text: text,
* id: id,
* Feel free to use this script under the terms of the GNU General Public visible: visible,
* License, as long as you do not remove or alter this notice. childs: [],
*/ mother: null,

/* modified by Troy D. Hanson, September 2006. License: GPL */
/* modified by Stuart Rackham, October 2006. License: GPL */
/* modified by Michael Fellinger, April 2009. License: GPL */

function getText(el) {
var text = "";
for (var i = el.firstChild; i != null; i = i.nextSibling) {
if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
text += i.data;
else if (i.firstChild != null)
text += getText(i);
}
return text;
}


function TocEntry(el, text, toclevel) { add_child: function(child){
this.element = el; this.childs.push(child);
this.text = text; child.mother = this;
this.toclevel = toclevel; },
}
to_html: function(out){
var ol, li, a;

if(this.visible){
li = document.createElement('li');
a = document.createElement('a');
a.innerHTML = this.text;
a.href = '#' + this.id;
li.appendChild(a);
out.appendChild(li);

if(this.childs.length > 0){
ol = document.createElement('ol');
li.appendChild(ol);

this.each_child_to_html(ol);
}
} else {
ol = document.createElement('ol');
out.appendChild(ol);
this.each_child_to_html(ol);
}

return(out);
},

each_child_to_html: function(root){
for(child_i in this.childs){
this.childs[child_i].to_html(root);
}
}
};

return(obj);
},

elements_by_tag_names: function(list, given_doc){
var doc = (doc || document);
var tag_names = list.split(',');
var tags = [];


function tocEntries(el, toclevels) { for(tag_names_i in tag_names){
var result = new Array; var partials = doc.getElementsByTagName(tag_names[tag_names_i]);
var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
// Function that scans the DOM tree for header elements (the DOM2 for(i = 0; i < partials.length; i++){
// nodeIterator API would be a better technique but not supported by all tags.push(partials[i]);
// browsers).
var iterate = function (el) {
for (var i = el.firstChild; i != null; i = i.nextSibling) {
if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
var mo = re.exec(i.tagName)
if (mo)
result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
iterate(i);
} }
} }
}
iterate(el);
return result;
}


// This function does the work. toclevels = 1..4. var test_node = tags[0];
function generateToc(toclevels) {
var toc = document.getElementById("toc"); if(!test_node){
var entries = tocEntries(document.getElementsByTagName("body")[0], toclevels); return([]);
for (var i = 0; i < entries.length; ++i) { } else if(test_node.sourceIndex){
var entry = entries[i]; tags.sort(function(a, b){ return(a.sourceIndex - b.sourceIndex); });
if (entry.element.id == "") } else if(test_node.compareDocumentPosition){
entry.element.id = "toc" + i; tags.sort(function(a, b){ return(3 - (a.compareDocumentPosition(b) & 6)); });
var a = document.createElement("a"); }
a.href = "#" + entry.element.id;
a.appendChild(document.createTextNode(entry.text)); return(tags);
var div = document.createElement("div"); },
div.appendChild(a);
div.className = "toclevel" + entry.toclevel; collect_headers: function(given_levels, doc){
toc.appendChild(div); var levels = (given_levels || 'h1,h2,h3,h4,h5');
var headers = [];
var tags = this.elements_by_tag_names(levels, doc);

for(tag_i in tags){
var tag, level, text, id

tag = tags[tag_i];
level = tag.nodeName.match('H(\\d+)')[1];
text = tag.innerHTML;

if(tag.id){
id = tag.id;
} else {
id = 'toc_' + tag_i;
tag.id = id;
}

headers.push({toclevel: level, text: text, id: id});
}

return(headers);
},

generate_ast: function(doc){
var headers = this.collect_headers(doc);
var original_root = new this.Header(1, 'ROOT', false);
var root = original_root;
root.mother = root;

for(header_i in headers){
var element = headers[header_i];
var header = new this.Header(element.toclevel, element.text, true, element.id);
var temp = root;
var i;

if(header.level == root.level){
root.mother.add_child(header);
} else if(header.level > root.level){
for(i = (header.level - 1); i > root.level; i--){
var temp_child = new this.Header(i, 'TEMP', false);
temp.add_child(temp_child);
temp = temp_child;
}

temp.add_child(header);
} else if(header.level < root.level){
for(i = header.level; i <= root.level; i++){
var temp_mother = temp.mother;
temp = temp_mother;
}

temp.add_child(header);
}

root = header;
}

return(original_root);
} }
if (entries.length == 0) };
document.getElementById("header").removeChild(toc);
function generateToc(n){
var root = document.getElementById('toc');
var ast = TOCCreator.generate_ast();
ast.to_html(root);
} }

0 comments on commit fbbdde3

Please sign in to comment.