1var bibtexify = (function($) { 2 // helper function to "compile" LaTeX special characters to HTML 3 var htmlify = function(str) { 4 // TODO: this is probably not a complete list.. 5 str = str.replace(/\\"\{a\}/g, 'ä') 6 .replace(/\{\\aa\}/g, 'å') 7 .replace(/\\aa\{\}/g, 'å') 8 .replace(/\\"a/g, 'ä') 9 .replace(/\\"\{o\}/g, 'ö') 10 .replace(/\\'e/g, 'é') 11 .replace(/\\'\{e\}/g, 'é') 12 .replace(/\\'a/g, 'á') 13 .replace(/\\'A/g, 'Á') 14 .replace(/\\"o/g, 'ö') 15 .replace(/\\ss\{\}/g, 'ß') 16 .replace(/\{/g, '') 17 .replace(/\}/g, '') 18 .replace(/\\&/g, '&') 19 .replace(/--/g, '–') 20 .replace(/\{\\textperiodcentered\}/g, '·') 21 .replace(/\\textperiodcentered/g, '·') 22 ; 23 return str; 24 }; 25 var uriencode = function(str) { 26 // TODO: this is probably not a complete list.. 27 str = str.replace(/\\"\{a\}/g, '%C3%A4') 28 .replace(/\{\\aa\}/g, '%C3%A5') 29 .replace(/\\aa\{\}/g, '%C3%A5') 30 .replace(/\\"a/g, '%C3%A4') 31 .replace(/\\"\{o\}/g, '%C3%B6') 32 .replace(/\\'e/g, '%C3%A9') 33 .replace(/\\'\{e\}/g, '%C3%A9') 34 .replace(/\\'a/g, '%C3%A1') 35 .replace(/\\'A/g, '%C3%81') 36 .replace(/\\"o/g, '%C3%B6') 37 .replace(/\\ss\{\}/g, '%C3%9F') 38 .replace(/\{/g, '') 39 .replace(/\}/g, '') 40 .replace(/\\&/g, '%26') 41 .replace(/--/g, '%E2%80%93'); 42 return str; 43 }; 44 45 // event handlers for the bibtex links 46 var EventHandlers = { 47 showbib: function showbib(event) { 48 $(this).next(".bibinfo").removeClass('hidden').addClass("open"); 49 $("#shutter").show(); 50 event.preventDefault(); 51 }, 52 hidebib: function hidebib(event) { 53 $("#shutter").hide(); 54 $(".bibinfo.open").removeClass("open").addClass("hidden"); 55 event.preventDefault(); 56 } 57 }; 58 59 var Bib2HTML = function(data, $pubTable, options) { 60 this.options = options; 61 this.$pubTable = $pubTable; 62 this.stats = { }; 63 this.initialize(data); 64 }; 65 66 var bibproto = Bib2HTML.prototype; 67 68 // helper functions to turn a single bibtex entry into HTML 69 bibproto.bib2html = { 70 // the main function which turns the entry into HTML 71 entry2html: function(entryData, bib) { 72 var type = entryData.entryType.toLowerCase(); 73 // default to type misc if type is unknown 74 if(!(type in bib.bib2html)) { 75 type = 'misc'; 76 entryData.entryType = type; 77 } 78 var itemStr = htmlify(bib.bib2html[type](entryData, bib)); 79 itemStr += bib.bib2html.links(entryData, bib); 80 if (bib.options.showbibtex) 81 itemStr += bib.bib2html.bibtex(entryData); 82 if (bib.options.tweet && entryData.url) { 83 itemStr += bib.bib2html.tweet(entryData, bib); 84 } 85 return itemStr.replace(/undefined/g, '<span class="undefined">missing<\/span>'); 86 }, 87 // converts the given author data into HTML 88 authors2html: function(entryData, bib) { 89 if (!(entryData.author instanceof Array) || (entryData.author.length == 0)) { 90 if (entryData.editor) 91 return entryData.editor; 92 else 93 return "Missing author/editor"; 94 } 95 96 var authorsStr = ''; 97 if (entryData.author.length == 1) 98 authorsStr = bib.bibtex._formatAuthor(entryData.author[0]); 99 else if (entryData.author.length == 2) 100 authorsStr = bib.bibtex._formatAuthor(entryData.author[0]) + " and " + bib.bibtex._formatAuthor(entryData.author[1]); 101 else { 102 for (var index = 0; index < entryData.author.length - 1; index++) { 103 if (index > 0) { authorsStr += ", "; } 104 authorsStr += bib.bibtex._formatAuthor(entryData.author[index]); 105 } 106 authorsStr += ", and " + bib.bibtex._formatAuthor(entryData.author[entryData.author.length - 1]); 107 } 108 return htmlify(authorsStr); 109 }, 110 // converts the given author data into HTML 111 authors2shorthtml: function(entryData, bib) { 112 if (!(entryData.author instanceof Array) || (entryData.author.length == 0)) { 113 if (entryData.editor) 114 return entryData.editor; 115 else 116 return "Missing author/editor"; 117 } 118 var authorsStr = ''; 119 if (entryData.author.length == 1) 120 authorsStr = entryData.author[0].last; 121 else if (entryData.author.length == 2) 122 authorsStr = entryData.author[0].last + " and " + entryData.author[1].last; 123 else 124 authorsStr = entryData.author[0].last + " et al."; 125 return htmlify(authorsStr); 126 }, 127 shortcite: function(entryData, bib) { 128 var year; 129 if (entryData.year == "To Appear") 130 year = ""; 131 else 132 year = " (" + entryData.year + ")"; 133 134 if (entryData.author) 135 return this.authors2shorthtml(entryData, bib) + year; 136 else 137 return entryData.title + " (" + entryData.year + ")"; 138 }, 139 // adds links to the PDF or url of the item 140 links: function(entryData, bib) { 141 var itemStr = ''; 142 if (entryData.url) { 143 itemStr += ' <a title="This article online" href="' + entryData.url + 144 '"><span class="fa fa-external-link" style="color:#0000FF;"></span><\/a> '; 145 } 146 if (entryData.doi) { 147 itemStr += ' <a href="http://dx.doi.org/'+entryData.doi+'" target="_blank"><span class="fa fa-link" style="color:#0000FF;"></span></a> '; 148 } 149 if (entryData.file && bib.options.file_links) { 150 var files = entryData.file.split(";") 151 for (var fileidx = 0; fileidx < files.length; ++fileidx) { 152 var data = files[fileidx].split(":"); 153 //data[0] name of file, data[1] path to file, data[2]={PDF} file type 154 switch (data[2]) { 155 case "PDF": 156 itemStr += '<a href="/static/literature/'+data[1]+'" target="_blank"><span class="fa fa-file-pdf-o" style="color:#e34947;"></span></a> '; 157 break; 158 default: 159 itemStr += '<a href="/static/literature/'+data[1]+'" target="_blank"><span class="fa fa-file-o"></span></a> '; 160 break; 161 } 162 } 163 } 164 165 return itemStr; 166 }, 167 // adds the bibtex link and the opening div with bibtex content 168 bibtex: function(entryData, bib) { 169 var itemStr = ''; 170 itemStr += ' (<a title="This article as BibTeX" href="#" class="biblink">' + 171 'bib</a>)<div class="bibinfo hidden">'; 172 itemStr += '<a href="#" class="bibclose" title="Close">x</a><pre>'; 173 itemStr += '@' + entryData.entryType + "{" + entryData.cite + ",\n"; 174 $.each(entryData, function(key, value) { 175 if (key == 'author') { 176 itemStr += ' author = { '; 177 for (var index = 0; index < value.length; index++) { 178 if (index > 0) { itemStr += " and "; } 179 itemStr += value[index].last; 180 } 181 itemStr += ' },\n'; 182 } else if (key != 'entryType' && key != 'cite') { 183 itemStr += ' ' + key + " = { " + value + " },\n"; 184 } 185 }); 186 itemStr += "}</pre></div>"; 187 return itemStr; 188 }, 189 // generates the twitter link for the entry 190 tweet: function(entryData, bib) { 191 // url, via, text 192 var itemStr = ' (<a title="Tweet this article" href="http://twitter.com/share?url='; 193 itemStr += entryData.url; 194 itemStr += '&via=' + bib.options.tweet; 195 itemStr += '&text='; 196 var splitName = function(wholeName) { 197 var spl = wholeName.split(' '); 198 return spl[spl.length-1]; 199 }; 200 var auth = entryData.author; 201 if (auth.length == 1) { 202 itemStr += uriencode(splitName(auth[0].last)); 203 } else if (auth.length == 2) { 204 itemStr += uriencode(splitName(auth[0].last) + "%26" + splitName(auth[1].last)); 205 } else { 206 itemStr += uriencode(splitName(auth[0].last) + " et al"); 207 } 208 itemStr += ": " + encodeURIComponent('"' + entryData.title + '"'); 209 itemStr += '" target="_blank">tweet</a>)'; 210 return itemStr; 211 }, 212 // helper functions for formatting different types of bibtex entries 213 inproceedings: function(entryData, bib) { 214 return this.authors2html(entryData, bib) + " (" + entryData.year + "). " 215 + entryData.title + ". In <em>" + entryData.booktitle 216 + ((entryData.address)?", " + entryData.address:"") + ".<\/em>"; 217 }, 218 article: function(entryData, bib) { 219 return this.authors2html(entryData, bib) + ', “' + 220 entryData.title + ',” <em>' + entryData.journal + "</em>, " 221 + ((entryData.volume)? "<b>
221" + entryData.volume + "</b>, " : "") 222 + ((entryData.number) ? "(" + entryData.number + "), " : "") 223 + ((entryData.pages) ? entryData.pages + " " : "") 224 + ((entryData.year) ? "(" + entryData.year + ") " : "") 225 + ((entryData.address)? entryData.address + ".":"") ; 226 }, 227 misc: function(entryData, bib) { 228 return this.authors2html(entryData, bib) + " (" + entryData.year + "). " + 229 entryData.title + ". " + 230 ((entryData.howpublished)?entryData.howpublished + ". ":"") + 231 ((entryData.note)?entryData.note + ".":""); 232 }, 233 mastersthesis: function(entryData, bib) { 234 return this.authors2html(entryData, bib) + ", “" 235 + entryData.title + ",” " + entryData.school + " (" + entryData.year + ")" ; 236 }, 237 techreport: function(entryData, bib) { 238 return this.authors2html(entryData, bib) + ", “" + 239 entryData.title + ",” " + entryData.institution + ", <b>" + 240 entryData.number + "</b> (" + entryData.year + ")"; 241 }, 242 book: function(entryData, bib) { 243 return this.authors2html(entryData, bib) + " (" + entryData.year + "). " + 244 " <em>" + entryData.title + "<\/em>, " + 245 entryData.publisher + ", " + entryData.year + 246 ((entryData.issn)?", ISBN: " + entryData.issn + ".":"."); 247 }, 248 inbook: function(entryData, bib) { 249 return this.authors2html(entryData, bib) + " (" + entryData.year + "). " + 250 entryData.chapter + " in <em>" + entryData.title + "<\/em>, " + 251 ((entryData.editor)?" Edited by " + entryData.editor + ", ":"") + 252 entryData.publisher + ", pp. " + entryData.pages + "" + 253 ((entryData.series)?", <em>" + entryData.series + "<\/em>":"") + 254 ((entryData.volume)?", Vol. " + entryData.volume + "":"") + 255 ((entryData.issn)?", ISBN: " + entryData.issn + "":"") + 256 "."; 257 }, 258 // weights of the different types of entries; used when sorting 259 importance: { 260 'TITLE': 9999, 261 'misc': 0, 262 'manual': 10, 263 'techreport': 20, 264 'mastersthesis': 30, 265 'inproceedings': 40, 266 'incollection': 50, 267 'proceedings': 60, 268 'conference': 70, 269 'article': 80, 270 'phdthesis': 90, 271 'inbook': 100, 272 'book': 110, 273 'unpublished': 120 274 }, 275 // labels used for the different types of entries 276 labels: { 277 'article': 'Journal', 278 'book': 'Book', 279 'conference': 'Conference', 280 'inbook': 'Book chapter', 281 'incollection': '', 282 'inproceedings': 'Conference', 283 'manual': 'Manual', 284 'mastersthesis': 'Thesis', 285 'misc': 'Misc', 286 'phdthesis': 'PhD Thesis', 287 'proceedings': 'Conference proceeding', 288 'techreport': 'Technical report', 289 'unpublished': 'Unpublished'} 290 }; 291 // format a phd thesis similarly to masters thesis 292 bibproto.bib2html.phdthesis = bibproto.bib2html.mastersthesis; 293 // conference is the same as inproceedings 294 bibproto.bib2html.conference = bibproto.bib2html.inproceedings; 295 296 bibproto.initialize = function initialize(data) { 297 this.bibtex = new BibTex(); 298 this.bibtex.authorstring = "FIRST VON LAST JR"; 299 this.bibtex.content = data; 300 this.bibtex.parse(); 301 this.entries = {}; 302 var bibentries = []; 303 var entryTypes = {}; 304 var len = this.bibtex.data.length; 305 jQuery.extend(true, this.bib2html, this.options.bib2html); 306 for (var index = 0; index < len; index++) { 307 var item = this.bibtex.data[index]; 308 item.id = item.cite; 309 item.title = htmlify(item.title); 310 if (item.author) 311 item.authors = this.bib2html.authors2html(item, this); 312 313 if (!item.year) { 314 item.year = this.options.defaultYear || "To Appear"; 315 } 316 var html = this.bib2html.entry2html(item, this); 317 bibentries.push([item.year, this.bib2html.labels[item.entryType], html]); 318 entryTypes[this.bib2html.labels[item.entryType]] = item.entryType; 319 this.updateStats(item); 320 321 if (item.cite in this.entries) { 322 console.log("Repeated cite key for this bib entry.");
323 console.log(item); 324 } 325 this.entries[item.cite] = item; 326 } 327 328 var self = this; 329 if (this.$pubTable) { 330 jQuery.fn.dataTableExt.oSort['type-sort-asc'] = function(x, y) { 331 var item1 = self.bib2html.importance[entryTypes[x]], 332 item2 = self.bib2html.importance[entryTypes[y]]; 333 return ((item1 < item2) ? -1 : ((item1 > item2) ? 1 : 0)); 334 }; 335 jQuery.fn.dataTableExt.oSort['type-sort-desc'] = function(x, y) { 336 var item1 = self.bib2html.importance[entryTypes[x]], 337 item2 = self.bib2html.importance[entryTypes[y]]; 338 return ((item1 < item2) ? 1 : ((item1 > item2) ? -1 : 0)); 339 }; 340 var table = this.$pubTable.dataTable({ 'aaData': bibentries, 341 'aaSorting': this.options.sorting, 342 'aoColumns': [ { "sTitle": "Year" }, 343 { "sTitle": "Type", "sType": "type-sort", "asSorting": [ "desc", "asc" ] }, 344 { "sTitle": "Publication", "bSortable": false }], 345 'bPaginate': false 346 }); 347 if (this.options.visualization) { 348 this.addBarChart(); 349 } 350 $("th", this.$pubTable).unbind("click").click(function(e) { 351 var $this = $(this), 352 $thElems = $this.parent().find("th"), 353 index = $thElems.index($this); 354 if ($this.hasClass("sorting_disabled")) { return; } 355 $this.toggleClass("sorting_asc").toggleClass("sorting_desc"); 356 if (index === 0) { 357 table.fnSort( [[0, $thElems.eq(0).hasClass("sorting_asc")?"asc":"desc"], 358 [1, $thElems.eq(1).hasClass("sorting_asc")?"asc":"desc"]]); 359 } else { 360 table.fnSort( [[1, $thElems.eq(1).hasClass("sorting_asc")?"asc":"desc"], 361 [0, $thElems.eq(0).hasClass("sorting_asc")?"asc":"desc"]]); 362 } 363 }); 364 // attach the event handlers to the bib items 365 $(".biblink", this.$pubTable).on('click', EventHandlers.showbib); 366 $(".bibclose", this.$pubTable).on('click', EventHandlers.hidebib); 367 } 368 }; 369 // updates the stats, called whenever a new bibtex entry is parsed 370 bibproto.updateStats = function updateStats(item) { 371 if (!this.stats[item.year]) { 372 this.stats[item.year] = { 'count': 1, 'types': {} }; 373 this.stats[item.year].types[item.entryType] = 1; 374 } else { 375 this.stats[item.year].count += 1; 376 if (this.stats[item.year].types[item.entryType]) { 377 this.stats[item.year].types[item.entryType] += 1; 378 } else { 379 this.stats[item.year].types[item.entryType] = 1; 380 } 381 } 382 }; 383 // adds the barchart of year and publication types 384 bibproto.addBarChart = function addBarChart() { 385 var yearstats = [], max = 0; 386 $.each(this.stats, function(key, value) { 387 max = Math.max(max, value.count); 388 yearstats.push({'year': key, 'count': value.count, 389 'item': value, 'types': value.types}); 390 }); 391 yearstats.sort(function(a, b) { 392 var diff = a.year - b.year; 393 if (!isNaN(diff)) { 394 return diff; 395 } else if (a.year < b.year) { 396 return -1; 397 } else if (a.year > b.year) { 398 return 1; 399 } 400 return 0; 401 }); 402 var chartIdSelector = "#" + this.$pubTable[0].id + "pubchart"; 403 var pubHeight = $(chartIdSelector).height()/max - 2; 404 var styleStr = chartIdSelector +" .year { width: " + 405 (100.0/yearstats.length) + "%; }" + 406 chartIdSelector + " .pub { height: " + pubHeight + "px; }";
407 var legendTypes = []; 408 var stats2html = function(item) { 409 var types = [], 410 str = '<div class="year">', 411 sum = 0; 412 $.each(item.types, function(type, value) { 413 types.push(type); 414 sum += value; 415 }); 416 types.sort(function(x, y) { 417 return this.bib2html.importance[y] - this.bib2html.importance[x]; 418 }); 419 str += '<div class="filler" style="height:' + ((pubHeight+2)*(max-sum)) + 'px;"></div>'; 420 for (var i = 0; i < types.length; i++) { 421 var type = types[i]; 422 if (legendTypes.indexOf(type) === -1) { 423 legendTypes.push(type); 424 } 425 for (var j = 0; j < item.types[type]; j++) { 426 str += '<div class="pub ' + type + '"></div>'; 427 } 428 } 429 return str + '<div class="yearlabel">' + item.year + '</div></div>'; 430 }; 431 var statsHtml = "<style>" + styleStr + "</style>"; 432 yearstats.forEac
432h(function(item) { 433 statsHtml += stats2html(item); 434 }); 435 var legendHtml = '<div class="legend">'; 436 for (var i = 0, l = legendTypes.length; i < l; i++) { 437 var legend = legendTypes[i]; 438 legendHtml += '<span class="pub ' + legend + '"></span>' + this.bib2html.labels[legend]; 439 } 440 legendHtml += '</div>'; 441 $(chartIdSelector).html(statsHtml).after(legendHtml); 442 }; 443 444 // Creates a new publication list to the HTML element with ID 445 // bibElemId. The bibsrc can be 446 // - a jQuery selector, in which case html of the element is used 447 // as the bibtex data 448 // - a URL, which is loaded and used as data. Note, that same-origin 449 // policy restricts where you can load the data. 450 // Supported options: 451 // - visualization: A boolean to control addition of the visualization. 452 // Defaults to true. 453 // - tweet: Twitter username to add Tweet links to bib items with a url field. 454 // - sorting: Control the default sorting of the list. Defaults to [[0, "desc"], 455 // [1, "desc"]]. See http://datatables.net/api fnSort for details 456 // on formatting. 457 // - bib2html: Can be used to override any of the functions or properties of 458 // the bib2html object. See above, starting around line 40. 459 return function(bibsrc, opts, bibElemId) { 460 var options = $.extend({}, 461 {'visualization': false, 'sorting': [[0, "desc"], [1, "desc"]], file_links:false, showbibtex:false}, 462 opts); 463 464 if (bibElemId) { 465 if (options.visualization) { 466 $pubTable.before('<div id="' + bibElemId + 'pubchart" class="bibchart"></div>'); 467 } 468 469 bibElemId = $("#" + bibElemId).addClass("bibtable"); 470 } 471 472 return new Bib2HTML(bibsrc, bibElemId, options); 473 }; 474})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.