/*
* Author = Philip Cooksey
* Edited = July 2015
* Website = https://github.com/pcooksey/bibtex-js
* Credit = Henrik Mühe
*
* Issues:
* no comment handling within strings
* no string concatenation
* no variable values yet
* Grammar implemented here:
* bibtex -> (string | preamble | comment | entry)*;
* string -> '@STRING' '{' key_equals_value '}';
* preamble -> '@PREAMBLE' '{' value '}';
* comment -> '@COMMENT' '{' value '}';
* entry -> '@' key '{' key ',' key_value_list '}';
* key_value_list -> key_equals_value (',' key_equals_value)*;
* key_equals_value -> key '=' value;
* value -> value_quotes | value_braces | key;
* value_quotes -> '"' .*? '"'; // not quite
* value_braces -> '{' .*? '"'; // not quite
*
*/
function BibtexParser() {
this.pos = 0;
this.input = "";
this.entries = {};
this.strings = {
JAN: "January",
FEB: "February",
MAR: "March",
APR: "April",
MAY: "May",
JUN: "June",
JUL: "July",
AUG: "August",
SEP: "September",
OCT: "October",
NOV: "November",
DEC: "December"
};
this.currentKey = "";
this.rawCurrentKey = "";
this.currentEntry = "";
this.setInput = function(t) {
this.input = t;
}
this.getEntries = function() {
return this.entries;
}
this.getBibTexRaw = function() {
return this.bibtexraw;
}
this.errorThrown = function(str) {
$("#bibtex_errors").html(str);
}
this.isWhitespace = function(s) {
return (s == ' ' || s == '\r' || s == '\t' || s == '\n');
}
this.match = function(s) {
this.skipWhitespace();
if (this.input.substring(this.pos, this.pos + s.length) == s) {
this.pos += s.length;
} else {
throw "Token mismatch, expected " + s + ", found " + this.input.substring(this.pos);
}
this.skipWhitespace();
}
this.tryMatch = function(s) {
this.skipWhitespace();
if (this.input.substring(this.pos, this.pos + s.length) == s) {
return true;
} else {
return false;
}
this.skipWhitespace();
}
this.skipWhitespace = function() {
while (this.isWhitespace(this.input[this.pos])) {
this.pos++;
}
if (this.input[this.pos] == "%") {
while (this.input[this.pos] != "\n") {
this.pos++;
}
this.skipWhitespace();
}
}
this.value_braces = function() {
var bracecount = 0;
this.match("{");
var start = this.pos;
while (true) {
if (this.input[this.pos] == '}' && this.input[this.pos - 1] != '\\') {
if (bracecount > 0) {
bracecount--;
} else {
var end = this.pos;
this.match("}");
return this.input.substring(start, end);
}
} else if (this.input[this.pos] == '{') {
bracecount++;
} else if (this.pos == this.input.length - 1) {
throw "Unterminated value";
}
this.pos++;
}
}
this.value_quotes = function() {
var bracecount = 0;
this.match('"');
var start = this.pos;
while (true) {
if (this.input[this.pos] == '"' && this.input[this.pos - 1] != '\\' && bracecount == 0) {
var end = this.pos;
this.match('"');
return this.input.substring(start, end);
} else if (this.input[this.pos] == '{') {
bracecount++;
} else if (this.input[this.pos] == '}') {
if (bracecount > 0) {
bracecount--;
}
} else if (this.pos == this.input.length - 1) {
throw "Unterminated value:" + this.input.substring(start);
}
this.pos++;
}
}
this.single_value = function() {
var start = this.pos;
if (this.tryMatch("{")) {
return this.value_braces();
} else if (this.tryMatch('"')) {
return this.value_quotes();
} else {
var k = this.key();
if (this.strings[k.toUpperCase()]) {
return this.strings[k];
} else if (k.match("^[0-9]+$")) {
return k;
} else {
throw "Value expected:" + this.input.substring(start);
}
}
}
this.value = function() {
var values = [];
values.push(this.single_value());
while (this.tryMatch("#")) {
this.match("#");
values.push(this.single_value());
}
return values.join("");
}
this.key = function() {
var start = this.pos;
while (true) {
if (this.pos == this.input.length) {
throw "Runaway key";
}
if (this.input[this.pos].match("[a-zA-Z0-9_:?\\./'\\+\\-\\*]")) {
this.pos++
} else {
this.rawCurrentKey = this.input.substring(start, this.pos);
return this.rawCurrentKey.toUpperCase();
}
}
}
this.key_equals_value = function() {
var key = this.key();
if (this.tryMatch("=")) {
this.match("=");
var val = this.value();
return [key, val];
} else {
throw "... = value expected, equals sign missing:" + this.input.substring(this.pos);
}
}
this.key_value_list = function() {
var kv = this.key_equals_value();
this.entries[this.currentEntry][kv[0]] = kv[1];
while (this.tryMatch(",")) {
this.match(",");
// fixes problems with commas at the end of a list
if (this.tryMatch("}") || this.tryMatch(")")) {
break;
}
kv = this.key_equals_value();
this.entries[this.currentEntry][kv[0]] = kv[1];
}
}
this.entry_body = function(directive) {
this.currentEntry = this.key();
this.entries[this.currentEntry] = new Object();
this.entries[this.currentEntry]["BIBTEXKEY"] = this.rawCurrentKey;
if (directive == "@INCOLLECTION") {
this.entries[this.currentEntry]["BIBTEXTYPE"] = "book chapter";
} else if (directive == "@INPROCEEDINGS") {
this.entries[this.currentEntry]["BIBTEXTYPE"] = "conference, workshop";
} else if (directive == "@ARTICLE") {
this.entries[this.currentEntry]["BIBTEXTYPE"] = "journal";
} else if (directive == "@TECHREPORT") {
this.entries[this.currentEntry]["BIBTEXTYPE"] = "technical report";
}
this.entries[this.currentEntry]["BIBTEXTYPEKEY"] = directive;
this.match(",");
this.key_value_list();
}
this.directive = function() {
this.match("@");
return "@" + this.key();
}
this.string = function() {
var kv = this.key_equals_value();
this.strings[kv[0].toUpperCase()] = kv[1];
}
this.preamble = function() {
this.value();
}
this.comment = function() {
this.pos = this.input.indexOf("}", this.pos);
}
this.entry = function(directive) {
this.entry_body(directive);
}
this.bibtex = function() {
var start = 0;
var end = 0;
while (this.tryMatch("@")) {
start = this.pos;
var d = this.directive().toUpperCase();
if (this.tryMatch("{")) {
this.match("{");
} else {
this.match("(");
}
if (d == "@STRING") {
this.string();
} else if (d == "@PREAMBLE") {
this.preamble();
} else if (d == "@COMMENT") {
this.comment();
} else {
this.entry(d);
}
end = this.pos + 1;
if (this.tryMatch("}")) {
this.match("}");
} else {
this.match(")");
}
if (this.tryMatch(",")) {
this.match(",");
}
// In case there is extra stuff in between entries
this.pos = end + this.input.substring(end, this.input.length).indexOf("@");
this.entries[this.currentEntry]["BIBTEXRAW"] = this.input.substring(start, end);
}
}
}
function BibtexDisplay() {
this.invert = function(obj) {
var new_obj = {};
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
new_obj[obj[prop]] = prop;
}
}
return new_obj;
}
function isSymbol(str) {
return str.length === 1 && str.test(/[\W]/i);
}
//Regex Searchs used by fixValue in proper order
this.regExps = [];
this.regExps.push(new RegExp("\{\\\\\\W*\\w+\}")); // 1 {\[]}
this.regExps.push(new RegExp("\\\\\\W*\{\\w+\}")); // 2 \[]{\[]}
this.regExps.push(new RegExp("\\\\\\W*\\w+\\s")); // 3 \[]
this.regExps.push(new RegExp("\\\\\\W*\\w+")); // 4 \[]
this.regExps.push(new RegExp("\\\\(?![:\\\\\])\\W{1}")); // 5
this.fixValue = function(value) {
do {
var removeBrackets = value.match(/^\{(.*?)\}$/g, '$1');
if (removeBrackets) {
value = value.replace(/^\{(.*?)\}$/g, '$1');
}
} while (removeBrackets);
// Working on a more efficient way of processing the latex
var index = value.indexOf("\\");
if (index > -1) {
for (var exp in this.regExps) {
do {
var str = value.match(this.regExps[exp]);
var key = (str) ? str[0] : "";
if (str) {
if (typeof(latex_to_unicode[key]) != "undefined") {
value = value.replace(key, latex_to_unicode[key]);
} else {
var newkey = key.replace(new RegExp("(\\w)"), '{$1}')
if (typeof(latex_to_unicode[newkey]) != "undefined") {
value = value.replace(key, latex_to_unicode[newkey]);
} else {
str = "";
}
}
} else {
str = "";
}
} while (str.length);
}
}
value = value.replace(/[\{|\}]/g, '');
return value;
}
this.getName = function(array) {
// First, Junior, Von, Last
var name = ["", "", "", ""];
// check how many elements in array 1, 2, or 3
switch (array.length) {
case 1:
{
// Split by spaces keeping {names names} together
var words = array[0].split(/\ \s?(?![^\{]*\})/);
// Get first name
var index = 0;
for (; index < words.length - 1; index++) {
var space = (index > 0) ? " " : "";
if (words[index][0] == '{') {
if (words[index][1] == '\\') {
words[index] = this.fixValue(words[index]);
// Test below
} else {
name[0] += space + this.fixValue(words[index]);
continue;
}
}
if (words[index][0] == words[index][0].toUpperCase()) {
name[0] += space + this.fixValue(words[index]);
} else {
break; //von part
}
}
// Get von part forward look for last non uppercase
var lastVon = index;
for (var temp = index; temp < words.length - 1; temp++) {
if (words[temp][0] == words[temp][0].toLowerCase()) {
lastVon = temp;
}
}
for (; index <= lastVon && index < words.length - 1; index++) {
var space = (name[2] != "") ? " " : "";
name[2] += space + this.fixValue(words[index]);
}
// Get last name
for (; index < words.length; index++) {
var space = (name[3] != "") ? " " : "";
name[3] += space + this.fixValue(words[index]);
}
return name;
}
break;
case 2:
case 3:
{
var arrayIndex = 0;
// Split by spaces keeping {names names} together
var words = array[arrayIndex].split(/\ \s?(?![^\{]*\})/);
var index = 0;
// Get von part forward look for last non uppercase
var lastVon = -1;
for (var temp = index; temp < words.length - 1; temp++) {
if (words[temp][0] == words[temp][0].toLowerCase()) {
lastVon = temp;
}
}
for (; index <= lastVon && index < words.length - 1; index++) {
var space = (name[2] != "") ? " " : "";
name[2] += space + this.fixValue(words[index]);
}
// Get last name
for (; index < words.length; index++) {
var space = (name[3] != "") ? " " : "";
name[3] += space + this.fixValue(words[index]);
}
arrayIndex++;
// Check if there is a Jr. part
if (array.length == 3) {
name[1] = this.fixValue(array[arrayIndex]);
arrayIndex++;
}
// Get first name
name[0] = this.fixValue(array[arrayIndex]);
return name;
}
break;
default:
console.log("Processed author incorrectly!");
return name;
}
}
var Format = Object.freeze({
"FIRST": 0,
"JUNIOR": 1,
"VON": 2,
"LAST": 3
});
this.displayAuthor = function(string, format) {
string = string.replace(/[ ]*[\n\t][ ]*/g, " ");
string = string.replace(/[ ]+/g, " ");
// Split string by 'and' keeping {words and words} together
var arrayString = string.split(new RegExp(/\s+and\s+?(?![^\{]*\})/));
// Get the max amount of authors to print
console.log(format);
var searchLength = arrayString.length;
if (format.attr("max")) {
searchLength = Math.min(format.attr("max"), searchLength);
}
// Check if authors are formatted
var newString = "";
if (format.find("span:not(a)").length) {
for (i = 0; i < searchLength; i++) {
// Split string by ',' keeping {words, and words} together
var name = this.getName(arrayString[i].split(/\,\s?(?![^\{]*\})/));
var author = format.clone();
var fullName = $.grep(name, Boolean).join(" ");
author.attr('class', fullName);
author.find("span:not(a)").each(function() {
var index = Format[$(this).attr('class').toUpperCase()];
// Check if value is empty
if (name[index] != "") {
$(this).html($(this).html() + name[index]);
} else {
$(this).remove();
}
});
if (i == 0) {
newString += author[0].outerHTML;
} else if (i + 1 >= arrayString.length) {
newString += ", and " + author[0].outerHTML;
} else {
newString += ", " + author[0].outerHTML;
}
}
} else {
newString = arrayString[0];
for (i = 1; i < searchLength; i++) {
if (i + 1 >= arrayString.length) {
newString += ", and " + arrayString[i];
} else {
newString += ", " + arrayString[i];
}
}
}
// Checking if et al. must be added
if (searchLength != arrayString.length) {
if (searchLength > 1) {
newString += ",";
}
newString += " et al.";
}
return newString;
}
this.createTemplate = function(entry, output) {
// Check if bibtex keys are limiting output (bibtexkeys="key1|key2|...|keyN")
if (output[0].hasAttribute("bibtexkeys")) {
var bitexkeys = output[0].getAttribute("bibtexkeys");
if (!entry["BIBTEXKEY"].match(bitexkeys))
return null;
}
// find template
var tpl = $(".bibtex_template").clone().removeClass('bibtex_template');
// find all keys in the entry
var keys = [];
for (var key in entry) {
keys.push(key.toUpperCase());
}
// find all ifs and check them
var removed = false;
do {
// find next if
var conds = tpl.find(".if");
if (conds.length == 0) {
break;
}
// check if
var cond = conds.first();
cond.removeClass("if");
var ifTrue = true;
var classList = cond.attr('class').split(' ');
$.each(classList, function(index, cls) {
if (cls[0] == "!" &&
keys.indexOf(cls.substring(1, cls.length).toUpperCase()) < 0) {
ifTrue = true;
} else if (keys.indexOf(cls.toUpperCase()) < 0) {
ifTrue = false;
}
cond.removeClass(cls);
});
// remove false ifs
if (!ifTrue) {
cond.remove();
}
} while (true);
tpl.find('.bibtexVar').each(function() {
var key = $(this).attr("extra").toUpperCase();
var regEx = new RegExp('\\+' + key + '\\+', "gi");
$.each(this.attributes, function(i, attrib) {
var value = attrib.value;
value = value.replace(regEx, entry[key]);
attrib.value = value;
});
});
// fill in remaining fields
for (var index in keys) {
var key = keys[index];
var value = entry[key] || "";
// Fill out bibtex raw and continue
if (key == "BIBTEXRAW") {
tpl.find("." + key.toLowerCase()).html(value);
continue;
}
if (key == "AUTHOR") {
var format = tpl.find("span:not(a)." + key.toLowerCase());
value = this.displayAuthor(value, format);
} else if (key == "PAGES") {
value = value.replace("--", "-");
} else if (key == "DATE") {
value = moment(value).format("MMM. YYYY");
} else if (key == "URL") {
value = value.replace(/\\url/g, '');
value = this.fixValue(value);
} else {
value = this.fixValue(value);
}
tpl.find("span:not(a)." + key.toLowerCase()).html(value);
tpl.find("a." + key.toLowerCase()).each(function() {
if (!$(this).attr("href")) {
$(this).attr("href", value);
}
});
}
tpl.addClass("bibtexentry");
return tpl;
}
this.createArray = function(entries) {
var entriesArray = [];
for (var entryKey in entries) {
entriesArray.push(entries[entryKey]);
}
return entriesArray;
}
this.sortArray = function(array, key, rule, type) {
var keyUpper = key.toUpperCase();
array = array.sort(function(a, b) {
var aValue = "",
bValue = "";
// Need to check if values exist
aValue = (keyUpper in a) ? a[keyUpper] : "";
bValue = (keyUpper in b) ? b[keyUpper] : "";
switch (rule.toUpperCase()) {
case "DESC":
//Values remain the same
break;
case "ASC":
//Just swaping the values
var tmp = bValue;
bValue = aValue;
aValue = tmp;
break;
default:
return 0;
break;
}
switch (type.toLowerCase()) {
case "string":
return bValue.toUpperCase().localeCompare(aValue.toUpperCase());
break;
case "number":
return parseInt(bValue) - parseInt(aValue);
break;
case "date":
return new Date(bValue) - new Date(aValue);
break;
default:
return 0;
break;
}
});
return array;
}
this.createStructure = function(structure, output, entries, level) {
var MissingGroup = "Other Publications";
//Used during the search
level = level || 0;
var struct = structure.clone().removeClass('bibtex_structure');
var groupChild = struct.children(".group");
var sectionsChild = struct.children(".sections");
var sortChild = struct.children(".sort");
if (groupChild.length) {
var group = groupChild.first();
var groupName = group.attr('class').split(" ")[1].toUpperCase();
var rule = group.attr('extra').split(" ")[0];
var type = group.attr('extra').split(" ")[1];
//Sort the array based on group rules
var sortedArray = this.sortArray(entries, groupName, rule, type);
// Get all the unique values for the groups
var values = [];
$.each(sortedArray, function(i, object) {
if (groupName in object && $.inArray(object[groupName], values) === -1) {
values.push(object[groupName]);
return;
}
});
values.push(MissingGroup); //This is for checking none grouped publications
//Get the bibtex topics html here.
var topics = $(".bibtex_topics");
// Iterate through the values and recurively call this function
globalStruct = $('
');
for (val in values) {
//Starting to create the page
var newStruct = struct.clone();
var groupNameValue = values[val];
//Add the header for the group
var header = newStruct.children("." + groupName.toLowerCase()).first().find(".title");
if (header.length) {
header.prepend(this.fixValue(groupNameValue));
} else {
newStruct.children("." + groupName.toLowerCase()).first().prepend("" + this.fixValue(groupNameValue) + "");
}
//Divide the array into group with groupNameValue
splicedArray = $.grep(sortedArray, function(object, i) {
if (groupNameValue == MissingGroup) {
return (typeof object[groupName] === "undefined") ? true : false;
} else {
return object[groupName] == groupNameValue;
}
});
if (splicedArray.length) {
//Add the topic value to the topics structure if it exists on the page
if (topics.length && level == 0) {
topics.append(" - " + groupNameValue + " ");
}
// Get back the struct to add to the page
var tempStruct = this.createStructure(groupChild.clone(), output, splicedArray, level + 1);
if (groupChild.children(".group").length) {
nextGroupName = "." + groupChild.children(".group").attr('class').split(' ').join('.');
newStruct.find(nextGroupName).replaceWith(tempStruct.find(nextGroupName));
} else {
newStruct.find(".templates").append(tempStruct.find(".templates").html());
}
if (level == 0) {
output.append(newStruct);
} else {
globalStruct.append(newStruct);
}
}
}
if (level == 0) {
return output;
} else {
return globalStruct;
}
} else if (sectionsChild.length) {
var values = [],
section = [],
toRemove = [];
// Get all the unique values for the sections
var sectionbibtexkey = sectionsChild.first().attr('class').split(" ")[1].toUpperCase();
$('.section', '.sections').each(function(i, object) {
values.push($(this).attr('class').split(" ")[1].toUpperCase());
section.push($(this));
});
//Get the bibtex topics html here.
var topics = $(".bibtex_topics");
// Iterate through the values and recurively call this function
globalStruct = $('');
//Starting to create the page
var newStruct = struct.clone();
for (val in values) {
var sectionNameValue = values[val];
var re = new RegExp(sectionNameValue);
//Divide the array into group with sectionNameValue
splicedArray = $.grep(entries, function(object, i) {
return re.test(object[sectionbibtexkey]);
});
if (splicedArray.length) {
//Add the topic value to the topics structure if it exists on the page
if (topics.length && level == 0) {
var sectionNameTitle = section[val].children().first().text();
topics.append(" - " + sectionNameTitle + " ");
}
// Get back the struct to add to the page
var tempStruct = this.createStructure(section[val].clone(), output, splicedArray, level + 1);
if (groupChild.children(".group").length) {
nextGroupName = "." + groupChild.children(".group").attr('class').split(' ').join('.');
newStruct.find(nextGroupName).replaceWith(tempStruct.find(nextGroupName));
} else {
newStruct.find(".templates").eq(val).append(tempStruct.find(".templates").html());
}
if (level == 0) {
output.append(newStruct);
} else {
globalStruct.append(newStruct);
}
} else {
toRemove.push(val);
}
}
for (val in toRemove) {
newStruct.find(".section").eq(toRemove[val]).remove();
}
if (level == 0) {
return output;
} else {
return globalStruct;
}
} else if (sortChild.length) {
var sortName = sortChild.attr('class').split(" ")[1].toUpperCase();
var rule = sortChild.first().attr('extra').split(" ")[0];
var type = sortChild.first().attr('extra').split(" ")[1];
var sort = structure.children(".sort").first().clone();
//Sort the array based on sort rules
var sortedArray = this.sortArray(entries, sortName, rule, type);
if (level == 0) {
output.append(this.createStructure(sortChild, output, sortedArray, level + 1));
} else {
return this.createStructure(sortChild, output, sortedArray, level + 1);
}
} else {
// iterate over bibTeX entries and add them to template
for (var entryKey in entries) {
var entry = entries[entryKey];
// Checking if web is set to visible
if (!entry["WEB"] || entry["WEB"].toUpperCase() != "NO") {
var tpl = this.createTemplate(entry, output);
// Check if template was created
if (tpl) {
structure.find(".templates").append(tpl);
tpl.show();
}
}
}
return structure;
}
}
this.displayBibtex = function(input, output) {
// parse bibtex input
var b = new BibtexParser();
b.setInput(input);
b.bibtex();
var entries = b.getEntries();
// save old entries to remove them later
var old = output.find("*");
var structure = $(".bibtex_structure").clone();
// If structure exists we need to do more complicated sorting with entries
if (structure.length) {
// Create array for sorting
var entriesArray = this.createArray(entries);
this.createStructure(structure, output, entriesArray);
} else {
// iterate over bibTeX entries
for (var entryKey in entries) {
var entry = entries[entryKey];
tpl = this.createTemplate(entry, output);
// Check if template was created
if (tpl) {
output.append(tpl);
tpl.show();
}
}
}
// remove old entries
old.remove();
}
}
function bibtex_js_draw() {
$(".bibtex_template").hide();
if ($("#bibtex_input").length) {
(new BibtexDisplay()).displayBibtex($("#bibtex_input").val(), $("#bibtex_display"));
} else {
//Gets the BibTex files and adds them together
var bibstring = "";
var requests = [];
// Create request for bibtex files
$('bibtex').each(function(index, value) {
var request = $.ajax({
url: $(this).attr('src'),
dataType: "text"
})
.done((data) => bibstring += data)
.fail((request, status, error) => console.error(error))
requests.push(request);
});
// Executed on completion of last outstanding ajax call
$.when.apply($, requests).then(function() {
// Check if we have a bibtex_display id or classes
if ($("#bibtex_display").length) {
(new BibtexDisplay()).displayBibtex(bibstring, $("#bibtex_display"));
} else if ($(".bibtex_display").length) {
// Loop through all bibtex_displays on the page
$(".bibtex_display").each(function(index) {
// ($this) is the class node output for the bitex entries
(new BibtexDisplay()).displayBibtex(bibstring, $(this));
});
}
loadExtras();
// Remove elements from html that are not needed to display
$(".bibtex_structure").remove();
});
}
}
/**
BibTex Searcher is used with input form
*/
function BibTeXSearcher() {
this.inputArray = new Array("");
this.inputLength = 0;
this.setInputArray = function(val) {
this.inputArray = val;
this.inputLength = val.length;
}
this.getStringName = function(string) {
var start_pos = string.indexOf('@') + 1;
var end_pos = string.indexOf('[', start_pos);
var array = [];
if (end_pos == -1) {
array[0] = string.substring(start_pos, string.length);
} else {
array[0] = string.substring(start_pos, end_pos);
end_pos2 = string.indexOf(']', start_pos);
array[1] = string.substring(end_pos + 1, end_pos2);
}
return array;
}
this.checkEntry = function(entry, word) {
var found = false;
if (word[0] != "@") {
entry.find("span:not(.noread)").each(
function() {
if ($(this).text().search(new RegExp(word, "i")) > -1 &&
entry.is(":visible")) {
found = true;
return false; //Break out of loop
}
});
} else {
//This search version is for more specific searchs using the @name[parameter]=value
var strings = word.split("=");
var arrayStr = this.getStringName(strings[0]);
if (arrayStr.length < 2) {
entry.find("span:not(.noread)." + arrayStr[0]).each(
function() {
if ($(this).text().search(new RegExp(strings[1], "i")) > -1 &&
entry.is(":visible")) {
found = true;
return false; //Break out of loop
}
});
} else {
switch (arrayStr[1]) {
case "first":
entry.find("span:not(.noread)." + arrayStr[0]).each(
function() {
arrayString = $(this).text().split(new RegExp(",[\\s]+and[\\s]+|,[\\s]+"));
if (strings[1] == arrayString[0] && entry.is(":visible")) {
found = true;
return false; //Break out of loop
}
});
break;
}
}
}
return found;
}
this.unhideAll = function() {
$("div#bibtex_display, div.bibtex_display").children().each(
function() {
$(this).show();
$(this).find(".bibtexentry").each(
function() {
$(this).show();
});
});
}
this.hideEntry = function(word) {
var funcCaller = this;
var container = $("div#bibtex_display, div.bibtex_display").children();
// No bibtex_structure search
if (container.first().hasClass("bibtexentry")) {
container.each(
function() {
if (!funcCaller.checkEntry($(this), word)) {
$(this).hide();
}
});
} else {
// There is a bibtex_structure
container.each(
function() {
var shouldHide = true;
$(this).find(".bibtexentry:visible").each(
function() {
if (!funcCaller.checkEntry($(this), word)) {
$(this).hide();
} else {
shouldHide = false;
}
});
// Hides outside div
if (shouldHide) {
$(this).hide();
}
});
}
}
this.searcher = function(input, needToRestart) {
needToRestart = typeof needToRestart !== 'undefined' ? needToRestart : false;
var string = input;
if (string.length) {
var splitInput = string.split("%");
//If input is less than restart
if (this.inputLength > splitInput.length || this.inputLength == 0) {
needToRestart = true;
}
//If last string reduced in size than restart
else if (this.inputArray[this.inputArray.length - 1].length >
splitInput[splitInput.length - 1].length) {
needToRestart = true;
}
//If earlier words changed than restart
else {
for (var i = 0; i < this.inputArray.length - 1; i++) {
if (this.inputArray[i] != splitInput[i]) {
needToRestart = true;
break;
}
}
}
if (needToRestart) {
this.unhideAll();
for (var word in splitInput) {
this.hideEntry(splitInput[word]);
}
} else {
this.hideEntry(splitInput[splitInput.length - 1]);
}
this.setInputArray(splitInput);
} else {
this.unhideAll();
}
}
}
function createWebPage(defaultTemplate) {
// draw bibtex when loaded
$(document).ready(function() {
// check for template, add default
if ($(".bibtex_template").length == 0) {
$("body").append(defaultTemplate);
}
bibtex_js_draw();
});
}
function loadExtras() {
BibTeXSearcherClass = new BibTeXSearcher();
$(".bibtex_author").each(function(i, obj) {
authorList($(this));
});
localStorage.removeItem("customerDatabase");
if (!localStorage.searcher) {
localStorage.searcher = new Object();
}
//Resets selects when back button is used
$("select").each(function() {
if (localStorage.getItem($(this).attr("id"))) {
$(this).val(JSON.parse(localStorage.getItem($(this).attr("id"))));
}
});
$(".bibtex_search").each(function(i, obj) {
$(this).on('change', function(e) {
combineSearcher(BibTeXSearcherClass, true);
localStorage.setItem($(this).attr("id"), JSON.stringify($(this).val()));
});
$(this).keyup(function() {
combineSearcher(BibTeXSearcherClass);
});
if ($(this).val() != "") {
combineSearcher(BibTeXSearcherClass, true);
}
});
}
function combineSearcher(searcherClass, needToRestart) {
needToRestart = typeof needToRestart !== 'undefined' ? needToRestart : false;
var string = "";
$("select.bibtex_search").each(function(i, obj) {
var front = "";
if (obj.hasAttribute("search"))
front = "@" + $(this).attr("search");
if (obj.hasAttribute("extra")) {
front += "[" + $(this).attr("extra") + "]=";
} else {
if (front != "") {
front += "=";
}
}
if ($(this).val() != "") {
string += "%" + front + $(this).val();
}
});
$("input.bibtex_search").each(function(i, obj) {
if ($(this).val() != "") {
string += "%" + $(this).val().split(' ').join('%');
}
});
searcherClass.searcher(string, needToRestart);
}
function authorList(object) {
var map = new Object();
$("span.author").each(function(i, obj) {
arrayString = $(this).text().split(new RegExp(",[\\s]+and[\\s]+|,[\\s]+"));
if (object.attr("extra") == "first") {
map[arrayString[0]] = 1;
} else {
for (i = 0; i < arrayString.length; i++) {
if (arrayString[i] in map) {
map[arrayString[i]] += 1;
} else {
map[arrayString[i]] = 1;
}
}
}
});
var tuples = [];
for (var key in map) tuples.push([key, key.split(" ").pop().toLowerCase()]);
tuples.sort(function(a, b) {
a = a[1];
b = b[1];
return a < b ? -1 : (a > b ? 1 : 0);
});
for (var i = 0; i < tuples.length; i++) {
var key = tuples[i][0];
var value = tuples[i][1];
var array = key.split(" ");
var text = array.pop() + ", " + array.join(" ");
object.append($("").attr("value", key).text(text));
}
}
var defaultTemplate = "