Skip to content

Commit b9aceae

Browse files
committed
Initial commit
0 parents  commit b9aceae

File tree

7 files changed

+311
-0
lines changed

7 files changed

+311
-0
lines changed

.editorconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
; Unix-style newlines
2+
[*]
3+
end_of_line = LF
4+
indent_style = tab
5+
trim_trailing_whitespace = false
6+
insert_final_newline = true

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules/
2+
temp/
3+
index.html

bit-docs.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
var path = require("path");
2+
3+
module.exports = function(bitDocs){
4+
var pkg = require("./package.json");
5+
var dependencies = {};
6+
dependencies[pkg.name] = pkg.version;
7+
8+
bitDocs.register("html", {
9+
dependencies: dependencies
10+
});
11+
}

package.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"name": "bit-docs-html-toc",
3+
"version": "0.1.0",
4+
"description": "table of contents bit-docs plugin",
5+
"main": "toc.js",
6+
"scripts": {
7+
"test": "echo 'testing'",
8+
"postversion": "git push --tags && git push",
9+
"release:pre": "npm version prerelease && npm publish",
10+
"release:patch": "npm version patch && npm publish",
11+
"release:minor": "npm version minor && npm publish",
12+
"release:major": "npm version major && npm publish"
13+
},
14+
"repository": {
15+
"type": "git",
16+
"url": "git+https://github.com/bit-docs/bit-docs-prettify.git"
17+
},
18+
"keywords": [
19+
"bit-docs"
20+
],
21+
"author": "Bitovi",
22+
"license": "MIT",
23+
"bugs": {
24+
"url": "https://github.com/bit-docs/bit-docs-prettify/issues"
25+
},
26+
"homepage": "https://github.com/bit-docs/bit-docs-prettify#readme",
27+
"system": {},
28+
"dependencies": {
29+
"can-control": "^3.0.0-pre.5",
30+
"can-stache": "^3.0.0-pre.11",
31+
"can-stache-bindings": "^3.0.0-pre.8"
32+
}
33+
}

readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# bit-docs-html-toc

test.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
var generate = require("bit-docs-generate-html/generate");
2+
var Q = require("q");
3+
var path = require("path");
4+
var assert = require("assert");
5+
6+
var Browser = require("zombie"),
7+
connect = require("connect");
8+
9+
10+
var find = function(browser, property, callback, done){
11+
var start = new Date();
12+
var check = function(){
13+
if(browser.window && browser.window[property]) {
14+
callback(browser.window[property]);
15+
} else if(new Date() - start < 2000){
16+
setTimeout(check, 20);
17+
} else {
18+
done("failed to find "+property);
19+
}
20+
};
21+
check();
22+
};
23+
var waitFor = function(browser, checker, callback, done){
24+
var start = new Date();
25+
var check = function(){
26+
if(checker(browser.window)) {
27+
callback(browser.window);
28+
} else if(new Date() - start < 2000){
29+
setTimeout(check, 20);
30+
} else {
31+
done(new Error("checker was never true"));
32+
}
33+
};
34+
check();
35+
};
36+
37+
38+
var open = function(url, callback, done){
39+
var server = connect().use(connect.static(path.join(__dirname))).listen(8081);
40+
var browser = new Browser();
41+
browser.visit("http://localhost:8081/"+url)
42+
.then(function(){
43+
callback(browser, function(){
44+
server.close();
45+
})
46+
}).catch(function(e){
47+
server.close();
48+
done(e)
49+
});
50+
};
51+
52+
// somehow do a build with this added on ...
53+
54+
describe("bit-docs-prettify", function(){
55+
it("basics work", function(done){
56+
this.timeout(30000);
57+
58+
var docMap = Q({
59+
index: {
60+
name: "index",
61+
body: "```\nvar str ='hello world';\n```"
62+
}
63+
});
64+
65+
generate(docMap,{
66+
html: {
67+
dependencies: {
68+
"bit-docs-prettify": __dirname
69+
}
70+
},
71+
dest: path.join(__dirname, "temp"),
72+
parent: "index",
73+
forceBuild: true
74+
}).then(function(){
75+
76+
open("temp/index.html",function(browser, close){
77+
78+
var prettyprinted = browser.window.document.getElementsByClassName("prettyprint")
79+
80+
assert.ok(prettyprinted.length, "has a returns object")
81+
82+
close();
83+
done();
84+
85+
},done);
86+
87+
}).catch(function(err){
88+
console.log("err",err.stack);
89+
done(err)
90+
});
91+
});
92+
});

toc.js

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
var stache = require("can-stache");
2+
require("can-stache-bindings");
3+
var Control = require("can-control");
4+
5+
var template = stache("{{#each titles}}" +
6+
"<li><a ($click)='scrollTo(., %event)' href='#{{id}}'>{{text}}</a></li>" +
7+
"{{/each}}");
8+
9+
var toc = document.getElementsByClassName("on-this-page")[0];
10+
11+
function throttle(fn, ms){
12+
var wait = false;
13+
return function(){
14+
if(!wait) {
15+
wait = true;
16+
var val = fn.apply(this, arguments);
17+
setTimeout(function(){
18+
wait = false;
19+
}, ms);
20+
return val;
21+
}
22+
};
23+
}
24+
25+
var TableOfContents = Control.extend({
26+
init: function(el, options){
27+
this.scroller = document.body;
28+
this.titleSelector = options.titleSelector || ".signature-title";
29+
30+
this.navHeight = this.getNavHeight();
31+
32+
this.titles = this.collectTitles();
33+
34+
// If there are no titles, bail
35+
if(!this.titles.length) {
36+
el.parentNode.removeChild(el);
37+
return;
38+
}
39+
this.titleIndex = 0;
40+
this.calculateActive();
41+
42+
// Append our template
43+
var toc = this;
44+
this.element.appendChild(template({
45+
titles: this.titles,
46+
scrollTo: function(item, ev){
47+
ev.preventDefault();
48+
toc.disabled(true);
49+
window.scrollTo(0, item.pos + 1);
50+
toc.calculateActive();
51+
52+
requestAnimationFrame(function(){
53+
toc.disabled(false);
54+
});
55+
}
56+
}));
57+
this.setActive(this.titleIndex);
58+
59+
// Wait until we've appended the TOC so it can be part of the calculation
60+
this.fixed(!this.isFirstTitleVisible());
61+
62+
window.addEventListener("scroll", this);
63+
},
64+
65+
getNavHeight: function(){
66+
var nav = document.querySelector(".navbar");
67+
return nav.clientHeight;
68+
},
69+
70+
isFirstTitleVisible: function(){
71+
var firstPosition = this.titles[0].pos + this.element.clientHeight +
72+
this.navHeight;
73+
return firstPosition > this.scroller.scrollTop;
74+
},
75+
76+
collectTitles: function(){
77+
var titles = document.querySelectorAll("article " + this.titleSelector);
78+
var curScroll = this.scroller.scrollTop;
79+
var navHeight = this.navHeight;
80+
return [].map.call(titles, function(title, idx){
81+
var txt = title.textContent;
82+
title.id = 'sig_' + txt.replace(/\s/g,"").replace(/[^\w]/g,"_");
83+
return {
84+
id: title.id,
85+
index: idx,
86+
text: txt,
87+
pos: title.getBoundingClientRect().top + curScroll - navHeight
88+
};
89+
});
90+
},
91+
92+
fixed: function(fixed){
93+
if(fixed === this._fixed) {
94+
return;
95+
}
96+
this._fixed = fixed;
97+
this.element.classList[fixed ? "add" : "remove"]("fixed");
98+
},
99+
100+
disabled: function(disabled){
101+
this.element.classList[disabled ? "add" : "remove"]("disabled");
102+
},
103+
104+
getTitle: function(idx){
105+
return this.titles[idx] || {};
106+
},
107+
108+
setActive: function(idx){
109+
var lastIndex = this.titleIndex;
110+
var lis = this.element.querySelectorAll("li");
111+
[].forEach.call(lis, function(li, index){
112+
li.classList[index === idx ? "add" : "remove"]("active");
113+
});
114+
this.titleIndex = idx;
115+
},
116+
117+
handleEvent: throttle(function(ev){
118+
switch(ev.type){
119+
case "scroll":
120+
this.handleScroll(ev);
121+
break;
122+
}
123+
}, 20),
124+
125+
handleScroll: function(ev){
126+
// Determine if we should show the TOC
127+
this.fixed(!this.isFirstTitleVisible());
128+
129+
this.calculateActive();
130+
},
131+
132+
calculateActive: function(){
133+
var scrollTop = this.scroller.scrollTop;
134+
135+
// Determine which h2 should be showing
136+
var prev = this.getTitle(this.titleIndex);
137+
var next = this.getTitle(this.titleIndex + 1);
138+
139+
// See if we need to jump to the next when scrolling down
140+
var cur;
141+
while(scrollTop > next.pos) {
142+
cur = next;
143+
next = this.getTitle(cur.index + 1);
144+
}
145+
146+
// See if we need to move to the previous when scrolling up
147+
if(!cur) {
148+
do {
149+
cur = prev;
150+
prev = this.getTitle(prev.index - 1);
151+
} while(scrollTop < cur.pos);
152+
}
153+
154+
if(typeof cur.pos !== "undefined") {
155+
this.setActive(cur.index);
156+
}
157+
},
158+
159+
160+
161+
});
162+
163+
if(toc) {
164+
new TableOfContents(toc);
165+
}

0 commit comments

Comments
 (0)