UNPKG

apidoc

Version:

RESTful web API Documentation Generator

590 lines (515 loc) 16.6 kB
require.config({ paths: { bootstrap: "./vendor/bootstrap.min", diffMatchPatch: "./vendor/diff_match_patch.min", handlebars: "./vendor/handlebars.min", handlebarsExtended: "./handlebars_helper", jquery: "./vendor/jquery.min", locales: "./locales/locale", lodash: "./vendor/lodash.min", prettify: "./vendor/prettify/prettify" }, shim: { bootstrap: { deps: ["jquery"] }, diffMatchPatch: { exports: "diff_match_patch" }, handlebars: { exports: "Handlebars" }, handlebarsExtended: { deps: ["jquery", "handlebars"], exports: "Handlebars" }, prettify: { exports: "prettyPrint" } }, urlArgs: "v=" + (new Date()).getTime(), waitSeconds: 1 }); require([ "jquery", "lodash", "locales", "handlebarsExtended", "./api_project.js", "./api_data.js", "prettify", "bootstrap" ], function($, _, locale, Handlebars, apiProject, apiData, prettyPrint) { var api = apiData.api; /** * Templates. */ var templateHeader = Handlebars.compile( $("#template-header").html() ); var templateFooter = Handlebars.compile( $("#template-footer").html() ); var templateArticle = Handlebars.compile( $("#template-article").html() ); var templateCompareArticle = Handlebars.compile( $("#template-compare-article").html() ); var templateGenerator = Handlebars.compile( $("#template-generator").html() ); var templateProject = Handlebars.compile( $("#template-project").html() ); var templateSections = Handlebars.compile( $("#template-sections").html() ); var templateSidenav = Handlebars.compile( $("#template-sidenav").html() ); /** * apiProject defaults. */ if( ! apiProject.template) apiProject.template = {}; if(apiProject.template.withCompare == null) apiProject.template.withCompare = true; if(apiProject.template.withGenerator == null) apiProject.template.withGenerator = true; /** * Data transform. */ // Grouped by group var apiByGroup = _.groupBy(api, function(entry) { return entry.group; }); // Grouped by group and name var apiByGroupAndName = {}; $.each(apiByGroup, function(index, entries) { apiByGroupAndName[index] = _.groupBy(entries, function(entry) { return entry.name; }); }); /** * Sort api by group - name - title. */ var newList = []; var umlauts = { "ä": "ae", "ü": "ue", "ö": "oe", "ß": "ss" }; $.each(apiByGroupAndName, function(index, groupEntries) { // Titel der ersten Einträge von group[].name[] ermitteln (name hat Versionsliste) var titles = {}; $.each(groupEntries, function(index, entries) { var title = entries[0].title; if(title) { title.toLowerCase().replace(/[äöüß]/g, function($0) { return umlauts[$0]; }); titles[title + " #~#" + index] = 1; } }); // each // Sortieren var values = Object.keys(titles); values.sort(); // Einzelne Elemente der neuen Liste hinzufügen. values.forEach(function(name) { var values = name.split( "#~#"); groupEntries[values[1]].forEach(function(entry) { newList.push(entry); }); // forEach }); // forEach }); // each // api überschreiben mit sortierter Liste. api = newList; /** * Group- and Versionlists. */ var apiGroups = {}; var apiVersions = {}; apiVersions[apiProject.version] = 1; $.each(api, function(index, entry) { apiGroups[entry.group] = 1; apiVersions[entry.version] = 1; }); // Sort. apiGroups = Object.keys(apiGroups); apiGroups.sort(); apiVersions = Object.keys(apiVersions); apiVersions.sort(); apiVersions.reverse(); /** * Create Navigationlist. */ var nav = []; apiGroups.forEach(function(group) { // Mainmenu-Entry. nav.push({ group: group, isHeader: true, title: group }); // Add Submenu. var oldName = ""; api.forEach(function(entry) { if(entry.group === group) { if(oldName !== entry.name) { nav.push({ title: entry.title, group: group, name: entry.name, type: entry.type, version: entry.version }); } else { nav.push({ title: entry.title, group: group, hidden: true, name: entry.name, type: entry.type, version: entry.version }); } oldName = entry.name; } }); // forEach }); // forEach // Mainmenu Header Entry. if(apiProject.header) { nav.unshift({ group: "_", isHeader: true, title: (apiProject.header.title == null) ? locale.__("General") : apiProject.header.title, isFixed: true }); } // Mainmenu Footer Entry. if(apiProject.footer && apiProject.footer.title != null) { nav.push({ group: "_footer", isHeader: true, title: apiProject.footer.title, isFixed: true }); } /** * Render Pagetitle. */ var title = apiProject.title ? apiProject.title : "apiDoc: " + apiProject.name + " - " + apiProject.version; $(document).attr("title", title); /** * Remove loader. */ $("#loader").remove(); /** * Render Sidenav. */ var fields = { nav: nav }; $("#sidenav").append( templateSidenav(fields) ); /** * Render Generator. */ $("#generator").append( templateGenerator(apiProject) ); /** * Render Project. */ _.extend(apiProject, { versions: apiVersions}); $("#project").append( templateProject(apiProject) ); /** * Render ApiDoc, header/footer documentation. */ if(apiProject.header) $("#header").append( templateHeader(apiProject.header) ); if(apiProject.footer) $("#footer").append( templateFooter(apiProject.footer) ); /** * Render Sections and Articles */ var articleVersions = {}; apiGroups.forEach(function(groupEntry) { var articles = []; var oldName = ""; var fields = {}; var description = ""; articleVersions[groupEntry] = {}; // Render all Articls of a group. api.forEach(function(entry) { if(groupEntry === entry.group) { if(oldName !== entry.name) { // Artikelversionen ermitteln. api.forEach(function(versionEntry) { if(groupEntry === versionEntry.group && entry.name === versionEntry.name) { if( ! articleVersions[entry.group][entry.name]) articleVersions[entry.group][entry.name] = []; articleVersions[entry.group][entry.name].push(versionEntry.version); } }); fields = { article: entry, versions: articleVersions[entry.group][entry.name] }; } else { fields = { article: entry, hidden: true, versions: articleVersions[entry.group][entry.name] }; } addArticleSettings(fields, entry); // TODO: make groupDescription compareable with older versions (not important for the moment). if (entry.groupDescription) description = entry.groupDescription; articles.push({ article: templateArticle(fields), group: entry.group, name: entry.name }); oldName = entry.name; } }); // forEach // Render Section with Articles. var fields = { group: groupEntry, title: groupEntry, description: description, articles: articles }; $("#sections").append( templateSections(fields) ); }); // forEach /** * Bootstrap Scrollspy. */ $("body").scrollspy({ offset: 25 }); // Content-Scroll on Navigation click. $(".sidenav").find("a").on("click", function(e) { e.preventDefault(); var id = $(this).attr("href"); $('html,body').animate({ scrollTop: parseInt($(id).offset().top) }, 400); window.location.hash = $(this).attr("href"); }); // Quickjump on Pageload to hash position. if(window.location.hash) { var id = window.location.hash; $('html,body').animate({ scrollTop: parseInt($(id).offset().top) }, 0); } /** * Check if Parameter (sub) List has a type Field. * Example: @apaSuccess varname1 No type. * @apaSuccess {String} varname2 With type. * * @param {Object} fields */ function _hasTypeInFields(fields) { hasField = false; $.each(fields, function(name) { if(_.any(fields[name], function(item) { return item.type; }) ) { hasField = true; } }); return hasField; } // _hasTypeInFields /** * On Template changes, recall plugins. */ function initDynamic() { // Bootstrap Popover. $("a[data-toggle=popover]") .popover() .click(function(e) { e.preventDefault(); }) ; var version = $("#version strong").html(); $("#sidenav li").removeClass("is-new"); if(apiProject.template.withCompare) { $("#sidenav li[data-version=\"" + version + "\"]").each(function(){ var group = $(this).data("group"); var name = $(this).data("name"); var length = $("#sidenav li[data-group=\"" + group + "\"][data-name=\"" + name + "\"]").length; var index = $("#sidenav li[data-group=\"" + group + "\"][data-name=\"" + name + "\"]").index($(this)); if(length === 1 || index === (length - 1)) { $(this).addClass("is-new"); } }); } } // initDynamic initDynamic(); /** * Pre- / Code-Format. */ prettyPrint(); /** * HTML-Template specific jQuery-Functions */ // Change Main Version $("#versions li.version a").on("click", function(e) { e.preventDefault(); var selectedVersion = $(this).html(); $("#version strong").html(selectedVersion); // Hide all $("article").addClass("hide"); $("#sidenav li:not(.nav-fixed)").addClass("hide"); // Show 1st equal or lower Version of each entry $("article[data-version]").each(function(index) { var group = $(this).data("group"); var name = $(this).data("name"); var version = $(this).data("version"); if(version <= selectedVersion) { if($("article[data-group=\"" + group + "\"][data-name=\"" + name + "\"]:visible").length === 0) { // Enable Article $("article[data-group=\"" + group + "\"][data-name=\"" + name + "\"][data-version=\"" + version + "\"]").removeClass("hide"); // Enable Navigation $("#sidenav li[data-group=\"" + group + "\"][data-name=\"" + name + "\"][data-version=\"" + version + "\"]").removeClass("hide"); $("#sidenav li.nav-header[data-group=\"" + group + "\"]").removeClass("hide"); } } }); initDynamic(); return; }); // On click compare all currently selected Versions with their predecessor. $("#compareAllWithPredecessor").on("click", changeAllVersionCompareTo); // On change the Version of an article. $("article .versions li.version a").on("click", changeVersionCompareTo); $.urlParam = function(name) { var results = new RegExp('[\\?&amp;]' + name + '=([^&amp;#]*)').exec(window.location.href); return (results && results[1]) ? results[1] : null; }; if($.urlParam("compare")) { // URL Paramter ?compare=1 is set. $("#compareAllWithPredecessor").trigger("click"); if(window.location.hash) { var id = window.location.hash; $('html,body').animate({ scrollTop: parseInt($(id).offset().top) - 18 }, 0); } } /** * */ function changeVersionCompareTo(e) { e.preventDefault(); var $root = $(this).parents("article"); var selectedVersion = $(this).html(); var $button = $root.find(".version"); var currentVersion = $button.find("strong").html(); $button.find("strong").html(selectedVersion); var group = $root.data("group"); var name = $root.data("name"); var version = $root.data("version"); var compareVersion = $root.data("compare-version"); if(compareVersion === selectedVersion) return; if( ! compareVersion && version == selectedVersion) return; if( compareVersion && articleVersions[group][name][0] === selectedVersion || version === selectedVersion ) { // Version des Eintrages wurde wieder auf höchste Version gesetzt (reset) resetArticle(group, name, version); } else { var $compareToArticle = $("article[data-group=\"" + group + "\"][data-name=\"" + name + "\"][data-version=\"" + selectedVersion + "\"]"); var sourceEntry = {}; var compareEntry = {}; $.each(apiByGroupAndName[group][name], function(index, entry) { if(entry.version === version) sourceEntry = entry; if(entry.version === selectedVersion) compareEntry = entry; }); var fields = { article: sourceEntry, compare: compareEntry, versions: articleVersions[group][name] }; var entry = sourceEntry; if(entry.parameter && entry.parameter.fields) fields._hasTypeInParameterFields = _hasTypeInFields(entry.parameter.fields); if(entry.error && entry.error.fields) fields._hasTypeInErrorFields = _hasTypeInFields(entry.error.fields); if(entry.success && entry.success.fields) fields._hasTypeInSuccessFields = _hasTypeInFields(entry.success.fields); if(entry.info && entry.info.fields) fields._hasTypeInInfoFields = _hasTypeInFields(entry.info.fields); var entry = compareEntry; if(fields._hasTypeInParameterFields !== true && entry.parameter && entry.parameter.fields) fields._hasTypeInParameterFields = _hasTypeInFields(entry.parameter.fields); if(fields._hasTypeInErrorFields !== true && entry.error && entry.error.fields) fields._hasTypeInErrorFields = _hasTypeInFields(entry.error.fields); if(fields._hasTypeInSuccessFields !== true && entry.success && entry.success.fields) fields._hasTypeInSuccessFields = _hasTypeInFields(entry.success.fields); if(fields._hasTypeInInfoFields !== true && entry.info && entry.info.fields) fields._hasTypeInInfoFields = _hasTypeInFields(entry.info.fields); var content = templateCompareArticle(fields); $root.after(content); var $content = $root.next(); // Event on.click muss neu zugewiesen werden (sollte eigentlich mit on automatisch funktionieren... sollte) $content.find(".versions li.version a").on("click", changeVersionCompareTo); // Navigation markieren $("#sidenav li[data-group=\"" + group + "\"][data-name=\"" + name + "\"][data-version=\"" + currentVersion + "\"]").addClass("has-modifications"); $root.remove(); // todo: bei Hauptversionswechsel oder zurückstellen auf höchste Eintragsversion, den Eintrag neu rendern } initDynamic(); return; } // changeVersionCompareTo /** * */ function changeAllVersionCompareTo(e) { e.preventDefault(); $("article:visible .versions").each(function(){ var $root = $(this).parents("article"); var currentVersion = $root.data("version"); var $foundElement = null; $(this).find("li.version a").each(function() { var selectVersion = $(this).html(); if(selectVersion < currentVersion && ! $foundElement) { $foundElement = $(this); } }); if($foundElement) { $foundElement.trigger("click"); } }); initDynamic(); return; } // changeAllVersionCompareTo /** * Add article settings. */ function addArticleSettings(fields, entry) { if(entry.header && entry.header.fields) fields._hasTypeInHeaderFields = _hasTypeInFields(entry.header.fields); if(entry.parameter && entry.parameter.fields) fields._hasTypeInParameterFields = _hasTypeInFields(entry.parameter.fields); if(entry.error && entry.error.fields) fields._hasTypeInErrorFields = _hasTypeInFields(entry.error.fields); if(entry.success && entry.success.fields) fields._hasTypeInSuccessFields = _hasTypeInFields(entry.success.fields); if(entry.info && entry.info.fields) fields._hasTypeInInfoFields = _hasTypeInFields(entry.info.fields); // Add prefix URL for endpoint if(apiProject.url) fields.article.url = apiProject.url + fields.article.url; // Add template settings fields.template = apiProject.template; } // addArticleSettings /** * Render an Article. */ function renderArticle(group, name, version) { var entry = {}; $.each(apiByGroupAndName[group][name], function(index, currentEntry) { if(currentEntry.version === version) entry = currentEntry; }); var fields = { article: entry, versions: articleVersions[group][name] }; addArticleSettings(fields, entry); return templateArticle(fields); } // renderArticle /** * Render the original Article and remove the current visible Article. */ function resetArticle(group, name, version) { var $root = $("article[data-group=\"" + group + "\"][data-name=\"" + name + "\"]:visible"); var content = renderArticle(group, name, version); $root.after(content); var $content = $root.next(); // Event on.click muss neu zugewiesen werden (sollte eigentlich mit on automatisch funktionieren... sollte) $content.find(".versions li.version a").on("click", changeVersionCompareTo); $("#sidenav li[data-group=\"" + group + "\"][data-name=\"" + name + "\"][data-version=\"" + version + "\"]").removeClass("has-modifications"); $root.remove(); return; } // resetArticle });