main.js 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  1. require.config({
  2. paths: {
  3. bootstrap: './vendor/bootstrap.min',
  4. diffMatchPatch: './vendor/diff_match_patch.min',
  5. handlebars: './vendor/handlebars.min',
  6. handlebarsExtended: './utils/handlebars_helper',
  7. jquery: './vendor/jquery.min',
  8. locales: './locales/locale',
  9. lodash: './vendor/lodash.custom.min',
  10. pathToRegexp: './vendor/path-to-regexp/index',
  11. prettify: './vendor/prettify/prettify',
  12. semver: './vendor/semver.min',
  13. utilsSampleRequest: './utils/send_sample_request',
  14. webfontloader: './vendor/webfontloader',
  15. list: './vendor/list.min',
  16. apiData: './api_data',
  17. apiProject: './api_project',
  18. },
  19. shim: {
  20. bootstrap: {
  21. deps: ['jquery']
  22. },
  23. diffMatchPatch: {
  24. exports: 'diff_match_patch'
  25. },
  26. handlebars: {
  27. exports: 'Handlebars'
  28. },
  29. handlebarsExtended: {
  30. deps: ['jquery', 'handlebars'],
  31. exports: 'Handlebars'
  32. },
  33. prettify: {
  34. exports: 'prettyPrint'
  35. }
  36. },
  37. urlArgs: 'v=' + (new Date()).getTime(),
  38. waitSeconds: 15
  39. });
  40. require([
  41. 'jquery',
  42. 'lodash',
  43. 'locales',
  44. 'handlebarsExtended',
  45. 'apiProject',
  46. 'apiData',
  47. 'prettify',
  48. 'utilsSampleRequest',
  49. 'semver',
  50. 'webfontloader',
  51. 'bootstrap',
  52. 'pathToRegexp',
  53. 'list'
  54. ], function($, _, locale, Handlebars, apiProject, apiData, prettyPrint, sampleRequest, semver, WebFont) {
  55. // load google web fonts
  56. loadGoogleFontCss();
  57. var api = apiData.api;
  58. //
  59. // Templates
  60. //
  61. var templateHeader = Handlebars.compile( $('#template-header').html() );
  62. var templateFooter = Handlebars.compile( $('#template-footer').html() );
  63. var templateArticle = Handlebars.compile( $('#template-article').html() );
  64. var templateCompareArticle = Handlebars.compile( $('#template-compare-article').html() );
  65. var templateGenerator = Handlebars.compile( $('#template-generator').html() );
  66. var templateProject = Handlebars.compile( $('#template-project').html() );
  67. var templateSections = Handlebars.compile( $('#template-sections').html() );
  68. var templateSidenav = Handlebars.compile( $('#template-sidenav').html() );
  69. //
  70. // apiProject defaults
  71. //
  72. if ( ! apiProject.template)
  73. apiProject.template = {};
  74. if (apiProject.template.withCompare == null)
  75. apiProject.template.withCompare = true;
  76. if (apiProject.template.withGenerator == null)
  77. apiProject.template.withGenerator = true;
  78. if (apiProject.template.forceLanguage)
  79. locale.setLanguage(apiProject.template.forceLanguage);
  80. if (apiProject.template.aloneDisplay == null)
  81. apiProject.template.aloneDisplay = false;
  82. // Setup jQuery Ajax
  83. $.ajaxSetup(apiProject.template.jQueryAjaxSetup);
  84. //
  85. // Data transform
  86. //
  87. // grouped by group
  88. var apiByGroup = _.groupBy(api, function(entry) {
  89. return entry.group;
  90. });
  91. // grouped by group and name
  92. var apiByGroupAndName = {};
  93. $.each(apiByGroup, function(index, entries) {
  94. apiByGroupAndName[index] = _.groupBy(entries, function(entry) {
  95. return entry.name;
  96. });
  97. });
  98. //
  99. // sort api within a group by title ASC and custom order
  100. //
  101. var newList = [];
  102. var umlauts = { 'ä': 'ae', 'ü': 'ue', 'ö': 'oe', 'ß': 'ss' }; // TODO: remove in version 1.0
  103. $.each (apiByGroupAndName, function(index, groupEntries) {
  104. // get titles from the first entry of group[].name[] (name has versioning)
  105. var titles = [];
  106. $.each (groupEntries, function(titleName, entries) {
  107. var title = entries[0].title;
  108. if(title !== undefined) {
  109. title.toLowerCase().replace(/[äöüß]/g, function($0) { return umlauts[$0]; });
  110. titles.push(title + '#~#' + titleName); // '#~#' keep reference to titleName after sorting
  111. }
  112. });
  113. // sort by name ASC
  114. titles.sort();
  115. // custom order
  116. if (apiProject.order)
  117. titles = sortByOrder(titles, apiProject.order, '#~#');
  118. // add single elements to the new list
  119. titles.forEach(function(name) {
  120. var values = name.split('#~#');
  121. var key = values[1];
  122. groupEntries[key].forEach(function(entry) {
  123. newList.push(entry);
  124. });
  125. });
  126. });
  127. // api overwrite with ordered list
  128. api = newList;
  129. //
  130. // Group- and Versionlists
  131. //
  132. var apiGroups = {};
  133. var apiGroupTitles = {};
  134. var apiVersions = {};
  135. apiVersions[apiProject.version] = 1;
  136. $.each(api, function(index, entry) {
  137. apiGroups[entry.group] = 1;
  138. apiGroupTitles[entry.group] = entry.groupTitle || entry.group;
  139. apiVersions[entry.version] = 1;
  140. });
  141. // sort groups
  142. apiGroups = Object.keys(apiGroups);
  143. apiGroups.sort();
  144. // custom order
  145. if (apiProject.order)
  146. apiGroups = sortByOrder(apiGroups, apiProject.order);
  147. // sort versions DESC
  148. apiVersions = Object.keys(apiVersions);
  149. apiVersions.sort(semver.compare);
  150. apiVersions.reverse();
  151. //
  152. // create Navigationlist
  153. //
  154. var nav = [];
  155. apiGroups.forEach(function(group) {
  156. // Mainmenu entry
  157. nav.push({
  158. group: group,
  159. isHeader: true,
  160. title: apiGroupTitles[group]
  161. });
  162. // Submenu
  163. var oldName = '';
  164. api.forEach(function(entry) {
  165. if (entry.group === group) {
  166. if (oldName !== entry.name) {
  167. nav.push({
  168. title: entry.title,
  169. group: group,
  170. name: entry.name,
  171. type: entry.type,
  172. version: entry.version,
  173. url: entry.url
  174. });
  175. } else {
  176. nav.push({
  177. title: entry.title,
  178. group: group,
  179. hidden: true,
  180. name: entry.name,
  181. type: entry.type,
  182. version: entry.version,
  183. url: entry.url
  184. });
  185. }
  186. oldName = entry.name;
  187. }
  188. });
  189. });
  190. /**
  191. * Add navigation items by analyzing the HTML content and searching for h1 and h2 tags
  192. * @param nav Object the navigation array
  193. * @param content string the compiled HTML content
  194. * @param index where to insert items
  195. * @return boolean true if any good-looking (i.e. with a group identifier) <h1> tag was found
  196. */
  197. function add_nav(nav, content, index) {
  198. var found_level1 = false;
  199. if ( ! content) {
  200. return found_level1;
  201. }
  202. var topics = content.match(/<h(1|2).*?>(.+?)<\/h(1|2)>/gi);
  203. if ( topics ) {
  204. topics.forEach(function(entry) {
  205. var level = entry.substring(2,3);
  206. var title = entry.replace(/<.+?>/g, ''); // Remove all HTML tags for the title
  207. var entry_tags = entry.match(/id="api-([^\-]+)(?:-(.+))?"/); // Find the group and name in the id property
  208. var group = (entry_tags ? entry_tags[1] : null);
  209. var name = (entry_tags ? entry_tags[2] : null);
  210. if (level==1 && title && group) {
  211. nav.splice(index, 0, {
  212. group: group,
  213. isHeader: true,
  214. title: title,
  215. isFixed: true
  216. });
  217. index++;
  218. found_level1 = true;
  219. }
  220. if (level==2 && title && group && name) {
  221. nav.splice(index, 0, {
  222. group: group,
  223. name: name,
  224. isHeader: false,
  225. title: title,
  226. isFixed: false,
  227. version: '1.0'
  228. });
  229. index++;
  230. }
  231. });
  232. }
  233. return found_level1;
  234. }
  235. // Mainmenu Header entry
  236. if (apiProject.header) {
  237. var found_level1 = add_nav(nav, apiProject.header.content, 0); // Add level 1 and 2 titles
  238. if (!found_level1) { // If no Level 1 tags were found, make a title
  239. nav.unshift({
  240. group: '_',
  241. isHeader: true,
  242. title: (apiProject.header.title == null) ? locale.__('General') : apiProject.header.title,
  243. isFixed: true
  244. });
  245. }
  246. }
  247. // Mainmenu Footer entry
  248. if (apiProject.footer) {
  249. var last_nav_index = nav.length;
  250. var found_level1 = add_nav(nav, apiProject.footer.content, nav.length); // Add level 1 and 2 titles
  251. if (!found_level1 && apiProject.footer.title != null) { // If no Level 1 tags were found, make a title
  252. nav.splice(last_nav_index, 0, {
  253. group: '_footer',
  254. isHeader: true,
  255. title: apiProject.footer.title,
  256. isFixed: true
  257. });
  258. }
  259. }
  260. // render pagetitle
  261. var title = apiProject.title ? apiProject.title : 'apiDoc: ' + apiProject.name + ' - ' + apiProject.version;
  262. $(document).attr('title', title);
  263. // remove loader
  264. $('#loader').remove();
  265. // render sidenav
  266. var fields = {
  267. nav: nav
  268. };
  269. $('#sidenav').append( templateSidenav(fields) );
  270. // render Generator
  271. $('#generator').append( templateGenerator(apiProject) );
  272. // render Project
  273. _.extend(apiProject, { versions: apiVersions});
  274. $('#project').append( templateProject(apiProject) );
  275. // render apiDoc, header/footer documentation
  276. if (apiProject.header)
  277. $('#header').append( templateHeader(apiProject.header) );
  278. if (apiProject.footer)
  279. $('#footer').append( templateFooter(apiProject.footer) );
  280. //
  281. // Render Sections and Articles
  282. //
  283. var articleVersions = {};
  284. var content = '';
  285. apiGroups.forEach(function(groupEntry) {
  286. var articles = [];
  287. var oldName = '';
  288. var fields = {};
  289. var title = groupEntry;
  290. var description = '';
  291. articleVersions[groupEntry] = {};
  292. // render all articles of a group
  293. api.forEach(function(entry) {
  294. if(groupEntry === entry.group) {
  295. if (oldName !== entry.name) {
  296. // determine versions
  297. api.forEach(function(versionEntry) {
  298. if (groupEntry === versionEntry.group && entry.name === versionEntry.name) {
  299. if ( ! articleVersions[entry.group].hasOwnProperty(entry.name) ) {
  300. articleVersions[entry.group][entry.name] = [];
  301. }
  302. articleVersions[entry.group][entry.name].push(versionEntry.version);
  303. }
  304. });
  305. fields = {
  306. article: entry,
  307. versions: articleVersions[entry.group][entry.name]
  308. };
  309. } else {
  310. fields = {
  311. article: entry,
  312. hidden: true,
  313. versions: articleVersions[entry.group][entry.name]
  314. };
  315. }
  316. // add prefix URL for endpoint unless it's already absolute
  317. if (apiProject.url) {
  318. if (fields.article.url.substr(0, 4).toLowerCase() !== 'http') {
  319. fields.article.url = apiProject.url + fields.article.url;
  320. }
  321. }
  322. addArticleSettings(fields, entry);
  323. if (entry.groupTitle)
  324. title = entry.groupTitle;
  325. // TODO: make groupDescription compareable with older versions (not important for the moment)
  326. if (entry.groupDescription)
  327. description = entry.groupDescription;
  328. articles.push({
  329. article: templateArticle(fields),
  330. group: entry.group,
  331. name: entry.name,
  332. aloneDisplay: apiProject.template.aloneDisplay
  333. });
  334. oldName = entry.name;
  335. }
  336. });
  337. // render Section with Articles
  338. var fields = {
  339. group: groupEntry,
  340. title: title,
  341. description: description,
  342. articles: articles,
  343. aloneDisplay: apiProject.template.aloneDisplay
  344. };
  345. content += templateSections(fields);
  346. });
  347. $('#sections').append( content );
  348. // Bootstrap Scrollspy
  349. $(this).scrollspy({ target: '#scrollingNav', offset: 18 });
  350. // Content-Scroll on Navigation click.
  351. $('.sidenav').find('a').on('click', function(e) {
  352. e.preventDefault();
  353. var id = $(this).attr('href');
  354. if ($(id).length > 0)
  355. $('html,body').animate({ scrollTop: parseInt($(id).offset().top) }, 400);
  356. window.location.hash = $(this).attr('href');
  357. });
  358. // Quickjump on Pageload to hash position.
  359. if(window.location.hash) {
  360. var id = window.location.hash;
  361. if ($(id).length > 0)
  362. $('html,body').animate({ scrollTop: parseInt($(id).offset().top) }, 0);
  363. }
  364. /**
  365. * Check if Parameter (sub) List has a type Field.
  366. * Example: @apiSuccess varname1 No type.
  367. * @apiSuccess {String} varname2 With type.
  368. *
  369. * @param {Object} fields
  370. */
  371. function _hasTypeInFields(fields) {
  372. var result = false;
  373. $.each(fields, function(name) {
  374. result = result || _.some(fields[name], function(item) { return item.type; });
  375. });
  376. return result;
  377. }
  378. /**
  379. * On Template changes, recall plugins.
  380. */
  381. function initDynamic() {
  382. // Bootstrap popover
  383. $('button[data-toggle="popover"]').popover().click(function(e) {
  384. e.preventDefault();
  385. });
  386. var version = $('#version strong').html();
  387. $('#sidenav li').removeClass('is-new');
  388. if (apiProject.template.withCompare) {
  389. $('#sidenav li[data-version=\'' + version + '\']').each(function(){
  390. var group = $(this).data('group');
  391. var name = $(this).data('name');
  392. var length = $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\']').length;
  393. var index = $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\']').index($(this));
  394. if (length === 1 || index === (length - 1))
  395. $(this).addClass('is-new');
  396. });
  397. }
  398. // tabs
  399. $('.nav-tabs-examples a').click(function (e) {
  400. e.preventDefault();
  401. $(this).tab('show');
  402. });
  403. $('.nav-tabs-examples').find('a:first').tab('show');
  404. // sample header-content-type switch
  405. $('.sample-header-content-type-switch').change(function () {
  406. var paramName = '.' + $(this).attr('name') + '-fields';
  407. var bodyName = '.' + $(this).attr('name') + '-body';
  408. var selectName = 'select[name=' + $(this).attr('name') + ']';
  409. if ($(this).val() == 'body-json') {
  410. $(selectName).val('undefined');
  411. $(this).val('body-json');
  412. $(paramName).removeClass('hide');
  413. $(this).parent().nextAll(paramName).first().addClass('hide');
  414. $(bodyName).addClass('hide');
  415. $(this).parent().nextAll(bodyName).first().removeClass('hide');
  416. } else if ($(this).val() == "body-form-data") {
  417. $(selectName).val('undefined');
  418. $(this).val('body-form-data');
  419. $(bodyName).addClass('hide');
  420. $(paramName).removeClass('hide');
  421. } else {
  422. $(this).parent().nextAll(paramName).first().removeClass('hide')
  423. $(this).parent().nextAll(bodyName).first().addClass('hide');
  424. }
  425. $(this).prev('.sample-request-switch').prop('checked', true);
  426. });
  427. // sample request switch
  428. $('.sample-request-switch').click(function (e) {
  429. var paramName = '.' + $(this).attr('name') + '-fields';
  430. var bodyName = '.' + $(this).attr('name') + '-body';
  431. var select = $(this).next('.' + $(this).attr('name') + '-select').val();
  432. if($(this).prop("checked")){
  433. if (select == 'body-json'){
  434. $(this).parent().nextAll(bodyName).first().removeClass('hide');
  435. }else {
  436. $(this).parent().nextAll(paramName).first().removeClass('hide');
  437. }
  438. }else {
  439. if (select == 'body-json'){
  440. $(this).parent().nextAll(bodyName).first().addClass('hide');
  441. }else {
  442. $(this).parent().nextAll(paramName).first().addClass('hide');
  443. }
  444. }
  445. });
  446. if (apiProject.template.aloneDisplay){
  447. //show group
  448. $('.show-group').click(function () {
  449. var apiGroup = '.' + $(this).attr('data-group') + '-group';
  450. var apiGroupArticle = '.' + $(this).attr('data-group') + '-article';
  451. $(".show-api-group").addClass('hide');
  452. $(apiGroup).removeClass('hide');
  453. $(".show-api-article").addClass('hide');
  454. $(apiGroupArticle).removeClass('hide');
  455. });
  456. //show api
  457. $('.show-api').click(function () {
  458. var apiName = '.' + $(this).attr('data-name') + '-article';
  459. var apiGroup = '.' + $(this).attr('data-group') + '-group';
  460. $(".show-api-group").addClass('hide');
  461. $(apiGroup).removeClass('hide');
  462. $(".show-api-article").addClass('hide');
  463. $(apiName).removeClass('hide');
  464. });
  465. }
  466. // call scrollspy refresh method
  467. $(window).scrollspy('refresh');
  468. // init modules
  469. sampleRequest.initDynamic();
  470. }
  471. initDynamic();
  472. if (apiProject.template.aloneDisplay) {
  473. var hashVal = window.location.hash;
  474. if (hashVal != null && hashVal.length !== 0) {
  475. $("." + hashVal.slice(1) + "-init").click();
  476. }
  477. }
  478. // Pre- / Code-Format
  479. prettyPrint();
  480. //
  481. // HTML-Template specific jQuery-Functions
  482. //
  483. // Change Main Version
  484. function setMainVersion(selectedVersion) {
  485. if (typeof(selectedVersion) === 'undefined') {
  486. selectedVersion = $('#version strong').html();
  487. }
  488. else {
  489. $('#version strong').html(selectedVersion);
  490. }
  491. // hide all
  492. $('article').addClass('hide');
  493. $('#sidenav li:not(.nav-fixed)').addClass('hide');
  494. // show 1st equal or lower Version of each entry
  495. $('article[data-version]').each(function(index) {
  496. var group = $(this).data('group');
  497. var name = $(this).data('name');
  498. var version = $(this).data('version');
  499. if (semver.lte(version, selectedVersion)) {
  500. if ($('article[data-group=\'' + group + '\'][data-name=\'' + name + '\']:visible').length === 0) {
  501. // enable Article
  502. $('article[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + version + '\']').removeClass('hide');
  503. // enable Navigation
  504. $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + version + '\']').removeClass('hide');
  505. $('#sidenav li.nav-header[data-group=\'' + group + '\']').removeClass('hide');
  506. }
  507. }
  508. });
  509. // show 1st equal or lower Version of each entry
  510. $('article[data-version]').each(function(index) {
  511. var group = $(this).data('group');
  512. $('section#api-' + group).removeClass('hide');
  513. if ($('section#api-' + group + ' article:visible').length === 0) {
  514. $('section#api-' + group).addClass('hide');
  515. } else {
  516. $('section#api-' + group).removeClass('hide');
  517. }
  518. });
  519. initDynamic();
  520. return;
  521. }
  522. setMainVersion();
  523. $('#versions li.version a').on('click', function(e) {
  524. e.preventDefault();
  525. setMainVersion($(this).html());
  526. });
  527. // compare all article with their predecessor
  528. $('#compareAllWithPredecessor').on('click', changeAllVersionCompareTo);
  529. // change version of an article
  530. $('article .versions li.version a').on('click', changeVersionCompareTo);
  531. // compare url-parameter
  532. $.urlParam = function(name) {
  533. var results = new RegExp('[\\?&amp;]' + name + '=([^&amp;#]*)').exec(window.location.href);
  534. return (results && results[1]) ? results[1] : null;
  535. };
  536. if ($.urlParam('compare')) {
  537. // URL Paramter ?compare=1 is set
  538. $('#compareAllWithPredecessor').trigger('click');
  539. if (window.location.hash) {
  540. var id = window.location.hash;
  541. $('html,body').animate({ scrollTop: parseInt($(id).offset().top) - 18 }, 0);
  542. }
  543. }
  544. /**
  545. * Initialize search
  546. */
  547. var options = {
  548. valueNames: [ 'nav-list-item','nav-list-url-item']
  549. };
  550. var endpointsList = new List('scrollingNav', options);
  551. /**
  552. * Set initial focus to search input
  553. */
  554. $('#scrollingNav .sidenav-search input.search').focus();
  555. /**
  556. * Detect ESC key to reset search
  557. */
  558. $(document).keyup(function(e) {
  559. if (e.keyCode === 27) $('span.search-reset').click();
  560. });
  561. /**
  562. * Search reset
  563. */
  564. $('span.search-reset').on('click', function() {
  565. $('#scrollingNav .sidenav-search input.search')
  566. .val("")
  567. .focus()
  568. ;
  569. endpointsList.search();
  570. });
  571. /**
  572. * Change version of an article to compare it to an other version.
  573. */
  574. function changeVersionCompareTo(e) {
  575. e.preventDefault();
  576. var $root = $(this).parents('article');
  577. var selectedVersion = $(this).html();
  578. var $button = $root.find('.version');
  579. var currentVersion = $button.find('strong').html();
  580. $button.find('strong').html(selectedVersion);
  581. var group = $root.data('group');
  582. var name = $root.data('name');
  583. var version = $root.data('version');
  584. var compareVersion = $root.data('compare-version');
  585. if (compareVersion === selectedVersion)
  586. return;
  587. if ( ! compareVersion && version == selectedVersion)
  588. return;
  589. if (compareVersion && articleVersions[group][name][0] === selectedVersion || version === selectedVersion) {
  590. // the version of the entry is set to the highest version (reset)
  591. resetArticle(group, name, version);
  592. } else {
  593. var $compareToArticle = $('article[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + selectedVersion + '\']');
  594. var sourceEntry = {};
  595. var compareEntry = {};
  596. $.each(apiByGroupAndName[group][name], function(index, entry) {
  597. if (entry.version === version)
  598. sourceEntry = entry;
  599. if (entry.version === selectedVersion)
  600. compareEntry = entry;
  601. });
  602. var fields = {
  603. article: sourceEntry,
  604. compare: compareEntry,
  605. versions: articleVersions[group][name]
  606. };
  607. // add unique id
  608. // TODO: replace all group-name-version in template with id.
  609. fields.article.id = fields.article.group + '-' + fields.article.name + '-' + fields.article.version;
  610. fields.article.id = fields.article.id.replace(/\./g, '_');
  611. fields.compare.id = fields.compare.group + '-' + fields.compare.name + '-' + fields.compare.version;
  612. fields.compare.id = fields.compare.id.replace(/\./g, '_');
  613. var entry = sourceEntry;
  614. if (entry.parameter && entry.parameter.fields)
  615. fields._hasTypeInParameterFields = _hasTypeInFields(entry.parameter.fields);
  616. if (entry.error && entry.error.fields)
  617. fields._hasTypeInErrorFields = _hasTypeInFields(entry.error.fields);
  618. if (entry.success && entry.success.fields)
  619. fields._hasTypeInSuccessFields = _hasTypeInFields(entry.success.fields);
  620. if (entry.info && entry.info.fields)
  621. fields._hasTypeInInfoFields = _hasTypeInFields(entry.info.fields);
  622. var entry = compareEntry;
  623. if (fields._hasTypeInParameterFields !== true && entry.parameter && entry.parameter.fields)
  624. fields._hasTypeInParameterFields = _hasTypeInFields(entry.parameter.fields);
  625. if (fields._hasTypeInErrorFields !== true && entry.error && entry.error.fields)
  626. fields._hasTypeInErrorFields = _hasTypeInFields(entry.error.fields);
  627. if (fields._hasTypeInSuccessFields !== true && entry.success && entry.success.fields)
  628. fields._hasTypeInSuccessFields = _hasTypeInFields(entry.success.fields);
  629. if (fields._hasTypeInInfoFields !== true && entry.info && entry.info.fields)
  630. fields._hasTypeInInfoFields = _hasTypeInFields(entry.info.fields);
  631. var content = templateCompareArticle(fields);
  632. $root.after(content);
  633. var $content = $root.next();
  634. // Event on.click re-assign
  635. $content.find('.versions li.version a').on('click', changeVersionCompareTo);
  636. // select navigation
  637. $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + currentVersion + '\']').addClass('has-modifications');
  638. $root.remove();
  639. // TODO: on change main version or select the highest version re-render
  640. }
  641. initDynamic();
  642. }
  643. /**
  644. * Compare all currently selected Versions with their predecessor.
  645. */
  646. function changeAllVersionCompareTo(e) {
  647. e.preventDefault();
  648. $('article:visible .versions').each(function(){
  649. var $root = $(this).parents('article');
  650. var currentVersion = $root.data('version');
  651. var $foundElement = null;
  652. $(this).find('li.version a').each(function() {
  653. var selectVersion = $(this).html();
  654. if (selectVersion < currentVersion && ! $foundElement)
  655. $foundElement = $(this);
  656. });
  657. if($foundElement)
  658. $foundElement.trigger('click');
  659. });
  660. initDynamic();
  661. }
  662. /**
  663. * Sort the fields.
  664. */
  665. function sortFields(fields_object) {
  666. $.each(fields_object, function (key, fields) {
  667. var reversed = fields.slice().reverse()
  668. var max_dot_count = Math.max.apply(null, reversed.map(function (item) {
  669. return item.field.split(".").length - 1;
  670. }))
  671. for (var dot_count = 1; dot_count <= max_dot_count; dot_count++) {
  672. reversed.forEach(function (item, index) {
  673. var parts = item.field.split(".");
  674. if (parts.length - 1 == dot_count) {
  675. var fields_names = fields.map(function (item) { return item.field; });
  676. if (parts.slice(1).length >= 1) {
  677. var prefix = parts.slice(0, parts.length - 1).join(".");
  678. var prefix_index = fields_names.indexOf(prefix);
  679. if (prefix_index > -1) {
  680. fields.splice(fields_names.indexOf(item.field), 1);
  681. fields.splice(prefix_index + 1, 0, item);
  682. }
  683. }
  684. }
  685. });
  686. }
  687. });
  688. }
  689. /**
  690. * Add article settings.
  691. */
  692. function addArticleSettings(fields, entry) {
  693. // add unique id
  694. // TODO: replace all group-name-version in template with id.
  695. fields.id = fields.article.group + '-' + fields.article.name + '-' + fields.article.version;
  696. fields.id = fields.id.replace(/\./g, '_');
  697. if (entry.header && entry.header.fields) {
  698. sortFields(entry.header.fields);
  699. fields._hasTypeInHeaderFields = _hasTypeInFields(entry.header.fields);
  700. }
  701. if (entry.parameter && entry.parameter.fields) {
  702. sortFields(entry.parameter.fields);
  703. fields._hasTypeInParameterFields = _hasTypeInFields(entry.parameter.fields);
  704. }
  705. if (entry.error && entry.error.fields) {
  706. sortFields(entry.error.fields);
  707. fields._hasTypeInErrorFields = _hasTypeInFields(entry.error.fields);
  708. }
  709. if (entry.success && entry.success.fields) {
  710. sortFields(entry.success.fields);
  711. fields._hasTypeInSuccessFields = _hasTypeInFields(entry.success.fields);
  712. }
  713. if (entry.info && entry.info.fields) {
  714. sortFields(entry.info.fields);
  715. fields._hasTypeInInfoFields = _hasTypeInFields(entry.info.fields);
  716. }
  717. // add template settings
  718. fields.template = apiProject.template;
  719. }
  720. /**
  721. * Render Article.
  722. */
  723. function renderArticle(group, name, version) {
  724. var entry = {};
  725. $.each(apiByGroupAndName[group][name], function(index, currentEntry) {
  726. if (currentEntry.version === version)
  727. entry = currentEntry;
  728. });
  729. var fields = {
  730. article: entry,
  731. versions: articleVersions[group][name]
  732. };
  733. addArticleSettings(fields, entry);
  734. return templateArticle(fields);
  735. }
  736. /**
  737. * Render original Article and remove the current visible Article.
  738. */
  739. function resetArticle(group, name, version) {
  740. var $root = $('article[data-group=\'' + group + '\'][data-name=\'' + name + '\']:visible');
  741. var content = renderArticle(group, name, version);
  742. $root.after(content);
  743. var $content = $root.next();
  744. // Event on.click needs to be reassigned (should actually work with on ... automatically)
  745. $content.find('.versions li.version a').on('click', changeVersionCompareTo);
  746. $('#sidenav li[data-group=\'' + group + '\'][data-name=\'' + name + '\'][data-version=\'' + version + '\']').removeClass('has-modifications');
  747. $root.remove();
  748. return;
  749. }
  750. /**
  751. * Load google fonts.
  752. */
  753. function loadGoogleFontCss() {
  754. WebFont.load({
  755. active: function() {
  756. // Update scrollspy
  757. $(window).scrollspy('refresh')
  758. },
  759. google: {
  760. families: ['Source Code Pro', 'Source Sans Pro:n4,n6,n7']
  761. }
  762. });
  763. }
  764. /**
  765. * Return ordered entries by custom order and append not defined entries to the end.
  766. * @param {String[]} elements
  767. * @param {String[]} order
  768. * @param {String} splitBy
  769. * @return {String[]} Custom ordered list.
  770. */
  771. function sortByOrder(elements, order, splitBy) {
  772. var results = [];
  773. order.forEach (function(name) {
  774. if (splitBy)
  775. elements.forEach (function(element) {
  776. var parts = element.split(splitBy);
  777. var key = parts[0]; // reference keep for sorting
  778. if (key == name || parts[1] == name)
  779. results.push(element);
  780. });
  781. else
  782. elements.forEach (function(key) {
  783. if (key == name)
  784. results.push(name);
  785. });
  786. });
  787. // Append all other entries that ar not defined in order
  788. elements.forEach(function(element) {
  789. if (results.indexOf(element) === -1)
  790. results.push(element);
  791. });
  792. return results;
  793. }
  794. });