Skip to content
This repository has been archived by the owner on Jun 11, 2024. It is now read-only.

Commit

Permalink
optimized navigation search and order
Browse files Browse the repository at this point in the history
  • Loading branch information
mpneuried committed Jan 17, 2023
1 parent 75f9b1d commit 91dc7e2
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ defmodule BXApiExampleWeb.TestController do
alias BXApiExample.Tests.Test

@apidoc """
@api {get} /test_entity/ List Tests
@api {get} /test_entity/ List
@apiName ListTests
@apiGroup Tests
@apiVersion 0.31.0
@apiGroup TestEntities
@apiVersion 0.8.15
@apiParam (Query Parameters) {Number} limit=500 Limit the number of returned elements
@apiParam (Query Parameters) {String } [id] get a single id
Expand Down Expand Up @@ -39,9 +39,9 @@ defmodule BXApiExampleWeb.TestController do

@apidoc """
@api {post} /test_entity/ Create
@apiGroup Tests
@apiGroup TestEntities
@apiName CreateTest
@apiVersion 0.31.0
@apiVersion 0.8.15
@apiParam (Body) {String} name the name of the element
@apiParam (Body) {String} tenant_id the tenant this element should belong to
Expand Down Expand Up @@ -71,4 +71,64 @@ defmodule BXApiExampleWeb.TestController do
|> render("show.json", test: result)
end
end

@apidoc """
@api {post} /example_entity/ Create
@apiGroup ExampleEntities
@apiName CreateTest
@apiVersion 0.8.15
@apiParam (Body) {String} name the name of the element
@apiParam (Body) {String} tenant_id the tenant this element should belong to
@apiParam (Body) {Object} settings={} a object of special settings for this element
@apiSuccessExample Success-Response:
HTTP/1.1 201 Created
{
"id": "5fcc2352-aa5a-4ad2-8c98-f6af5f9b7637",
"name": "Test 183",
"tenant_id": "test",
"settings": { "foo": 1337 }
}
@apiExample {curl} Curl:
curl -X POST -i http://api.example.com/api/example_entity -d '{
"name": "Test 183",
"tenant_id": "test",
"settings": { "foo": 1337 }
}'
}
"""
def create(conn, test_params) do
with {:ok, %Test{} = result} <- Tests.create_Test(test_params) do
conn
|> put_status(:created)
|> render("show.json", test: result)
end
end

@apidoc """
@apiDefine MQTTExampleEntitiesData
@apiExample {mqtt} Example message:
{
"id": "5fcc2352-aa5a-4ad2-8c98-f6af5f9b7637",
"name": "Test 183",
"tenant_id": "test",
"settings": { "foo": 1337 }
}
"""

@apidoc """
@api {mqtt} tenant/:tenant_id/example_entity/create ExampleEntity Created
@apiGroup #MQTT-Messages
@apiName MQTT ExampleEntities Created
@apiVersion 0.8.15
@apiDescription MQTT Message after a new example entity was created
@apiUse MQTTExampleEntitiesData
"""
defp get_topic(%{tenant_id: cid, id: _id}, "create") do
["tenant/#{cid}/example_entity/create"]
end
end
2 changes: 1 addition & 1 deletion lib/core/languages/ex.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const STANDARD_PARSER = {

const OLD_PARSER = {
docBlocksRegExp: /@apidoc\s+("{3})\uffff?(.+?)\uffff?(?:\s*)?("{3})+\s?/g,
inlineRegExp: /^@apidoc\s*\n/gm,
inlineRegExp: /^@apidoc\s*\n/g,
};

module.exports = EX_TYPE === 'standard' ? STANDARD_PARSER : OLD_PARSER;
38 changes: 22 additions & 16 deletions template/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,38 @@
<body class="container-fluid">

<!-- SIDENAV -->

<script id="template-sidenav-list" type="text/x-handlebars-template">
{{#each nav}}
{{#if title}}
{{#if isHeader}}
{{#if isFixed}}
<li class="nav-fixed nav-header navbar-btn nav-list-item" data-group="{{group}}"><a href="#api-{{group}}" data-name="show-api-{{group}}" class="show-api api-{{group}}-init">{{underscoreToSpace title}}</a></li>
{{else}}
<li class="nav-header nav-list-item" data-group="{{group}}"><a href="#api-{{group}}" data-group="show-api-{{group}}" class="show-group api-{{group}}-init">{{underscoreToSpace title}}</a></li>
{{/if}}
{{else}}
<li class="{{#if hidden}}hide {{/if}}" data-group="{{group}}" data-name="{{name}}" data-version="{{version}}">
<a href="#api-{{group}}-{{name}}" title="{{url}}" data-group="show-api-{{group}}" data-name="show-api-{{group}}-{{name}}" class="nav-list-item show-api api-{{group}}-{{name}}-init">{{title}}<div class="nav-list-url-item hide">{{url}}</div></a>
</li>
{{/if}}
{{/if}}
{{/each}}
</script>

<script id="template-sidenav" type="text/x-handlebars-template">
<nav id="scrollingNav">
<div class="sidenav-search">
<input class="form-control search" data-action='filter-search' type="text" placeholder="{{__ "Filter..."}}">
<span class="search-reset">x</span>
</div>
<ul class="sidenav nav nav-list list">
{{#each nav}}
{{#if title}}
{{#if isHeader}}
{{#if isFixed}}
<li class="nav-fixed nav-header navbar-btn nav-list-item" data-group="{{group}}"><a href="#api-{{group}}" data-name="show-api-{{group}}" class="show-api api-{{group}}-init">{{underscoreToSpace title}}</a></li>
{{else}}
<li class="nav-header nav-list-item" data-group="{{group}}"><a href="#api-{{group}}" data-group="show-api-{{group}}" class="show-group api-{{group}}-init">{{underscoreToSpace title}}</a></li>
{{/if}}
{{else}}
<li class="{{#if hidden}}hide {{/if}}" data-group="{{group}}" data-name="{{name}}" data-version="{{version}}">
<a href="#api-{{group}}-{{name}}" title="{{url}}" data-group="show-api-{{group}}" data-name="show-api-{{group}}-{{name}}" class="nav-list-item show-api api-{{group}}-{{name}}-init">{{title}}<div class="nav-list-url-item hide">{{url}}</div></a>
</li>
{{/if}}
{{/if}}
{{/each}}
<ul class="sidenav nav nav-list list" >
{{subTemplate "sidenav-list" nav=nav }}
</ul>
</nav>
</script>


<!-- PROJECT -->
<script id="template-project" type="text/x-handlebars-template">
<div class="pull-left">
Expand Down
73 changes: 47 additions & 26 deletions template/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ document.addEventListener('DOMContentLoaded', () => {
Prism.highlightAll();
});

function init () {
function init() {
// the data is injected at compile time by webpack
let api = API_DATA; // eslint-disable-line no-undef
const apiProject = API_PROJECT; // eslint-disable-line no-undef
Expand All @@ -52,6 +52,7 @@ function init () {
const templateProject = Handlebars.compile($('#template-project').html());
const templateSections = Handlebars.compile($('#template-sections').html());
const templateSidenav = Handlebars.compile($('#template-sidenav').html());
const templateSidenavList = Handlebars.compile($('#template-sidenav-list').html());

// apiProject defaults
const defaultTemplateOptions = {
Expand Down Expand Up @@ -89,6 +90,7 @@ function init () {
$.each(apiByGroupAndName, (index, groupEntries) => {
// get titles from the first entry of group[].name[] (name has versioning)
let titles = [];

$.each(groupEntries, (titleName, entries) => {
const title = entries[0].title;
if (title) {
Expand Down Expand Up @@ -125,13 +127,16 @@ function init () {

$.each(api, (index, entry) => {
apiGroups[entry.group] = 1;
apiGroupTitles[entry.group] = entry.groupTitle || entry.group;
apiGroupTitles[entry.group] = { title: entry.groupTitle || entry.group, group: entry.group };
apiVersions[entry.version] = 1;
});

// sort groups
apiGroups = Object.keys(apiGroups);
apiGroups.sort();
apiGroups = Object.values(apiGroupTitles).sort((left, right) => {
return -left.title.localeCompare(right.title);
}).map(group => {
return group.group;
});

// custom order
if (apiProject.order) { apiGroups = sortGroupsByOrder(apiGroupTitles, apiProject.order); }
Expand All @@ -150,7 +155,7 @@ function init () {
nav.push({
group: group,
isHeader: true,
title: apiGroupTitles[group],
title: apiGroupTitles[group].title,
});

// Submenu
Expand Down Expand Up @@ -189,7 +194,7 @@ function init () {
* @param index where to insert items
* @return boolean true if any good-looking (i.e. with a group identifier) <h1> tag was found
*/
function addNav (nav, content, index) {
function addNav(nav, content, index) {
let foundLevel1 = false;
if (!content) {
return foundLevel1;
Expand Down Expand Up @@ -402,7 +407,7 @@ function init () {
*
* @param {Object} fields
*/
function _hasTypeInFields (fields) {
function _hasTypeInFields(fields) {
let result = false;
$.each(fields, name => {
result = result || some(fields[name], item => { return item.type; });
Expand All @@ -413,7 +418,7 @@ function init () {
/**
* On Template changes, recall plugins.
*/
function initDynamic () {
function initDynamic() {
// Bootstrap popover
$('button[data-toggle="popover"]').popover().click(function (e) {
e.preventDefault();
Expand Down Expand Up @@ -508,7 +513,7 @@ function init () {
// HTML-Template specific jQuery-Functions
//
// Change Main Version
function setMainVersion (selectedVersion) {
function setMainVersion(selectedVersion) {
if (typeof selectedVersion === 'undefined') {
selectedVersion = $('#version strong').html();
} else {
Expand Down Expand Up @@ -593,15 +598,32 @@ function init () {
*/
$('[data-action="filter-search"]').on('keyup', event => {
const query = event.currentTarget.value.toLowerCase();
// find all links that are endpoints
$('.sidenav').find('a.nav-list-item').each((index, el) => {
// begin by showing all so they don't stay hidden
$(el).show();
// now simply hide the ones that don't match the query
if (!el.innerText.toLowerCase().includes(query)) {
$(el).hide();

// templateSidenavList(fields)
const groupIndex = {};
const filteredNav = nav.filter((navEl) => {
return navEl.isHeader || navEl.group.toLowerCase().includes(query) || navEl.name.toLowerCase().includes(query) || navEl.title.toLowerCase().includes(query);
}).reduce((acc, navEl) => {
if (navEl.isHeader) {
groupIndex[navEl.group] = navEl;
groupIndex[navEl.group].elements = [];
acc.push(navEl);
return acc;
}
groupIndex[navEl.group].elements.push(navEl);
return acc;
}, []).filter((group) => {
return group.elements.length;
}).flatMap((group) => {
const { elements, ...groupRest } = group;
return [groupRest, ...elements];
});

if (filteredNav.length) {
$('.sidenav ').html(templateSidenavList({ nav: filteredNav }));
} else {
$('.sidenav ').html('<li class="nav-header nav-list-item" style="text-align:center"><i class="show-group">No results</i></li>');
}
});

/**
Expand All @@ -610,15 +632,14 @@ function init () {
$('span.search-reset').on('click', function () {
$('#scrollingNav .sidenav-search input.search')
.val('')
.focus()
;
.focus();
$('.sidenav').find('a.nav-list-item').show();
});

/**
* Change version of an article to compare it to an other version.
*/
function changeVersionCompareTo (e) {
function changeVersionCompareTo(e) {
e.preventDefault();

const $root = $(this).parents('article');
Expand Down Expand Up @@ -700,7 +721,7 @@ function init () {
/**
* Compare all currently selected Versions with their predecessor.
*/
function changeAllVersionCompareTo (e) {
function changeAllVersionCompareTo(e) {
e.preventDefault();
$('article:visible .versions').each(function () {
const $root = $(this).parents('article');
Expand All @@ -718,7 +739,7 @@ function init () {
/**
* Add article settings.
*/
function addArticleSettings (fields, entry) {
function addArticleSettings(fields, entry) {
// add unique id
// TODO: replace all group-name-version in template with id.
fields.id = fields.article.group + '-' + fields.article.name + '-' + fields.article.version;
Expand Down Expand Up @@ -751,7 +772,7 @@ function init () {
/**
* Render Article.
*/
function renderArticle (group, name, version) {
function renderArticle(group, name, version) {
let entry = {};
$.each(apiByGroupAndName[group][name], function (index, currentEntry) {
if (currentEntry.version === version) { entry = currentEntry; }
Expand All @@ -769,7 +790,7 @@ function init () {
/**
* Render original Article and remove the current visible Article.
*/
function resetArticle (group, name, version) {
function resetArticle(group, name, version) {
const $root = $('article[data-group=\'' + group + '\'][data-name=\'' + name + '\']:visible');
const content = renderArticle(group, name, version);

Expand All @@ -791,7 +812,7 @@ function init () {
* @param {String} splitBy
* @return {String[]} Custom ordered list.
*/
function sortByOrder (elements, order, splitBy) {
function sortByOrder(elements, order, splitBy) {
const results = [];
order.forEach(function (name) {
if (splitBy) {
Expand Down Expand Up @@ -819,11 +840,11 @@ function init () {
* @param {String[]} order
* @return {String[]} Custom ordered list.
*/
function sortGroupsByOrder (groups, order) {
function sortGroupsByOrder(groups, order) {
const results = [];
order.forEach(sortKey => {
Object.keys(groups).forEach(name => {
if (groups[name].replace(/_/g, ' ') === sortKey) { results.push(name); }
if (groups[name].title.replace(/_/g, ' ') === sortKey) { results.push(name); }
});
});
// Append all other entries that are not defined in order
Expand Down

0 comments on commit 91dc7e2

Please sign in to comment.