//Visual Book designer (vbd) class
var vbd = {
// Version numbers
_require: 2.81,
version: 3.73,
bookpageversion: 0.00,
pageheadversion: 0.00,
// default name of all new books:
pageTree: null,
defName: 'New Book',
defpagename: 'New Page',
defheadname: 'New Heading',
newpagecnt: 1,
newheadcnt: 1,
//div IDs where the gadget is inserted into the page
formspan: "WKVBDSpan",
statspan: "WKVBDStatSpan",
// Navigation templates and configuration parameters
templates: new Array(
["Simple Header", 0, 0, "Simple header"],
["Page Nav Header", 1, 0, "Header with forward/back links"],
["Page Nav Header2", 1, 0, "Header with forward/back links (2)"],
["Page List Header", 0, 1, "Header with page list"],
["Page List Nav", 1, 1, "Header with page list and forward/back links"]
),
template: 0,
// Reading levels
readingLevels: new Array(
'Pre-Reader',
'Beginner',
'Intermediate',
'Advanced',
'Professional'
),
readingLevel: 2,
// Prerequisite and corequisite books
prerequisites: new Array(),
corequisites: new Array(),
// Subjects for categorization
subjects: new Array(),
// whether to include certain special pages in the book by default
useresources: false,
uselicensing: false,
useintroduction: false,
usecollectionpreface: true,
// other options
defaultinherit: false,
defaultcollapse: false,
commentsaspages: false,
useexternaledit: false,
// Drag-n-drop values
lastClicked: null,
offsetX: 0,
offsetY: 0,
startX: 0,
startY: 0,
box: null
};
//Basic array management functions
vbd.CopyArray = function(array) { return array.slice(0); }
vbd.FindPageNameInArray = function (array, name) {
for(var i = 0; i < array.length; i++) {
if(array[i].pagename == name) return i;
}
return -1;
}
vbd.FindHeadNameInArray = function(array, name) {
for(var i = 0; i < array.length; i++) {
if(array[i].label == name) return i;
}
return -1;
}
//Make a checkbox that corresponds to a boolean flag in vbd
vbd.makeOptionsCheckbox = function (field) {
var cbox = wk.makeElement('input', {type: "checkbox"});
cbox.checked = vbd[field];
cbox.onclick = function () { vbd[field] = cbox.checked; }
return cbox;
}
//Initialization functions. If the wk object is not found, the noinit method is called. Otherwise, the
//initialize method is called to start the gadget.
vbd.noinit = function() {
wk.spanText(vbd.formspan, "Cannot load VBD. WKGadgetsCore is missing or is wrong version. "
+ "Please install WKGadgetsCore, or update it to version " + vbd._require + ".");
}
vbd.initialize = function () {
vbd.pageTree = new BookPage(vbd.defName);
vbd.status = wk.spanEditor(vbd.statspan);
vbd.status("Use the outline tool below to create a new book");
var query = wk.getQueryHash();
if(typeof query["book"] == "undefined") {
vbd.visual();
return;
}
vbd.status("Loading the outline for " + query["book"] + "...");
wk.loadWikiText(query["book"], function (text) {
var start = text.indexOf('{{User:Whiteknight/SavedOutlineStart}}');
var end = text.indexOf('{{User:Whiteknight/SavedOutlineEnd}}');
if(start == -1 || end == -1) {
vbd.visual();
return;
}
vbd.loadNodeTree(text.substring(start + 38, end));
vbd.status("Use the outline tool below to create a new book");
});
}
if(typeof wk == 'object' && wk.testVersion(vbd._require)) {
addOnloadHook(vbd.initialize);
} else {
addOnloadHook(vbd.noinit);
}
//rebuild the outline
vbd.visual = function() {
vbd.box = wk.spanText(vbd.formspan, "");
if(vbd.box == null) return;
vbd.box.appendChild(vbd.pageTree.makeNode());
}
//Clear the outline completely and create a new one
vbd.clear = function() {
vbd.pageTree = new BookPage(vbd.defName);
vbd.subjects = new Array();
vbd.readingLevel = 2;
vbd.newpagecnt = 1;
vbd.newheadcnt = 1;
vbd.visual();
}
//Load a saved outline from a save page
vbd.loadNodeTree = function (text) {
vbd.clear();
var lastn = 0;
var last = new Array();
last[0] = vbd.pageTree;
var lines = text.split("\n");
for(i = 0; i < lines.length; i++) {
lines[i] = lines[i].replace(/^[ \t]+/, "");
lines[i] = lines[i].replace(/[ \t]+$/, "");
lines[i] = lines[i].replace(/\r\n/g, "");
if(lines[i] == "") continue;
if(lines[i].match(/^=/)) { //heading
var levels = lines[i].match(/^=+/);
var n = levels[0].length;
var k = n - 1;
var head = new PageHeading(lines[i].substr(n));
last[k].addHeading(head);
last[k] = head;
lastn = k;
} else if(lines[i].match(/^\*+/)) { //subpage
var stars = lines[i].match(/^\*+/);
var n = stars[0].length;
var k = n - 1;
if(last[k] == null) { k = 0; }
last[n] = new BookPage(lines[i].substr(n));
last[k].addSubpage(last[n]);
lastn = n;
} else if(lines[i].match(/^&/)) { //pagetext
last[lastn].pagetext += lines[i].substr(1);
} else if(lines[i].match(/^%/)) { //comment
last[lastn].comments += lines[i].substr(1);
} else { //main title
vbd.pageTree.pagename = lines[i];
lastn = 0;
}
}
vbd.pageTree.formspan.innerHTML = "";
vbd.visual();
vbd.pageTree.formspan.appendChild(document.createTextNode(
'Successfully loaded saved outline'
));
}
//Try to load in a saved collection
vbd.loadNodeTreeCollection = function(text) {
vbd.clear();
var last = vbd.pageTree;
var lines = text.split("\n");
for(var i = 0; i < lines.length; i++) {
if(lines[i].match(/^===/) || lines[i].match(/\[\[category:/i)) {
continue;
} else if(lines[i].match(/^==.+==/)) {
vbd.pageTree.pagename = vbd.extractHeadingName(lines[i]);
} else if(lines[i].match(/^;/)) {
var head = new PageHeading(lines[i].substring(1));
last.addHeading(head);
last = head;
} else if(lines[i].match(/^:\[\[/)) {
if(lines[i].match(/Resources/)) { vbd.useresources = true; continue; }
if(lines[i].match(/Licensing/)) { vbd.uselicensing = true; continue; }
if(lines[i].match(/Wikibooks:/)) { vbd.usecollectionpreface = true; continue; }
var page = new BookPage(vbd.extractLinkPageName(lines[i], vbd.pageTree.pagename));
last.addSubpage(page);
}
}
vbd.visual();
vbd.pageTree.formspan.innerHTML = 'Successfully loaded collection!';
}
//take the wikitext of an arbitrary page and try to load a reasonable outline from it.
vbd.loadNodeTreeTOC = function (text, title) {
vbd.clear();
var lastn = 0;
var last = new Array();
last[0] = vbd.pageTree;
vbd.pageTree.pagename = title;
var lines = text.split("\n");
for(i = 0; i < lines.length; i++) {
lines[i] = lines[i].replace(/^[ \t]+/, "");
lines[i] = lines[i].replace(/[ \t]+$/, "");
lines[i] = lines[i].replace(/\r\n/g, "");
if(lines[i] == "") continue;
if(lines[i].match(/^===.+===/)) { //heading
var head = new PageHeading(vbd.extractHeadingName(lines[i]));
last[0].addHeading(head);
last[0] = head;
} else if(lines[i].match(/^[\*\#]*\s*\[\[.+\]\]/)) { //subpage
if(lines[i].match(/Resources/)) { vbd.useresources = true; continue; }
if(lines[i].match(/Licensing/)) { vbd.uselicensing = true; continue; }
if(lines[i].match(/Category:/i)) continue;
var stars = lines[i].match(/^[\*\#]*/);
var n = stars[0].length;
if(n == 0) n = 1;
var k = n - 1;
if(last[k] == null) { k = 0; }
last[n] = new BookPage(vbd.extractLinkPageName(lines[i], title));
last[k].addSubpage(last[n]);
lastn = n;
}
}
vbd.pageTree.formspan.innerHTML = "";
vbd.visual();
vbd.pageTree.formspan.appendChild(document.createTextNode(
'Successfully loaded outline from ' + title + ' TOC!'
));
}
//try to get the name of a level-3 heading
vbd.extractHeadingName = function(line) {
line = line.substring(3);
line = line.substring(0, line.indexOf("==="));
return line;
}
//Try to get the page name from a link. Very limited ability to deal with relative links
vbd.extractLinkPageName = function(line, title) {
line = line.substring(line.indexOf("[[") + 2);
var end = line.indexOf("|");
if(end == -1) {
end = line.indexOf("]]");
}
line = line.substring(0, end)
if(line.charAt(line.length - 1) == '/') line = line.substring(0, line.length - 1);
if(line.charAt(0) == '/') line = title + line;
for(end = line.indexOf("/") ; end != -1; end = line.indexOf("/")) {
line = line.substring(end + 1);
}
return line;
}
//when saving an outline, find and remove an old save, if one is located on the page.
vbd.killOldSaves = function(text) {
var start = text.indexOf('{{User:Whiteknight/SavedOutlineStart}}');
var end = text.indexOf('{{User:Whiteknight/SavedOutlineEnd}}');
if(start == -1 || end == -1) return text; //no previous save
var prefix = text.slice(0, start);
var suffix = text.slice(end + 36);
return prefix + suffix;
}
//force a page name to use appropriate capitalization
vbd.forceCaps = function(title, isRoot) {
if(isRoot) return vbd.forceTitleCaps(title);
else return vbd.forceFirstCaps(title);
}
//determines if the word needs to be capitalized. Returns 1 if it should be, 0 otherwise.
vbd.isRealWord = function (word) {
var preps = new Array('the', 'in', 'of', 'for', 'to', 'is', 'a', 'an');
for(var i = 0; i < preps.length; i++) {
if(word == preps[i]) return 0;
}
return 1;
}
//book names are forced to title caps
vbd.forceTitleCaps = function(title) {
title.replace("_", " ");
var words = title.split(" ");
for(var i = 0; i < words.length; i++) {
if(words[i].length > 3 || i == 0 || vbd.isRealWord(words[i]))
words[i] = words[i].charAt(0).toUpperCase() + words[i].slice(1);
}
title = words.join(" ");
return title;
}
//page names are forced to have the first letter capitalized, but are not forced to have title-caps
vbd.forceFirstCaps = function(title) {
title.replace("_", " ");
return title.charAt(0).toUpperCase() + title.slice(1);
}
//Create the wikitext of the selected navigation template
vbd.makeTemplateText = function () {
var template = vbd.templates[vbd.template];
var book = vbd.pageTree.pagename;
var text = "{"+"{subst:User:Whiteknight/" + template[0] + "|" +
((template[1])?("book="):("")) + book;
if(template[2] == 1) {
text += "|" + ((template[1] == 1)?("list="):("")) + vbd.pageTree.makeTemplateLinks();
text += "[[" + book + "/Resources|Resources]] - " +
"[[" + book + "/Licensing|Licensing]] - " +
"[[Talk:" + book + "|Discuss]]";
}
return text + "}}";
}
//<noinclude>
// XXX: Drop-down menu utilities. These aren't implemented yet.
//vbd.createDropMenu = function(parent, children) {
// var menu = wk.makeElement('div', {style:"position:absolute; top: 0px; left: 0px; z-index: 10; background-color: white;"});
// wk.appendChildren(menu, children);
// menu.onmouseout = function() {
// parent.removeChild(menu);
// }
// parent.appendChild(menu);
//}
// XXX: Drag'n'Drop utilities. These aren't implemented yet.
//document.addEventListener("mouseup", function(event) {
// if(vbd.lastClicked &&
// event.eventPhase == Event.BUBBLING_PHASE &&
// event.currentTarget == event.target) {
// vbd.lastClicked.box.style.border = "none";
// vbd.lastClicked = null;
// }
//}, false);
//vbd.extractNumber = function(value) {
// var n = parseInt(value);
// return n == null || isNaN(n) ? 0 : n;
//}
//vbd.moveMouse = function(e) {
// vbd.lastClicked.box.style.left = (vbd.offsetX + e.clientX - vbd.startX) + 'px';
// vbd.lastClicked.box.style.top = (vbd.offsetY + e.clientY - vbd.startY) + 'px';
// vbd.status("x:" + vbd.lastClicked.box.style.left + " y: " + vbd.lastClicked.box.style.top);
//}
//</noinclude>