JAVASCRIPT 32
Api.js Guest on 31st July 2020 12:54:59 PM
  1. var $hilighted,
  2.         $hilightedMenuItem,
  3.         optionDictionary = {},
  4.         names = [],
  5.         buildApiOffline,
  6.         offline = {},
  7.         API = {},
  8.     methods = [],
  9.         memberInfo = {},
  10.         usedUrls = [],
  11.         page = PAGE,
  12.         buildPage;
  13.  
  14. function loadScript(url, callback) {
  15.         //http://www.nczonline.net/blog/2009/07/28/the-best-way-to-load-external-javascript/
  16.         var script = document.createElement("script");
  17.         script.type = "text/javascript";
  18.         if (script.readyState){  //IE
  19.                 script.onreadystatechange = function(){
  20.                         if (script.readyState == "loaded" ||
  21.                                         script.readyState == "complete"){
  22.                                 script.onreadystatechange = null;
  23.                                 callback();
  24.                         }
  25.                 };
  26.         } else {  //Others
  27.                 script.onload = function() {
  28.                         callback();
  29.                 };
  30.         }
  31.  
  32.         script.src = url;
  33.         document.getElementsByTagName("head")[0].appendChild(script);
  34. }
  35.  
  36. function toDot (id){
  37.         return id.replace(/[-]+/g,'.');
  38. }
  39.  
  40. function escapeHTML(html) {
  41.         if (typeof html === 'string') {
  42.                 html = html
  43.                         .replace('\u25CF', '\\u25CF')
  44.                         .replace(/</g, '&lt;')
  45.                         .replace(/>/g, '&gt;');
  46.         }
  47.         return html;
  48. }
  49.  
  50. function escapeSelector (name) {
  51.         return name.replace('<', '\\<').replace('>', '\\>');
  52. }
  53.  
  54. function activateInternalLinks($parent) {
  55.         $('a[href^="#"]', $parent).each(function (i, anchor) {
  56.                 $(anchor).click(function (e) {
  57.                         memberClick(anchor.href.replace(/.*#/, ''), e);
  58.                         return false;
  59.                 });
  60.         });
  61. }
  62.  
  63.  
  64. /**
  65.  * Highligth a specific option by coloring it in the menu view and section view
  66.  */
  67. function hilight (id) {
  68.         var linkId, $el, $detailsWrap = $('#details-wrap');
  69.  
  70.         $el = $('div.member#' + escapeSelector(id));
  71.  
  72.         // clear old
  73.         if ($hilighted) {
  74.                 $hilighted.removeClass('hilighted');
  75.         }
  76.         if ($hilightedMenuItem) {
  77.                 $hilightedMenuItem.removeClass('hilighted');
  78.         }
  79.  
  80.         if ($el.length === 0) {
  81.                 $detailsWrap.scrollTop(0);
  82.         } else {
  83.                 // hilight new
  84.                 $hilighted = $el;
  85.                 $hilighted.addClass('hilighted');
  86.  
  87.                 // Scroll to the hilighted member
  88.                 $detailsWrap.animate({ scrollTop: $hilighted.offset().top + $detailsWrap.scrollTop() - 160 }, 400);
  89.  
  90.                 // Workaround for weird case where an element wont scroll under certain conditions
  91.                 // http://stackoverflow.com/questions/1830080/jquery-scrolltop-doesnt-seem-to-work-in-safari-or-chrome-windows#answer-4165094
  92.                 $('body, html, document').animate({ scrollTop: $hilighted.offset().top + $detailsWrap.scrollTop() - 160 }, 400);
  93.         }
  94.         linkId = id.replace(/[^a-z0-9<>\\]+/gi,'.');
  95.  
  96.         $hilightedMenuItem = $('a[href="/' + getBasePath() + linkId +'"]').not('.plus');
  97.         $hilightedMenuItem.addClass('hilighted');
  98.  
  99. }
  100.  
  101. /**
  102.  * Expand and load children when necessary of current level
  103.  */
  104. function toggleExpand($elem, callback) {
  105.         var $_menu = $elem.find('div[id$="-menu"]').first(),
  106.                 _id = $_menu.attr('id').replace("-menu",""),
  107.                 displayChildrenCallback = function () {
  108.  
  109.                         $('.dots', $elem).removeClass('loading');
  110.                         $elem.removeClass("collapsed");
  111.                         $elem.addClass("expanded");
  112.                         $_menu.slideDown();
  113.                         // show relevant section
  114.  
  115.                         if (/[A-Z]/.test(_id[0])) {
  116.                                 _id = 'object-' + _id;
  117.                         }
  118.                         toggleSection(_id);
  119.  
  120.                         if (callback) {
  121.                                 callback();
  122.                         }
  123.  
  124.                 };
  125.  
  126.  
  127.         if ($elem.hasClass('collapsed')) {
  128.  
  129.                 /* if not loaded, load children, standard we have three children */
  130.                 if ($_menu.children().size() == 1) {
  131.                         $('.dots', $elem).addClass('loading');
  132.                         loadChildren(_id, false, displayChildrenCallback);
  133.  
  134.                 } else {
  135.                         displayChildrenCallback();
  136.                 }
  137.         } else {
  138.                 // hide children
  139.                 $_menu.slideUp('normal',function(){
  140.                         $elem.removeClass("expanded");
  141.                         $elem.addClass("collapsed");
  142.                 });
  143.         }
  144. }
  145.  
  146. function toggleSection(sectionId) {
  147.         $section = $("#details > div.section:visible");
  148.  
  149.         // hide current section
  150.         if($section){
  151.                 $section.hide();
  152.         }
  153.         if (/[^\\]</.test(sectionId)) {
  154.                 sectionId = sectionId.replace('<', '\\<').replace('>', '\\>');
  155.         }
  156.         $('#details > div.section#' + sectionId).show();
  157. }
  158.  
  159. /**
  160.  * Makes a member name with dot-notation wrappable as html by splitting it at the dots and returning spans with text
  161.  *
  162.  * @param memberTitle - the dot-notation member title
  163.  */
  164. function wrappableMemberTitle(memberTitle) {
  165.         var parts = memberTitle.split('.'),
  166.                 wrappableMemberTitle = '',
  167.                 index;
  168.         for (index in parts) {
  169.                 wrappableMemberTitle += '<span>.' + parts[index] + '</span>';
  170.         }
  171.  
  172.         // Replace first dot
  173.         wrappableMemberTitle = wrappableMemberTitle.replace(/\./, '');
  174.  
  175.         return wrappableMemberTitle;
  176. }
  177.  
  178. function addSectionOption(val){
  179.         var title = val.fullname.replace('<', '&lt;').replace('>', '&gt;');
  180.         $section = $('<div class="section" id="' + val.name + '" style="display:none;"></div>').appendTo('#details');
  181.         $('<h1>' + wrappableMemberTitle(title) + '</h1>'
  182.         + (val.description ? '<div class="section-description">' + val.description + '</div>': '')
  183.         + (val.demo ? '<div class="demo section-demo"><h4>Try it:</h4> ' + val.demo + '</div>': '' )).appendTo($section);
  184.  
  185.         activateInternalLinks($section);
  186.         $(document).triggerHandler({ type:"xtra.btn.section.event",id: optionDictionary[val.fullname], table: 'option' });
  187. }
  188.  
  189. function addSectionObject(val){
  190.         var title = val.title;
  191.         $section = $('<div class="section" id="object-' + val.name + '" style="display:none;"></div>').appendTo('#details');
  192.         $('<h1>' + wrappableMemberTitle(title) + '</h1>').appendTo($section);
  193.         $('<div class="section-description">' + val.description + '</div>').appendTo($section);
  194.  
  195.         activateInternalLinks($section);
  196.         $(document).triggerHandler({ type:"xtra.btn.section.event",id: 'object-'+ val.name, table: 'object'});
  197. }
  198.  
  199. function markupReturnType(s) {
  200.         var basePath;
  201.         if (historyEnabled()) {
  202.                 basePath = '/' + getBasePath();
  203.         } else {
  204.                 basePath = '#';
  205.         }
  206.         s = s.replace(/[<>]/g, function (a) {
  207.                 return {
  208.                         '<': '&lt;',
  209.                         '>': '&gt;'
  210.                 }[a];
  211.         });
  212.         s = s.replace(/(Axis|Chart|Element|Highcharts|Point|Renderer|Series)/g, '<a href="' + basePath + '$1">$1</a>');
  213.         return s;
  214. }
  215.  
  216. /**
  217.  * Checks if the history API
  218.  * @returns {boolean}
  219.  */
  220. function historyEnabled() {
  221.         return runDB &&
  222.                 window.history !== undefined &&
  223.                 window.history !== null &&
  224.                 window.history.pushState !== undefined &&
  225.                 window.history.pushState !== null;
  226. }
  227.  
  228. /**
  229.  * Makes info about a member available at the memberInfo map for e.g. rich cards.
  230.  *
  231.  * @param memberObject - an object containing information about a member
  232.  */
  233. function storeMember(memberObject) {
  234.         // Add a pretty name with '()' if the member is a method
  235.         memberObject.prettyName = memberObject.fullname + (memberObject.type === 'method' ? '()' : '');
  236.  
  237.         // Add the member to the memberInfo map with the dot-notation name
  238.         memberInfo[memberObject.fullname] = memberObject;
  239. }
  240.  
  241. /**
  242.  * Creates a script element for the Google Rich Card and returns it as a jQuery object.
  243.  *
  244.  * @returns {*|jQuery|HTMLElement} the Google Rich Card script as a jQuery object
  245.  */
  246. function addRichCardScript() {
  247.         var script = document.createElement("script");
  248.  
  249.         script.id = "richCard";
  250.         script.type = "application/ld+json";
  251.  
  252.         document.getElementsByTagName("head")[0].appendChild(script);
  253.  
  254.         return $(script);
  255. }
  256.  
  257. /**
  258.  * Returns the memberInfo of a specific member, or an empty object if it does not exist.
  259.  *
  260.  * @param {string} member - the member id to get info from (dot-notation)
  261.  * @returns {object} the memberInfo of a specific member, or an empty object if it does not exist
  262.  */
  263. function getMemberInfo(member) {
  264.         return memberInfo[member] ? memberInfo[member] : {};
  265. }
  266.  
  267. /**
  268.  * Modifies or creates the Google Rich Card with information from the member.
  269.  *
  270.  * If the card does not exist, it is created via addRichCardScript().
  271.  *
  272.  * @param member - the id of the member (dot-notation)
  273.  */
  274. function modifyRichCard(member) {
  275.         var cardScript = $('#richCard'),
  276.                 json = {
  277.                         "@context": "http://schema.org/",
  278.                         "@type": "APIReference",
  279.                         "name": member,
  280.                         "image": "http://api.highcharts.com/resources/images/" + PRODUCTNAME + ".svg",
  281.                         "description": getMemberInfo(member).description
  282.                 };
  283.  
  284.         if (cardScript.length < 1) {
  285.                 cardScript = addRichCardScript();
  286.         }
  287.  
  288.         cardScript.html(JSON.stringify(json, null, 4));
  289. }
  290.  
  291. /**
  292.  * Updates the height of the nav and wrapper.
  293.  */
  294. function updateHeight() {
  295.         var $wrapper = $("#wrapper"),
  296.                 $wrapperContainer = $("#wrapper .container");
  297.         if (jQuery(window).width() >= 768) {
  298.                 // Disable
  299.                 var padding,
  300.                         height = $(window).height() - $('#top').height() - $('#footer').height();
  301.                 $wrapper.height(height);
  302.                 padding = $wrapperContainer.innerHeight() - $wrapperContainer.height();
  303.                 height = $wrapper.height() - padding;
  304.                 $("#wrapper-inner").height(height);
  305.                 $("#nav-wrap").height(height);
  306.                 $("#details-wrap").height(height);
  307.         } else {
  308.                 // no height defined on the element for mobile devices
  309.                 $('#nav-wrap').removeAttr('style');
  310.         }
  311. }
  312.  
  313. /**
  314.  * Updates links to other products and languages to contain the current member
  315.  * if it is available.
  316.  *
  317.  * @param member - the member in question (dot-notation)
  318.  */
  319. function updateMemberLinks(member) {
  320.         var $links = $('.update-page'),
  321.                 availableProducts = getMemberInfo(member).products || {},
  322.         availableProduct;
  323.         $links.each(function (i, link) {
  324.         link.href = link.href.substring(0, link.href.lastIndexOf('/')) + '/';
  325.                 for (i = 0; i < availableProducts.length; i++) {
  326.             availableProduct = availableProducts[i]
  327.             if (link.id.indexOf(availableProduct) >= 0) {
  328.                 link.href += member;
  329.                 break;
  330.             }
  331.                 }
  332.  
  333.         });
  334. }
  335.  
  336. /**
  337.  * Simulates a click on a link to a member by loading it with JS through gotoSection().
  338.  * If an event is provided, its preventDefault() is called, and history is rewritten
  339.  * with window.history.pushState().
  340.  *
  341.  * @param member - the id of a member, e.g. "exporting.chartOptions" (dot-notation)
  342.  * @param e - the click event
  343.  */
  344. function memberClick(member, e) {
  345.         var path = location.pathname,
  346.                 url;
  347.  
  348.         // Handle history only if there was an event.
  349.         // If not, this function was called by accessing
  350.         // the site or navigating the history.
  351.         if (e !== undefined) {
  352.                 // Prevents the page to be loaded from the server
  353.                 e.preventDefault();
  354.  
  355.                 // Remove trailing slash
  356.                 path = path.replace(/\/$/, '');
  357.  
  358.                 if (page.length < 1) {
  359.                         // Add member to url if there was no existing page
  360.                         url = path + '/' + member;
  361.                 } else {
  362.                         // Remove old member from path and add new member if there was a page
  363.                         url = path.substring(0, path.lastIndexOf('/')) + '/' + member;
  364.                 }
  365.  
  366.                 // Update page variable to member
  367.                 page = member.replace(/\//g, '');
  368.  
  369.                 if (historyEnabled()) {
  370.                         window.history.pushState({'page': page}, member, url);
  371.                 } else {
  372.                         window.location.hash = member;
  373.                 }
  374.  
  375.         }
  376.  
  377.         // Load content
  378.         gotoSection(member, true);
  379.  
  380.         // Lastly, update the height of the nav and wrapper
  381.         updateHeight();
  382. }
  383.  
  384. /**
  385.  * Checks if a string has a value.
  386.  * @param string - the string to check
  387.  * @returns {boolean} true if the string is neither undefined or empty
  388.  */
  389. function strHasValue(string) {
  390.         return string !== undefined && string.length > 0;
  391. }
  392.  
  393. /**
  394.  * Returns a the same string with capitalized first letter
  395.  * E.g. "highcharts" returns "Highcharts"
  396.  *
  397.  * @param {string} string - the string to capitalize
  398.  *
  399.  * @returns {string} a string with capitalized first letter
  400.  */
  401. function capitalizeFirstLetter(string) {
  402.     return string.charAt(0).toUpperCase() + string.slice(1);
  403. }
  404.  
  405. /**
  406.  * Get the path between domain name and member
  407.  * E.g. localhost:8080/highcharts-api/highcharts/data
  408.  *                                         |            base path               |
  409.  *
  410.  * @returns {string} the path between domain name and member
  411.  */
  412. function getBasePath() {
  413.         var ctxt = CTXT.replace('/', ''),
  414.                 prod = PRODUCTNAME + '/';
  415.         if (strHasValue(ctxt)) {
  416.                 ctxt += '/';
  417.         }
  418.         return ctxt + prod;
  419. }
  420.  
  421. /**
  422.  * Sets the first part of the document title to the member name, and returns it.
  423.  * E.g. "exporting.buttons.contextButton" sets
  424.  * "exporting.buttons.contextButton | Highcharts API Reference" as the document
  425.  * title.
  426.  *
  427.  * @param {string} memberName
  428.  *                      - name of the member, e.g.
  429.  *                      "exporting.buttons.contextButton" (dot-notation)
  430.  *
  431.  * @returns {string} the page title
  432.  */
  433. function memberToDocumentTitle(memberName) {
  434.         var title,
  435.                 prettyName = getMemberInfo(memberName).prettyName;
  436.  
  437.         title = prettyName + ' | ' + capitalizeFirstLetter(PRODUCTNAME) + ' API Reference';
  438.         if (prettyName !== undefined) {
  439.                 document.title = title;
  440.         }
  441.         return title;
  442. }
  443.  
  444. /**
  445.  * Sets the page content to the splash page
  446.  */
  447. function showSplashPage() {
  448.         var $splashPage = $('#splashText'),
  449.                 $plus = $('.plus');
  450.  
  451.         if($section){
  452.                 $section.hide();
  453.         }
  454.  
  455.         if ($plus.hasClass('expanded')) {
  456.                 $plus.removeClass('expanded');
  457.                 $plus.addClass('collapsed');
  458.                 $plus.find('div[id$="-menu"]').slideUp();
  459.         }
  460.  
  461.         $splashPage.show();
  462. }
  463.  
  464. function loadOptionMemberInSection(obj, isParent){
  465.         //add member to section in div#details
  466.         var $_section = $('div#' + obj.parent.replace('<', '\\<').replace('>', '\\>') + '.section'),
  467.                 $memberDiv,
  468.                 contextClass = obj.description && obj.description.indexOf('<p>') > -1 ? '' : ' context';
  469.  
  470.         $memberDiv = $('<div class="member" id="' + obj.name + '"><h2 class="title">' + obj.title + '</h2>'
  471.                         + (obj.returnType ? '<span class="returnType">: ' + markupReturnType(obj.returnType) + '</span>' : '')
  472.                         + (obj.deprecated ? '<div class="deprecated"><p>Deprecated</p></div>' : '' )
  473.                         + (obj.since ? '<div class="since">Since ' + obj.since + '</div>' : '' )
  474.                         + (obj.description ? '<div class="description">' + obj.description
  475.                                         + (obj.defaults ? ' Defaults to <code>' + escapeHTML(obj.defaults) + '</code>.'  : '')
  476.                                         + '</div>' : '')
  477.                         + (obj.context ? '<div class="description' + contextClass + '">The <code>this</code> keyword refers to the '+ markupReturnType(obj.context) +' object.</div>' : '')
  478.                         + (obj.demo ? '<div class="demo"><h4>Try it:</h4> ' + obj.demo + '</div>': '' )
  479.                         + (obj.seeAlso ? '<div class="see-also"><h4>See also:</h4> ' + obj.seeAlso + '</div>': '' )
  480.                         + '</div>').appendTo($_section);
  481.  
  482.         activateInternalLinks($memberDiv);
  483.  
  484.         $('div#' + escapeSelector(obj.name) + '.member h2.title').html(function() {
  485.                 var title = $.trim($(this).text());
  486.                 return $('<a href="/' + getBasePath() + obj.fullname + '" ' + (isParent ? '' : 'class="noChildren"') + '>' + title + '</a>').click(function(e){
  487.                         memberClick(obj.fullname, e);
  488.                 });
  489.         });
  490. }
  491.  
  492. function loadObjectMemberInSection(obj) {
  493.         $memberDiv = $('<div class="member" id="' + obj.name + '">'
  494.                         + '<h2 class="title">' + obj.title + '</h2> '
  495.                         + (obj.params ? '<span class="parameters">' + obj.params + '</span>' : '')
  496.                         + (obj.since ? '<div class="since">Since ' + obj.since + '</div>' : '' )
  497.                         + (obj.deprecated ? '<div class="deprecated"><p>Deprecated</p></div>' : '' )
  498.                         + '<div class="description"><p>' + obj.description +  '</p>'
  499.                         + (obj.paramsDescription ? '<h4>Parameters</h4><ul id="paramdesc"><li>' +
  500.                                         obj.paramsDescription.replace(/\|\|/g,'</li><li>') + '</li></ul>' : '')
  501.                         + (obj.returnType ? '<h4>Returns</h4><ul id="returns"><li>' + markupReturnType(obj.returnType) + '</li></ul>' : '')
  502.                         + '</div>'
  503.                         + (obj.demo ? '<div class="demo"><h4>Try it:</h4> ' + obj.demo + '</div>': '' )
  504.                         + '</div>').appendTo('div#object-' + obj.parent + '.section');
  505.  
  506.         $('div#' + escapeSelector(obj.name) + '.member h2.title').html(function() {
  507.                 var title = $.trim($(this).text());
  508.                 return $('<a href="/' + getBasePath() + obj.fullname + '" class="noChildren">' + title + '</a>').click(function(e){
  509.                         memberClick(obj.fullname, e);
  510.                 });
  511.         });
  512.         activateInternalLinks($memberDiv);
  513. }
  514.  
  515. function loadChildren(name, silent, callback) {
  516.  
  517.         var isObject = /[A-Z]/.test(name[0]),
  518.                 url = CTXT + '/' + (isObject ?
  519.                         'object/' + PRODUCTNAME + '-obj/child/' + name :
  520.                         'option/' + PRODUCTNAME + '/child/' + name);
  521.  
  522.         // If url has been used to load children before, do not load them again
  523.         if ($.inArray(url, usedUrls) !== -1) {
  524.                 return;
  525.         }
  526.         // Add the url to the list of used urls
  527.         usedUrls.push(url);
  528.  
  529.         $.ajax({
  530.                 type: "GET",
  531.                 url: url,
  532.                 dataType: "json",
  533.                 error: function () {
  534.                         var $menu;
  535.                         $menu = $('div#' + escapeSelector(name) + '-menu');
  536.                         $('.dots', $menu.parent()).removeClass('loading').addClass('error').html('Error');
  537.                 },
  538.                 success: function (data) {
  539.                         var display = 'block',
  540.                                 $menu, $menuItem;
  541.  
  542.                         if (silent) {
  543.                                 display = 'none';
  544.                         }
  545.  
  546.                         name = name.replace('<', '\\<').replace('>', '\\>');
  547.                         $menu = $('div#' + name + '-menu');
  548.  
  549.  
  550.                         $.each(data, function (key, val) {
  551.                                 var $div = $('<div></div>').appendTo($menu), $plus, $menuLink,
  552.                                         name,
  553.                                         title,
  554.                                         defaults,
  555.                                         cls;
  556.  
  557.                                 // Remove duplicate series<seriesType>.type-properties
  558.                                 if (/series<.+>--type/.test(val.name)) {
  559.                                         return true; // return true in $.each() is the same as continue loop
  560.                                 }
  561.  
  562.                                 // Make info available for e.g. rich cards
  563.                                 storeMember(val);
  564.  
  565.                                 /*if (val.type === 'method') {
  566.                                         name = val.name.replace('--', '.') + '()';
  567.                                 } else if (val.type === 'property') {
  568.                                         name = val.name.replace('--', '.');
  569.                                 } else {
  570.                                         name = val.fullname;
  571.                                 }*/
  572.                                 name = val.fullname;
  573.  
  574.                                 if (val.isParent) {
  575.                                         var preBracket = '{',
  576.                                                 postBracket = '}';
  577.  
  578.                                         if (val.returnType && val.returnType.indexOf('Array') === 0) {
  579.                                                 preBracket = '[{';
  580.                                                 postBracket = '}]';
  581.                                         }
  582.  
  583.  
  584.                                         $menuItem = $('<div class="menuitem collapsed"></div>');
  585.                                         $menuLink = $('<a href="/' + getBasePath() + name + '">' + val.title + '</a>').appendTo($menuItem);
  586.  
  587.                                         $menuLink.click(function (e) {
  588.                                                 memberClick(val.fullname, e);
  589.                                         });
  590.                                         $plus = $('<a href="/' + getBasePath() + name + '" class="plus"></a>').appendTo($menuItem);
  591.                                         $plus.click(function (e) {
  592.                                                 e.preventDefault();
  593.                                                 if ($plus.parent().hasClass('collapsed')) {
  594.                                                         $menuLink.click();
  595.                                                 } else {
  596.                                                         toggleExpand($plus.parent());
  597.                                                 }
  598.                                         });
  599.                                         $menuItem.append(':&nbsp;' + preBracket + '<span class="dots"><span>…</span></span>');
  600.                                         // add empty submenu
  601.                                         $('<div id="' + val.name + '-menu" style="display:none"><div>').appendTo($menuItem);
  602.                                         $menuItem.append(postBracket);
  603.                                         $menuItem.appendTo($menu);
  604.                                         addSectionOption(val);
  605.                                 } else {
  606.                                         if (val.type === 'method') {
  607.                                                 title = val.title + '()';
  608.                                                 methods.push(val.fullname);
  609.                                         } else {
  610.                                                 title = val.title;
  611.                                         }
  612.  
  613.                                         $menuLink = $('<a href="/' + getBasePath() + name + '">' + title + '</a>').appendTo($div);
  614.                                         $menuLink.click(function (e) {
  615.                                                 hideSidebar();
  616.                                                 memberClick(name, e);
  617.                                         });
  618.                                         if (val.type === 'method') {
  619.                                                 defaults = '[function]';
  620.                                         } else if (val.type === 'property') {
  621.                                                 defaults = '[' + val.returnType + ']';
  622.                                         } else if (val.defaults === 'null' || val.defaults === 'undefined' || val.defaults === '' || val.defaults === undefined) {
  623.                                                 defaults = val.defaults;
  624.                                         } else if (val.returnType === 'String' || val.returnType === 'Color') {
  625.                                                 defaults = '"' + val.defaults + '"';
  626.  
  627.                                         } else {
  628.                                                 defaults = val.defaults;
  629.                                         }
  630.  
  631.                                         if (val.returnType) {
  632.                                                 cls = val.returnType.toLowerCase();
  633.                                         } else {
  634.                                                 cls = '';
  635.                                                 console.warn('Missing returnType for ' + val.fullname);
  636.                                         }
  637.  
  638.  
  639.                                         $('<span class="value value-' + cls + '">: ' + escapeHTML(defaults) + '</span>').appendTo($div);
  640.                                 }
  641.                                 if (isObject) {
  642.                                         loadObjectMemberInSection(val);
  643.                                 } else {
  644.                                         loadOptionMemberInSection(val, val.isParent);
  645.                                 }
  646.                         });
  647.  
  648.                         $(document).triggerHandler({
  649.                                 type: "xtra.btn.member.event",
  650.                                 id: isObject ? 'object-' + name : name,
  651.                                 table: isObject ? 'object' : 'option'
  652.                         });
  653.  
  654.                         if (callback) {
  655.                                 callback();
  656.                         }
  657.                 }
  658.         });
  659. }
  660.  
  661. function gotoSection(anchor, hilighted) {
  662.  
  663.         var name,
  664.         levels,
  665.         $_parentparent,
  666.         callbackStack = [];
  667.  
  668.         // Handle typed parent item, like series<line>
  669.         name = anchor.split('.');
  670.         if (name.length > 1) {
  671.                 name[name.length - 1] = '-' + name[name.length - 1];
  672.         }
  673.         name = name.join('-');
  674.  
  675.         levels = name.split(/[-]{1,2}/);
  676.  
  677.         // Asyncronously expand parent elements of selected item
  678.         $.each(levels, function(i) {
  679.                 callbackStack.push(function () {
  680.                         var proceed = true,
  681.                                 level,
  682.                                 $_menu,
  683.                                 $_parent;
  684.  
  685.                         if (levels[i]) {
  686.                                 level = levels.slice(0, i + 1).join('-');
  687.  
  688.                                 if (level.indexOf('<') > -1) {
  689.                                         $_parentparent = $('#' + level.split('<')[0] + '-menu').parent();
  690.                                         level = escapeSelector(level);
  691.                                 }
  692.  
  693.                                 $_menu = $('#' + level + '-menu');
  694.                                 $_parent = $_menu.parent();
  695.  
  696.                                 if ($_menu && $_parent.hasClass('collapsed')) {
  697.  
  698.                                         if ($_parentparent && $_parentparent.hasClass('collapsed')) {
  699.                                                 toggleExpand($_parentparent);
  700.                                         }
  701.                                         // Do the toggle, and pass the next level as the callback argument
  702.                                         toggleExpand($_parent, callbackStack[i + 1]);
  703.                                         proceed = false;
  704.                                 }
  705.                         }
  706.  
  707.                         if (level) {
  708.                                 // For the last path item, show the section etc
  709.                                 if (/[A-Z]/.test(level[0])) {
  710.                                         level = 'object-' + level;
  711.                                 }
  712.                                 if ($('#details > div.section#' + level).length) {
  713.                                         toggleSection(level);
  714.  
  715.                                         // empty search
  716.                                         $("#search").val("");
  717.  
  718.                                 }
  719.                         }
  720.  
  721.                         if (proceed && callbackStack[i + 1]) {
  722.                                 callbackStack[i + 1]();
  723.                         }
  724.                 });
  725.         });
  726.  
  727.         // Hilighting is the last operation in the async stack
  728.         if (hilighted) {
  729.                 callbackStack.push(function () {
  730.                         if (strHasValue(name)) {
  731.                                 // Highlight if there was a member
  732.                                 // E.g. product#some.member
  733.                                 hilight(name);
  734.                                 // Update the Google Rich Card
  735.                                 modifyRichCard(anchor);
  736.                                 // Set the page title
  737.                                 memberToDocumentTitle(anchor);
  738.                 // Update the links with class 'update-page' to contain the member path
  739.                 updateMemberLinks(anchor);
  740.                         } else {
  741.                                 showSplashPage();
  742.                         }
  743.                 });
  744.         }
  745.  
  746.         // Start the recursive iteration
  747.         callbackStack[0]();
  748. }
  749.  
  750. /**
  751.  * Add the first level menu items on page load
  752.  */
  753. function addFirstLevelMenuItem(key, val, type) {
  754.  
  755.  
  756.         var $menuItem = $('<div class="menuitem collapsed"></div>').appendTo('#' + type + 's'),
  757.                 $plus, $menuLink,
  758.                 sectionId = val.fullname || val.name,
  759.                 title = escapeHTML(val.title),
  760.                 mainSection,
  761.                 name = val.name,
  762.                 recurseToType = false,
  763.                 menuItemPrefix = '',
  764.                 prefix = ': {',
  765.                 suffix = '}';
  766.  
  767.         // Make info available for e.g. rich cards
  768.         storeMember(val);
  769.  
  770.         if (val.returnType && val.returnType.indexOf('Array') === 0) {
  771.                 if (val.returnType === 'Array<Object>') {
  772.                         prefix = ': [{';
  773.                         suffix = '}]';
  774.                 } else {
  775.                         prefix = ': [';
  776.                         suffix = ']';
  777.                 }
  778.         }
  779.  
  780.         // Global options
  781.         if ($.inArray(val.name, ['global', 'lang']) !== -1) {
  782.                 $menuItem = $('<div class="menuitem collapsed"></div>').appendTo('#global-options');
  783.         }
  784.  
  785.  
  786.         // Handle the series<line> syntax
  787.         if (sectionId.indexOf('<') > -1) {
  788.                 mainSection = sectionId.split('<')[0];
  789.  
  790.                 // The first time we encounter a menu item on the syntax series<line>, add the series menu item
  791.                 if ($('#' + mainSection + '-menu').length === 0) {
  792.                         sectionId = title = name = mainSection;
  793.                         prefix = ': [';
  794.                         suffix = ']';
  795.                         recurseToType = true; // run this method again, but now for the { type: "line" } menu item
  796.                 } else {
  797.                         $menuItem.appendTo($('#' + mainSection + '-menu'));
  798.                         menuItemPrefix = '{<br class="typed"/>';
  799.                         title = '<span class="typed">type: "' + sectionId.split('<')[1].split('>')[0] + '"</span>';
  800.                         prefix = ', ';
  801.                 }
  802.  
  803.  
  804.         }
  805.  
  806.         if (menuItemPrefix) {
  807.                 $menuItem.append(menuItemPrefix);
  808.         }
  809.  
  810.         $menuLink = $('<a href="/' + getBasePath() + sectionId + '">' + title + '</a>')
  811.                 .appendTo($menuItem)
  812.                 .click(function(e){
  813.                         memberClick(sectionId, e);
  814.                         return false;
  815.                 });
  816.  
  817.         if (val.isParent) {
  818.                 $plus = $('<a href="/' + getBasePath() + sectionId + '" class="plus"></a>')
  819.                         .appendTo($menuItem)
  820.                         .click(function (e) {
  821.                                 e.preventDefault();
  822.                                 if ($plus.parent().hasClass('collapsed')) {
  823.                                         $menuLink.click();
  824.                                 } else {
  825.                                         toggleExpand($plus.parent());
  826.                                 }
  827.                         });
  828.         }
  829.  
  830.         $menuItem.append(prefix);
  831.  
  832.         $('<span class="dots"><span>…</span></span>').appendTo($menuItem);
  833.  
  834.         if(val.isParent) {
  835.                 $('<div id="' + name + '-menu" style="display:none"><div>').appendTo($menuItem);
  836.         }
  837.  
  838.         $menuItem.append(suffix);
  839.  
  840.  
  841.         // create sections in div#details
  842.         if (type === 'option') {
  843.                 addSectionOption(val);
  844.         } else {
  845.                 addSectionObject(val);
  846.         }
  847.  
  848.         if (recurseToType) {
  849.                 addFirstLevelMenuItem.apply(null, arguments);
  850.         }
  851. }
  852.  
  853. prepareOffline = function(callback) {
  854.  
  855.         offline = {highcharts: {}, highstock: {}, highmaps: {}};
  856.  
  857.         // now we have the data loaded we rewrite $.ajax for offline use
  858.         $.ajax = function(obj) {
  859.                 var result,
  860.                         splitted;
  861.  
  862.                 if (obj.url === '/' + PRODUCTNAME + '/names') {
  863.                         result = API[PRODUCTNAME].names;
  864.                 }
  865.  
  866.                 if (obj.url === '/option/'+ PRODUCTNAME + '/main') {
  867.                         result = API[PRODUCTNAME].main.option;
  868.                 }
  869.  
  870.                 if (obj.url === '/object/'+ PRODUCTNAME + '-obj/main') {
  871.                         result = API[PRODUCTNAME].main.object;
  872.                 }
  873.  
  874.                 splitted = obj.url.split('object/' + PRODUCTNAME + '-obj/child/');
  875.                 if (splitted.length > 1) {
  876.                         result = API[PRODUCTNAME].object[splitted[1]].children;
  877.                 }
  878.                 splitted = obj.url.split('option/' + PRODUCTNAME + '/child/');
  879.                 if (splitted.length > 1) {
  880.                         result = API[PRODUCTNAME].option[splitted[1]].children;
  881.                 }
  882.  
  883.                 // result to handler
  884.                 obj.success(result);
  885.         };
  886.  
  887.         callback();
  888. };
  889.  
  890. // build dictionary for offline use
  891. buildApiOffline = function(data, callback) {
  892.  
  893.         var option,
  894.                 names,
  895.                 type,
  896.                 i = 0;
  897.  
  898.         API[PRODUCTNAME] = { option: [], object: [], main: {}, names: [] };
  899.  
  900.         names = API[PRODUCTNAME].names;
  901.  
  902.         function fillWithType(type) {
  903.                 var idx,
  904.                         slot = API[PRODUCTNAME][type],
  905.                         main = API[PRODUCTNAME].main[type] = [],
  906.                         name;
  907.  
  908.                 // Loop over options in dump file
  909.                 for (idx = 0; idx < data[type].length; idx++) {
  910.                         option = data[type][idx];
  911.                         name = option.name;
  912.                         names.push(name);
  913.  
  914.                         if (option.isParent) {
  915.  
  916.                                 // Store main options separately
  917.                                 if (!/-/.test(name)) {
  918.                                         main.push(option);
  919.                                 }
  920.  
  921.                                 if (slot[name] == undefined) {
  922.                                         slot[name] = {details: option, children: []};
  923.                                 } else {
  924.                                         /* In case the parent option was already
  925.                                          * deducted from a child option
  926.                                          */
  927.                                         slot[name].details = option;
  928.                                 }
  929.                         }
  930.  
  931.                         // we have a child!
  932.                         if (slot.hasOwnProperty(option.parent)) {
  933.                                 slot[option.parent].children.push(option);
  934.                         } else {
  935.                                 slot[option.parent] = {details: null, children: [option]};
  936.                         }
  937.                 }
  938.         }
  939.  
  940.         while(i < 2) {
  941.                 type = ['option', 'object'][i];
  942.                 fillWithType(type);
  943.                 i++
  944.         }
  945.  
  946.         callback();
  947.  
  948. };
  949.  
  950. buildPage = function() {
  951.  
  952.         // autocomplete
  953.         $.ajax({
  954.                 type: "GET",
  955.                 url: CTXT + '/' + PRODUCTNAME + '/names',
  956.                 // Always load synchronously
  957.                 async: false,
  958.                 dataType: "json",
  959.                 success: function (data) {
  960.                         $.each(data, function (key, val) {
  961.                                
  962.                                 if (strHasValue(val)) {
  963.                                         var dotted = toDot(val);
  964.  
  965.                                         names.push(dotted);
  966.                                         optionDictionary[dotted] = val;
  967.                                 }
  968.                         });
  969.  
  970.                         $("#search" ).autocomplete({
  971.                                 source: names,
  972.                                 autoFocus: true,
  973.                                 minLength: 2,
  974.                                 select: function( event, ui ) {
  975.                                                 memberClick(ui.item.value, event);
  976.                                 },
  977.                                 position: {
  978.                                         my: 'left top',
  979.                                         of: '#search-wrap'
  980.                                 }
  981.                         });
  982.                 }
  983.         });
  984.  
  985.         // load main options and build folded menu tree
  986.         $.ajax({
  987.                 type: "GET",
  988.                 url: CTXT + '/option/' + PRODUCTNAME + '/main',
  989.                 // Always load synchronously
  990.                 async: false,
  991.                 dataType: "json",
  992.                 success: function (data) {
  993.                         $.each(data, function (key, val) {
  994.                                 addFirstLevelMenuItem(key, val, 'option');
  995.                         });
  996.                 }
  997.         });
  998.  
  999.         // load objects of product
  1000.         $.ajax({
  1001.                 type: "GET",
  1002.                 url: CTXT + '/object/' + PRODUCTNAME + '-obj/main',
  1003.                 // Always load synchronously
  1004.                 async: false,
  1005.                 dataType: "json",
  1006.                 success: function (data) {
  1007.                         $.each(data, function (key, val) {
  1008.                                 addFirstLevelMenuItem(key, val, 'object');
  1009.                         });
  1010.                         if (data.length < 1) {
  1011.                                 $('#objects-nav-section').hide();
  1012.                         }
  1013.                 },
  1014.                 /**
  1015.                  * Hides the Objects nav section if there were no objects found for the product
  1016.                  * @param jqXHR
  1017.                  * @param textStatus
  1018.                  * @param errorThrown
  1019.                  */
  1020.                 error: function (jqXHR, textStatus, errorThrown) {
  1021.                         console.error('Failed to retrieve objects for ' + PRODUCTNAME + '.', jqXHR, textStatus, errorThrown);
  1022.                         $('#objects-nav-section').hide();
  1023.                 }
  1024.         });
  1025.  
  1026.          // check url for anchor, remove also '()' from old links for object.method().
  1027.          anchor = window.location.hash.replace('#', '').replace('()','');
  1028.          if (strHasValue(anchor)) {
  1029.                 memberClick(anchor);
  1030.          }
  1031.  
  1032.         if (/\?object_not_found=true/.test(window.location.search)) {
  1033.                         dottedName = window.location.hash.split('#').pop();
  1034.                         internalName = optionDictionary[dottedName];
  1035.                         $('div#' + internalName).append('<div class="error">The object/option wasn\'t found in the database, maybe itÍ„\'s inherited??</div>');
  1036.         }
  1037.  
  1038.          // focus search
  1039.          $("#search")[0].focus();
  1040. };
  1041.  
  1042. /**
  1043.  * Checks if the sidebar is open based on the body class.
  1044.  *
  1045.  * @returns {boolean} true if the sidebar is open; false if not
  1046.  */
  1047. function sidebarIsOpen() {
  1048.         return $('body').hasClass('sidr-open');
  1049. }
  1050.  
  1051. /**
  1052.  * Hides the sidebar if it is open.
  1053.  */
  1054. function hideSidebar() {
  1055.         if (sidebarIsOpen()) {
  1056.                 $('#sidebar-nav-link').click();
  1057.         }
  1058. }
  1059.  
  1060. /**
  1061.  * Initializes the sidebar functionality.
  1062.  */
  1063. function initializeSidebar() {
  1064.         // Sidr sidebar activation
  1065.         $('.sidebar-nav-link').sidr({
  1066.                 name: 'nav',
  1067.                 displace: false
  1068.         });
  1069.  
  1070.         // Make clicking the page wrapper and nav links also collapse the sidebar
  1071.         $('#details-wrap').on('click', function () {
  1072.                 hideSidebar();
  1073.         });
  1074. }
  1075.  
  1076. /**
  1077.  * Initializes a dropdown with a given name prefix,
  1078.  * by setting the 'expanded' attribute on the dropdown link and list.
  1079.  *
  1080.  * The dropdown structure needs to contain a link and a list with
  1081.  * the same name prefix. Example:
  1082.  *
  1083.  *     <a id="[name]-link" expanded="false"></a>
  1084.  *     <ul id="[name]-list" expanded="false>
  1085.  *         ...
  1086.  *     </ul>
  1087.  *
  1088.  * @param name - the name of the dropdown
  1089.  */
  1090. function initializeDropdown(name) {
  1091.         var $list = $('#' + name +  '-list'),
  1092.                 $link = $('#' + name +  '-link');
  1093.         $link.on('click', function (e) {
  1094.                 e.preventDefault();
  1095.                 if ($link.attr('expanded') === 'true'){
  1096.                         $link.attr('expanded', false);
  1097.                         $list.attr('expanded', false);
  1098.                 } else {
  1099.                         $link.attr('expanded', true);
  1100.                         $list.attr('expanded', true);
  1101.                 }
  1102.         });
  1103.  
  1104.         $('#details-wrap').on('click', function () {
  1105.                 $link.attr('expanded', false);
  1106.                 $list.attr('expanded', false);
  1107.         });
  1108. }
  1109.  
  1110. /**
  1111.  * Adds simulation of history navigation by detecting changes to the history state.
  1112.  *
  1113.  * @return [undefined] - nothing
  1114.  */
  1115. function simulateHistory () {
  1116.  
  1117.         if (historyEnabled()) { // Use the history API if available
  1118.                 /**
  1119.                  * Updates the history with memberClick().
  1120.                  *
  1121.                  * If it is stored in the history state, the page will be used to update.
  1122.                  * If not, the global PAGE variable will be used.
  1123.                  *
  1124.                  * @param e - the event that triggered the history update
  1125.                  */
  1126.                 window.onpopstate = function (e) {
  1127.                         console.log('@updateHistory', PAGE, e);
  1128.                         if (e.state !== undefined && e.state !== null && e.state.page !== undefined) {
  1129.                                 memberClick(e.state.page);
  1130.                         } else {
  1131.                                 memberClick(PAGE);
  1132.                         }
  1133.                 }
  1134.         } else { // Use the #-notation if history API is not available
  1135.                 window.onhashchange = function (e) {
  1136.                         memberClick(window.location.hash.replace(/#/, ''));
  1137.                 }
  1138.         }
  1139. }
  1140.  
  1141. // Startup
  1142. $(function () {
  1143.         var hash = location.hash,
  1144.                 href,
  1145.                 url;
  1146.  
  1147.         // Fallback for old urls with # instead of /.
  1148.         // Replaces # with /
  1149.         if (strHasValue(hash)) {
  1150.                 page = hash.replace(/#/, '');
  1151.                 href = hash.replace(/#/, '/');
  1152.                 url = location.pathname + href;
  1153.                 if (historyEnabled()) {
  1154.                         window.history.replaceState({'page': page}, href, url);
  1155.                 } else {
  1156.                         PAGE = page;
  1157.                 }
  1158.         }
  1159.  
  1160.         // Initialize sidr sidebar
  1161.         initializeSidebar();
  1162.  
  1163.         // Initialize the programming language selector
  1164.         initializeDropdown('products');
  1165.         initializeDropdown('prog-lang-selector');
  1166.  
  1167.         if (runDB) {
  1168.                 buildPage();
  1169.         } else {
  1170.                 // prepare dump object
  1171.                 prepareOffline(function () {
  1172.                         // load offline data
  1173.                         loadScript('./js/' + PRODUCTNAME + '.json', function() {
  1174.                                 buildApiOffline(offline[PRODUCTNAME], buildPage);
  1175.                         });
  1176.                 });
  1177.                 // hide elements that don't make sence in offline mode
  1178.                 $('.hidden-offline').hide();
  1179.         }
  1180.  
  1181.         // convert hash from redirected dash syntax to new dot syntax
  1182.         if (/-/.test(location.hash)) {
  1183.                 location.hash = location.hash.replace(/(--|-)/g, '.');
  1184.         }
  1185.  
  1186.         // Add scrollanimation to button
  1187.         $("a[href='#top']").click(function() {
  1188.                 $("html, body").animate({ scrollTop: 0 }, "slow");
  1189.                 return false;
  1190.         });
  1191.  
  1192.         $(window).on('scroll', function() {
  1193.                 var button = $("#scrollTop");
  1194.                 if (!$("#top").isOnScreen()) {
  1195.                         if (button.css('display') == 'none') {
  1196.                                 button.fadeIn("slow");
  1197.                         }
  1198.                 } else {
  1199.                         if (button.css('display') == 'block') {
  1200.                                 button.fadeOut("slow");
  1201.                         }
  1202.                 }
  1203.         });
  1204.  
  1205.         $.fn.isOnScreen = function(){
  1206.                 var win = $(window),
  1207.                         viewport = {
  1208.                                 top : win.scrollTop(),
  1209.                                 left : win.scrollLeft()
  1210.                         };
  1211.  
  1212.                 viewport.right = viewport.left + win.width();
  1213.                 viewport.bottom = viewport.top + win.height();
  1214.  
  1215.                 var bounds = this.offset();
  1216.                 bounds.right = bounds.left + this.outerWidth();
  1217.                 bounds.bottom = bounds.top + this.outerHeight();
  1218.  
  1219.                 return (!(viewport.right < bounds.left || viewport.left > bounds.right || viewport.bottom < bounds.top || viewport.top > bounds.bottom));
  1220.  
  1221.         };
  1222.  
  1223.         updateHeight();
  1224.  
  1225.         $(window).resize(updateHeight);
  1226.  
  1227.         // Make the Highcharts/Highstock links dynamic
  1228.         $('#highstock-link, #highcharts-link').click(function () {
  1229.                 this.href += location.hash;
  1230.         });
  1231.  
  1232.         // Login shortcut (hot corner)
  1233.         $("<div>")
  1234.                 .css({
  1235.                         position: 'absolute',
  1236.                         display: 'block',
  1237.                         width: '10px',
  1238.                         height: '10px',
  1239.                         right: 0,
  1240.                         cursor: 'pointer'
  1241.                 })
  1242.                 .click(function () {
  1243.                         var ctxt = strHasValue(CTXT) ? CTXT.replace(/\//g, '') + '/' : '';
  1244.  
  1245.                         $('<iframe src="/'+ ctxt + 'auth/login">').dialog({
  1246.                                 height: 300
  1247.                         });
  1248.                 })
  1249.                 .prependTo('#top .container');
  1250.  
  1251.         // Call the custom simulateHistory() function to allow history navigation
  1252.         // with 'back' and 'forward'
  1253.     simulateHistory();
  1254.  
  1255.         if (strHasValue(page)) {
  1256.                 memberClick(page);
  1257.         }
  1258.  
  1259. });

Paste is for source code and general debugging text.

Login or Register to edit, delete and keep track of your pastes and more.

Raw Paste

Login or Register to edit or fork this paste. It's free.