/* 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, recentCount: 5, 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(""+msg+""); } } this.setScope = function(code) { $('#scope #results').html(code); } this.clearCode = function(msg) { $('#code pre').empty(); if (msg) { $('#codes pre').html(""+msg+""); } } 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); } // hash should be "#code" this.showPanel = function(hash, callback){ t.showLoading(); setTimeout(function(){ $(".panel:visible").hide(); $("a.tab").removeClass('active'); $("a.tab[href='"+hash+"']").addClass('active'); $(hash).show(0, callback); t.updateScopeCount(); t.hideLoading(); }, 200); // 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("#scope"); // 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 = $("") .attr('id', 'module_search') .keyup(function(){ t.searchModule($(this).val()); }) .appendTo("#languages"); $("") .attr('href','#') .click(t.clearSearchModule) .html("Clear") .appendTo("#languages"); // Recent modules var recent = $("
") .attr('id', 'recent') .appendTo("#languages"); // 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; $('') .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); if ($('.tab.api').hasClass('active')) t.showPanel("#scope"); t.addRecent(lang, module); } // Add item to recent list this.addRecent = function(lang, module) { var full_module = lang+'/'+module; // If already there, do nothing if ($('#recent').text().indexOf(full_module) > -1) return; // Delete oldest if at limit if ($('#recent a').length >= t.state.recentCount) { $('#recent a').last().remove(); } // Add it $('') .html(full_module) .attr('href', "#"+lang+"/"+module+".gf") .prependTo("#recent"); } // 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 = ''+name+''; return ''+b+''+c+''+s[0]+''+s[1]+''+anchor+'' } 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 = ''+name+''; return ''+b+''+c+''+anchor+''+s[1]+'' } }); 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 "Syntax", "Constructors", "Cat", "Structural", "Combinators", // 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 = ''+name+''; out += ''+b+''+c+''+anchor+''+s[1]+'' } } 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(); } // ===== Module search ===== this.searchModule = function(s) { if (!s) { return t.clearSearchModule(); } $('#language_select').hide(); $("#modules").empty(); for (var lang in t.state.index['languages']) { var modules = t.state.index['languages'][lang]; for (var j in modules) { var module = modules[j]; var full_module = lang+'/'+module; if (!module) continue; if (full_module.toLowerCase().indexOf(s.toLowerCase())==-1) continue; $('') .html(full_module) .attr('href', "#"+lang+"/"+module+".gf") .appendTo("#modules"); } } }; this.clearSearchModule = function() { $('#module_search').val(''); $('#language_select').show(); t.setLanguage(t.state.language); return false; }; // ===== 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(); }); };