main.js 33 KB

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