Files
gf-core/lib/doc/browse/script.js
2013-07-24 07:07:50 +00:00

504 lines
16 KiB
JavaScript

/*
GF RGL Browser
John J. Camilleri, 2013
*/
var thing = null;
$(document).ready(function(){
thing = new Thing();
// ===== URL history =====
$.history.on('load change push pushed', function(event, url, type) {
var stripExt = function(s) {
var i = s.lastIndexOf('.');
return (i>-1) ? s.substr(0, i) : s;
};
var s = url.split("/");
var lang = s[0];
var module = stripExt(s[1]);
var parseLineNo = s[1].match(/:(\d+)(-(\d+))?$/);
if (thing.state.current.equals(lang, module)) {
if (parseLineNo) {
thing.scrollToCodeLine(parseInt(parseLineNo[1]));
}
// else there's nothing to do!
} else {
if (parseLineNo != undefined)
thing.loadFile(lang, module, parseInt(parseLineNo[1]));
else
thing.loadFile(lang, module);
}
}).listen('hash');
});
function Thing() {
var t = this;
// ===== State information =====
this.state = {
index: undefined,
lookup: {},
loadCount: 0,
language: undefined, // lang of drop-down
current: { // current file
language: undefined,
module: undefined,
set: function(lang, module) {
t.state.current.language = lang;
t.state.current.module = module;
},
equals: function(a, b) {
if (!b)
return (a == t.state.current.module);
else
return (a == t.state.current.language) && (b == t.state.current.module);
}
},
title: "RGL Source Browser",
urlPrefix: "/",
defaultLangs: ['abstract','api','common','prelude']
} ;
this.lookupModuleLanguage = function(module) {
var l = t.state.lookup[module];
if (l==undefined || l.length==0)
return null;
else if (l.length==1)
return l[0];
else {
for (i in l) {
if ($.inArray(l[i], t.state.defaultLangs))
return l[i];
}
return l[0]; // no preferred default, just return first...
}
}
this.lookupAllModuleLanguages = function(module) {
return t.state.lookup[module];
}
// ===== Utility/UI functions =====
this.showLoading = function(){
t.state.loadCount++;
$("#loading").show();
}
this.hideLoading = function(){
t.state.loadCount = Math.max(t.state.loadCount-1, 0);
if (t.state.loadCount == 0)
$("#loading").hide();
}
this.scrollToTop = function() {
$("html, body").animate({ scrollTop: 0 }, "slow");
}
this.scrollToCodeLine = function(lineNo) {
t.showPanel("#code", function() {
// Find exact line, using the classes generated by google prettify
try {
var obj = $("#code pre li.L"+(lineNo%10)+":eq("+Math.floor(lineNo/10)+")").prev();
var y = Math.max(obj.offset().top - obj.parent().offset().top - 75, 0);
$("#code").parent().animate({ scrollTop: y }, "slow", function(){
t.highlight(obj);
});
} catch (e) {}
});
}
this.highlight = function(obj) {
obj.css('background-color', "yellow");
setTimeout(function(){
obj.css('background-color', "");
}, 1500);
}
this.clearScope = function(msg) {
$('#scope #results').empty();
t.updateScopeCount();
if (msg) {
$('#scope #results').html("<em>"+msg+"</em>");
}
}
this.setScope = function(code) {
$('#scope #results').html(code);
}
this.clearCode = function(msg) {
$('#code pre').empty();
if (msg) {
$('#codes pre').html("<em>"+msg+"</em>");
}
}
this.setCode = function(code) {
$('#code pre').text(code);
prettyPrint();
}
this.updateScopeCount = function(){
$('#scope #count').text( $("#scope #results tr:visible").length );
}
this.updateAPICount = function(){
$('#api #count').text( $("#api #results tr:visible").length );
}
this.setLanguage = function(lang){
t.state.language = lang;
$("#languages select").val(lang);
t.initModules(lang);
}
// obj can be just a plain selector or a jQuery object
this.showPanel = function(obj, callback){
t.showLoading();
setTimeout(function(){
$(".panel:visible").hide();
$(obj).show(0, callback);
t.updateScopeCount();
t.hideLoading();
}, 500); // this ensures the loading displays
}
this.getPanel = function() {
return $('.panel:visible').first();
}
this.setTitle = function(s){
$('#module_name').html(s);
$('title').html(t.state.title + ": " + s);
}
// ===== Initialization =====
// Initialize the panels, tabs
$("a.tab").click(function(){
var panel = $(this).attr("href");
t.showPanel(panel);
return false;
});
t.showPanel(".panel:first");
// Load the index file and populate language & module lists
$.ajax({
url: "index.json",
dataType: "json",
type: "GET",
success: function(data) {
t.state.index = data;
if (data['urlprefix']) t.state.urlPrefix = data['urlprefix'];
// Build language lookup index
for (var lang in data['languages']) {
for (var i in data['languages'][lang]) {
var module = data['languages'][lang][i];
if (!module) continue;
if (!t.state.lookup[module]) t.state.lookup[module] = [];
t.state.lookup[module].push(lang);
}
}
// Initialize the language list
var lang_select = $("<select>")
.attr('id', 'language_select')
.change(function(){
t.setLanguage($(this).val());
})
.appendTo("#languages")
var language_list = data['languages'];
for (var i in language_list) {
if (!i) continue;
var lang = i;
$('<option>')
.html(lang)
.appendTo(lang_select);
}
t.setLanguage("english");
// Initialize API results
t.initAPI();
// Done
t.hideLoading();
},
error: function(){
t.hideLoading();
alert("Error getting index. Try reloading page, or just give up.");
}
});
// ===== Loading functionality =====
// Initialize the module list
this.initModules = function(lang){
t.state.index['languages'][lang] = t.state.index['languages'][lang].sort();
$("#modules").empty();
for (var i in t.state.index['languages'][lang]) {
var module = t.state.index['languages'][lang][i];
if (!module) continue;
$('<a>')
.html(module)
.attr('href', "#"+lang+"/"+module+".gf")
.appendTo("#modules");
}
};
// Load both scope & source for a file
this.loadFile = function(lang, module, lineNo){
t.setTitle(lang+"/"+module);
t.state.current.set(lang, module);
t.loadTagsFile(module);
t.loadSourceFile(lang, module, lineNo);
}
// Load a tags file
this.loadTagsFile = function(module) {
t.clearScope();
t.showLoading();
$.ajax({
url: "tags/"+module+".gf-tags",
type: "GET",
dataType: "text",
success: function(data){
data = data.replace(/^(\S+)\s(\S+)\s(.+)?$/gm, function(a,b,c,d){
var s = d.split("\t");
if (c == "indir") {
var module = s[2].substring(s[2].lastIndexOf('/')+1, s[2].lastIndexOf('.'));
var lang = t.lookupModuleLanguage(module);
var name = lang+"/"+module;
var url = "#"+lang+"/"+module;
var anchor = '<a href="'+url+'">'+name+'</a>';
return '<tr class="indir" name="'+b+'"><th>'+b+'</th><td>'+c+'</td><td>'+s[0]+'</td><td>'+s[1]+'</td><td>'+anchor+'</td><td></td></tr>'
} else {
var bits = s[0].split("/"); // ["lib", "src", "english", "AdjectiveEng.gf:43-46"]
var name = bits[3]+"/"+bits[4];
var url = "#"+bits[3]+"/"+bits[4];
var anchor = '<a href="'+url+'">'+name+'</a>';
return '<tr class="local" name="'+b+'"><th>'+b+'</th><td>'+c+'</td><td></td><td></td><td>'+anchor+'</td><td>'+s[1]+'</td></tr>'
}
});
t.setScope(data);
t.runFilter();
t.hideLoading();
},
error: function(data){
t.clearScope("No scope available");
t.hideLoading();
},
});
}
// Load a source module
this.loadSourceFile = function(lang, module, lineNo) {
t.clearCode();
t.showLoading();
$.ajax({
url: t.state.urlPrefix + "lib/src/"+lang+"/"+module+".gf",
type: "GET",
dataType: "text",
success: function(data, status, xhr){
t.setCode(data);
t.hideLoading();
if (lineNo) {
t.scrollToCodeLine(lineNo);
}
},
error: function(data){
t.clearCode("No code available");
t.hideLoading();
}
});
}
// Which modules do we include for API?
this.apiModules = [
// api
"Constructors",
// abstract
"Adjective",
"Adverb",
"Backward",
"Cat",
"Common",
"Compatibility",
"Conjunction",
"Extra",
"Grammar",
"Idiom",
"Lang",
"Lexicon",
"Noun",
"Numeral",
"NumeralTransfer",
"Phrase",
"Question",
"Relative",
"Sentence",
"Structural",
"Symbol",
"Tense",
"Text",
"Transfer",
"Verb",
];
this.initAPI = function() {
t.showLoading();
$('#api #results').empty();
for (var i in t.apiModules) {
var module = t.apiModules[i];
$.ajax({
url: "tags/"+module+".gf-tags",
type: "GET",
dataType: "text",
success: function(data){
data = data.replace(/^(\S+)\s(\S+)\s(.+)?$/gm, function(a,b,c,d){
var out = '';
var s = d.split("\t");
if (c != "indir") {
var type = s[1];
if (type) {
var bits = s[0].split("/"); // ["lib", "src", "english", "AdjectiveEng.gf:43-46"]
var name = bits[3]+"/"+bits[4];
var url = "#"+bits[3]+"/"+bits[4];
var anchor = '<a href="'+url+'">'+name+'</a>';
out += '<tr name="'+b+'"><th>'+b+'</th><td>'+c+'</td><td>'+anchor+'</td><td>'+s[1]+'</td></tr>'
}
}
return out;
});
$('#api #results').append($(data));
$("#api #results tr").removeClass('odd');
$("#api #results tr:odd").addClass('odd');
$('#api #count').text( $("#api #results tr").length );
},
error: function(data){
console.log("Error loading tags file: " + module);
},
});
}
t.hideLoading();
}
// ===== Filtering of scope info =====
// Custom selector
$.expr[':'].match = function(a,b,c) {
var obj = $(a);
var needle = c[3];
var haystack = obj.attr('name');
if (haystack == undefined)
return false;
if ($("#scope #case_sensitive").is(":checked"))
return haystack.indexOf(needle)>=0;
else
return haystack.toLowerCase().indexOf(needle.toLowerCase())>=0;
};
this.runFilter = function() {
t.showLoading();
$("#scope #results tr").removeClass('odd');
var s = $("#scope #search").val();
try {
if (s) {
$("#scope #results tr").hide();
$("#scope #results tr:match(\""+s+"\")").show();
} else {
$("#scope #results tr").show();
}
if ($("#scope #show_local").is(":checked") ) {
$("#scope #results tr.indir").hide();
}
} catch (error) {
alert(error.message);
}
t.updateScopeCount();
$("#scope #results tr:visible:odd").addClass('odd');
t.hideLoading();
}
// Instant results
this.prevSearch = $("#scope #search").val();
$("#scope #search").keyup(function(){
var s = $("#scope #search").val();
if (s!=t.prevSearch) {
t.runFilter();
t.prevSearch = s;
}
});
$("#scope #search").keypress(function(e){
var code = (e.keyCode ? e.keyCode : e.which);
if(code == 13) { // Enter
t.runFilter();
}
});
$("#scope #clear").click(function(){
$("#scope #search")
.val('')
.focus()
t.runFilter();
});
$("#scope #case_sensitive").change(t.runFilter);
$("#scope #show_all").change(t.runFilter);
$("#scope #show_local").change(t.runFilter);
// ===== API search =====
// Custom selector
$.expr[':'].matchAPI = function(a,b,c) {
var obj = $(a); // tr
var ident = $(obj.children().get(0)).text();
var type = $(obj.children().get(3)).text();
var needle = c[3];
var match_ident = ident.toLowerCase().indexOf(needle.toLowerCase())>=0;
var match_type = type.toLowerCase().indexOf(needle.toLowerCase())>=0;
// if ($("#scope #case_sensitive").is(":checked"))
// return haystack.indexOf(needle)>=0;
// else
return match_ident || match_type ;
};
this.runFilterAPI = function() {
t.showLoading();
$("#api #results tr").removeClass('odd');
var s = $("#api #search").val();
try {
if (s) {
$("#api #results tr").hide();
$("#api #results tr:matchAPI(\""+s+"\")").show();
} else {
$("#api #results tr").show();
}
} catch (error) {
alert(error.message);
}
t.updateAPICount();
$("#api #results tr:visible:odd").addClass('odd');
t.hideLoading();
}
// Instant results
this.prevAPISearch = $("#api #search").val();
$("#api #search").keyup(function(){
var s = $("#api #search").val();
if (s!=t.prevAPISearch) {
t.runFilterAPI();
t.prevAPISearch = s;
}
});
$("#api #search").keypress(function(e){
var code = (e.keyCode ? e.keyCode : e.which);
if(code == 13) { // Enter
t.runFilterAPI();
}
});
$("#api #clear").click(function(){
$("#api #search")
.val('')
.focus();
t.runFilterAPI();
});
};