Home | History | Annotate | Download | only in js
      1 
      2 /* Initialize some droiddoc stuff */
      3 $(document).ready(function() {
      4   
      5   // init available apis based on user pref
      6   changeApiLevel();
      7   initSidenavHeightResize()
      8 });
      9 
     10 var API_LEVEL_COOKIE = "api_level";
     11 var minLevel = 1;
     12 var maxLevel = 1;
     13 
     14 /******* SIDENAV DIMENSIONS ************/
     15 
     16   
     17   function initSidenavHeightResize() {
     18     // Change the drag bar size to nicely fit the scrollbar positions
     19     var $dragBar = $(".ui-resizable-s");
     20     $dragBar.css({'width': $dragBar.parent().width() - 5 + "px"});
     21     
     22     $( "#resize-packages-nav" ).resizable({ 
     23       containment: "#nav-panels",
     24       handles: "s",
     25       alsoResize: "#packages-nav",
     26       resize: function(event, ui) { resizeNav(); }, /* resize the nav while dragging */
     27       stop: function(event, ui) { saveNavPanels(); } /* once stopped, save the sizes to cookie  */
     28       });
     29           
     30   }
     31   
     32 function updateSidenavFixedWidth() {
     33   if (!navBarIsFixed) return;
     34   $('#devdoc-nav').css({
     35     'width' : $('#side-nav').css('width'),
     36     'margin' : $('#side-nav').css('margin')
     37   });
     38   $('#devdoc-nav a.totop').css({'display':'block','width':$("#nav").innerWidth()+'px'});
     39   
     40   initSidenavHeightResize();
     41 }
     42 
     43 function updateSidenavFullscreenWidth() {
     44   if (!navBarIsFixed) return;
     45   $('#devdoc-nav').css({
     46     'width' : $('#side-nav').css('width'),
     47     'margin' : $('#side-nav').css('margin')
     48   });
     49   $('#devdoc-nav .totop').css({'left': 'inherit'});
     50   
     51   initSidenavHeightResize();
     52 }
     53 
     54 function buildApiLevelSelector() {
     55   maxLevel = SINCE_DATA.length;
     56   var userApiLevel = parseInt(readCookie(API_LEVEL_COOKIE));
     57   userApiLevel = userApiLevel == 0 ? maxLevel : userApiLevel; // If there's no cookie (zero), use the max by default
     58 
     59   minLevel = parseInt($("#doc-api-level").attr("class"));
     60   // Handle provisional api levels; the provisional level will always be the highest possible level
     61   // Provisional api levels will also have a length; other stuff that's just missing a level won't,
     62   // so leave those kinds of entities at the default level of 1 (for example, the R.styleable class)
     63   if (isNaN(minLevel) && minLevel.length) {
     64     minLevel = maxLevel;
     65   }
     66   var select = $("#apiLevelSelector").html("").change(changeApiLevel);
     67   for (var i = maxLevel-1; i >= 0; i--) {
     68     var option = $("<option />").attr("value",""+SINCE_DATA[i]).append(""+SINCE_DATA[i]);
     69   //  if (SINCE_DATA[i] < minLevel) option.addClass("absent"); // always false for strings (codenames)
     70     select.append(option);
     71   }
     72 
     73   // get the DOM element and use setAttribute cuz IE6 fails when using jquery .attr('selected',true)
     74   var selectedLevelItem = $("#apiLevelSelector option[value='"+userApiLevel+"']").get(0);
     75   selectedLevelItem.setAttribute('selected',true);
     76 }
     77 
     78 function changeApiLevel() {
     79   maxLevel = SINCE_DATA.length;
     80   var selectedLevel = maxLevel;
     81 
     82   selectedLevel = parseInt($("#apiLevelSelector option:selected").val());
     83   toggleVisisbleApis(selectedLevel, "body");
     84 
     85   var date = new Date();
     86   date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years
     87   var expiration = date.toGMTString();
     88   writeCookie(API_LEVEL_COOKIE, selectedLevel, null, expiration);
     89 
     90   if (selectedLevel < minLevel) {
     91     var thing = ($("#jd-header").html().indexOf("package") != -1) ? "package" : "class";
     92     $("#naMessage").show().html("<div><p><strong>This " + thing + " is not available with API level " + selectedLevel + ".</strong></p>"
     93                               + "<p>To use this " + thing + ", you must develop your app using a build target "
     94                               + "that supports API level " + $("#doc-api-level").attr("class") + " or higher. To read these "
     95                               + "APIs, change the value of the API level filter above.</p>"
     96                               + "<p><a href='" +toRoot+ "guide/appendix/api-levels.html'>What is the API level?</a></p></div>");
     97   } else {
     98     $("#naMessage").hide();
     99   }
    100 }
    101 
    102 function toggleVisisbleApis(selectedLevel, context) {
    103   var apis = $(".api",context);
    104   apis.each(function(i) {
    105     var obj = $(this);
    106     var className = obj.attr("class");
    107     var apiLevelIndex = className.lastIndexOf("-")+1;
    108     var apiLevelEndIndex = className.indexOf(" ", apiLevelIndex);
    109     apiLevelEndIndex = apiLevelEndIndex != -1 ? apiLevelEndIndex : className.length;
    110     var apiLevel = className.substring(apiLevelIndex, apiLevelEndIndex);
    111     if (apiLevel.length == 0) { // for odd cases when the since data is actually missing, just bail
    112       return;
    113     }
    114     apiLevel = parseInt(apiLevel);
    115 
    116     // Handle provisional api levels; if this item's level is the provisional one, set it to the max
    117     var selectedLevelNum = parseInt(selectedLevel)
    118     var apiLevelNum = parseInt(apiLevel);
    119     if (isNaN(apiLevelNum)) {
    120         apiLevelNum = maxLevel;
    121     }
    122 
    123     // Grey things out that aren't available and give a tooltip title
    124     if (apiLevelNum > selectedLevelNum) {
    125       obj.addClass("absent").attr("title","Requires API Level \""
    126             + apiLevel + "\" or higher");
    127     } 
    128     else obj.removeClass("absent").removeAttr("title");
    129   });
    130 }
    131 
    132 
    133 
    134 
    135 
    136 
    137 
    138 
    139 
    140 
    141 /* NAVTREE */
    142 
    143 function new_node(me, mom, text, link, children_data, api_level)
    144 {
    145   var node = new Object();
    146   node.children = Array();
    147   node.children_data = children_data;
    148   node.depth = mom.depth + 1;
    149 
    150   node.li = document.createElement("li");
    151   mom.get_children_ul().appendChild(node.li);
    152 
    153   node.label_div = document.createElement("div");
    154   node.label_div.className = "label";
    155   if (api_level != null) {
    156     $(node.label_div).addClass("api");
    157     $(node.label_div).addClass("api-level-"+api_level);
    158   }
    159   node.li.appendChild(node.label_div);
    160 
    161   if (children_data != null) {
    162     node.expand_toggle = document.createElement("a");
    163     node.expand_toggle.href = "javascript:void(0)";
    164     node.expand_toggle.onclick = function() {
    165           if (node.expanded) {
    166             $(node.get_children_ul()).slideUp("fast");
    167             node.plus_img.src = me.toroot + "assets/images/triangle-closed-small.png";
    168             node.expanded = false;
    169           } else {
    170             expand_node(me, node);
    171           }
    172        };
    173     node.label_div.appendChild(node.expand_toggle);
    174 
    175     node.plus_img = document.createElement("img");
    176     node.plus_img.src = me.toroot + "assets/images/triangle-closed-small.png";
    177     node.plus_img.className = "plus";
    178     node.plus_img.width = "8";
    179     node.plus_img.border = "0";
    180     node.expand_toggle.appendChild(node.plus_img);
    181 
    182     node.expanded = false;
    183   }
    184 
    185   var a = document.createElement("a");
    186   node.label_div.appendChild(a);
    187   node.label = document.createTextNode(text);
    188   a.appendChild(node.label);
    189   if (link) {
    190     a.href = me.toroot + link;
    191   } else {
    192     if (children_data != null) {
    193       a.className = "nolink";
    194       a.href = "javascript:void(0)";
    195       a.onclick = node.expand_toggle.onclick;
    196       // This next line shouldn't be necessary.  I'll buy a beer for the first
    197       // person who figures out how to remove this line and have the link
    198       // toggle shut on the first try. --joeo (a] android.com
    199       node.expanded = false;
    200     }
    201   }
    202   
    203 
    204   node.children_ul = null;
    205   node.get_children_ul = function() {
    206       if (!node.children_ul) {
    207         node.children_ul = document.createElement("ul");
    208         node.children_ul.className = "children_ul";
    209         node.children_ul.style.display = "none";
    210         node.li.appendChild(node.children_ul);
    211       }
    212       return node.children_ul;
    213     };
    214 
    215   return node;
    216 }
    217 
    218 function expand_node(me, node)
    219 {
    220   if (node.children_data && !node.expanded) {
    221     if (node.children_visited) {
    222       $(node.get_children_ul()).slideDown("fast");
    223     } else {
    224       get_node(me, node);
    225       if ($(node.label_div).hasClass("absent")) {
    226         $(node.get_children_ul()).addClass("absent");
    227       } 
    228       $(node.get_children_ul()).slideDown("fast");
    229     }
    230     node.plus_img.src = me.toroot + "assets/images/triangle-opened-small.png";
    231     node.expanded = true;
    232 
    233     // perform api level toggling because new nodes are new to the DOM
    234     var selectedLevel = $("#apiLevelSelector option:selected").val();
    235     toggleVisisbleApis(selectedLevel, "#side-nav");
    236   }
    237 }
    238 
    239 function get_node(me, mom)
    240 {
    241   mom.children_visited = true;
    242   for (var i in mom.children_data) {
    243     var node_data = mom.children_data[i];
    244     mom.children[i] = new_node(me, mom, node_data[0], node_data[1],
    245         node_data[2], node_data[3]);
    246   }
    247 }
    248 
    249 function this_page_relative(toroot)
    250 {
    251   var full = document.location.pathname;
    252   var file = "";
    253   if (toroot.substr(0, 1) == "/") {
    254     if (full.substr(0, toroot.length) == toroot) {
    255       return full.substr(toroot.length);
    256     } else {
    257       // the file isn't under toroot.  Fail.
    258       return null;
    259     }
    260   } else {
    261     if (toroot != "./") {
    262       toroot = "./" + toroot;
    263     }
    264     do {
    265       if (toroot.substr(toroot.length-3, 3) == "../" || toroot == "./") {
    266         var pos = full.lastIndexOf("/");
    267         file = full.substr(pos) + file;
    268         full = full.substr(0, pos);
    269         toroot = toroot.substr(0, toroot.length-3);
    270       }
    271     } while (toroot != "" && toroot != "/");
    272     return file.substr(1);
    273   }
    274 }
    275 
    276 function find_page(url, data)
    277 {
    278   var nodes = data;
    279   var result = null;
    280   for (var i in nodes) {
    281     var d = nodes[i];
    282     if (d[1] == url) {
    283       return new Array(i);
    284     }
    285     else if (d[2] != null) {
    286       result = find_page(url, d[2]);
    287       if (result != null) {
    288         return (new Array(i).concat(result));
    289       }
    290     }
    291   }
    292   return null;
    293 }
    294 
    295 function load_navtree_data(toroot) {
    296   var navtreeData = document.createElement("script");
    297   navtreeData.setAttribute("type","text/javascript");
    298   navtreeData.setAttribute("src", toroot+"navtree_data.js");
    299   $("head").append($(navtreeData));
    300 }
    301 
    302 function init_default_navtree(toroot) {
    303   init_navtree("tree-list", toroot, NAVTREE_DATA);
    304   
    305   // perform api level toggling because because the whole tree is new to the DOM
    306   var selectedLevel = $("#apiLevelSelector option:selected").val();
    307   toggleVisisbleApis(selectedLevel, "#side-nav");
    308 }
    309 
    310 function init_navtree(navtree_id, toroot, root_nodes)
    311 {
    312   var me = new Object();
    313   me.toroot = toroot;
    314   me.node = new Object();
    315 
    316   me.node.li = document.getElementById(navtree_id);
    317   me.node.children_data = root_nodes;
    318   me.node.children = new Array();
    319   me.node.children_ul = document.createElement("ul");
    320   me.node.get_children_ul = function() { return me.node.children_ul; };
    321   //me.node.children_ul.className = "children_ul";
    322   me.node.li.appendChild(me.node.children_ul);
    323   me.node.depth = 0;
    324 
    325   get_node(me, me.node);
    326 
    327   me.this_page = this_page_relative(toroot);
    328   me.breadcrumbs = find_page(me.this_page, root_nodes);
    329   if (me.breadcrumbs != null && me.breadcrumbs.length != 0) {
    330     var mom = me.node;
    331     for (var i in me.breadcrumbs) {
    332       var j = me.breadcrumbs[i];
    333       mom = mom.children[j];
    334       expand_node(me, mom);
    335     }
    336     mom.label_div.className = mom.label_div.className + " selected";
    337     addLoadEvent(function() {
    338       scrollIntoView("nav-tree");
    339       });
    340   }
    341 }
    342 
    343 /* TOGGLE INHERITED MEMBERS */
    344 
    345 /* Toggle an inherited class (arrow toggle)
    346  * @param linkObj  The link that was clicked.
    347  * @param expand  'true' to ensure it's expanded. 'false' to ensure it's closed.
    348  *                'null' to simply toggle.
    349  */
    350 function toggleInherited(linkObj, expand) {
    351     var base = linkObj.getAttribute("id");
    352     var list = document.getElementById(base + "-list");
    353     var summary = document.getElementById(base + "-summary");
    354     var trigger = document.getElementById(base + "-trigger");
    355     var a = $(linkObj);
    356     if ( (expand == null && a.hasClass("closed")) || expand ) {
    357         list.style.display = "none";
    358         summary.style.display = "block";
    359         trigger.src = toRoot + "assets/images/triangle-opened.png";
    360         a.removeClass("closed");
    361         a.addClass("opened");
    362     } else if ( (expand == null && a.hasClass("opened")) || (expand == false) ) {
    363         list.style.display = "block";
    364         summary.style.display = "none";
    365         trigger.src = toRoot + "assets/images/triangle-closed.png";
    366         a.removeClass("opened");
    367         a.addClass("closed");
    368     }
    369     return false;
    370 }
    371 
    372 /* Toggle all inherited classes in a single table (e.g. all inherited methods)
    373  * @param linkObj  The link that was clicked.
    374  * @param expand  'true' to ensure it's expanded. 'false' to ensure it's closed.
    375  *                'null' to simply toggle.
    376  */
    377 function toggleAllInherited(linkObj, expand) {
    378   var a = $(linkObj);
    379   var table = $(a.parent().parent().parent()); // ugly way to get table/tbody
    380   var expandos = $(".jd-expando-trigger", table);
    381   if ( (expand == null && a.text() == "[Expand]") || expand ) {
    382     expandos.each(function(i) {
    383       toggleInherited(this, true);
    384     });
    385     a.text("[Collapse]");
    386   } else if ( (expand == null && a.text() == "[Collapse]") || (expand == false) ) {
    387     expandos.each(function(i) {
    388       toggleInherited(this, false);
    389     });
    390     a.text("[Expand]");
    391   }
    392   return false;
    393 }
    394 
    395 /* Toggle all inherited members in the class (link in the class title)
    396  */
    397 function toggleAllClassInherited() {
    398   var a = $("#toggleAllClassInherited"); // get toggle link from class title
    399   var toggles = $(".toggle-all", $("#body-content"));
    400   if (a.text() == "[Expand All]") {
    401     toggles.each(function(i) {
    402       toggleAllInherited(this, true);
    403     });
    404     a.text("[Collapse All]");
    405   } else {
    406     toggles.each(function(i) {
    407       toggleAllInherited(this, false);
    408     });
    409     a.text("[Expand All]");
    410   }
    411   return false;
    412 }
    413 
    414 /* Expand all inherited members in the class. Used when initiating page search */
    415 function ensureAllInheritedExpanded() {
    416   var toggles = $(".toggle-all", $("#body-content"));
    417   toggles.each(function(i) {
    418     toggleAllInherited(this, true);
    419   });
    420   $("#toggleAllClassInherited").text("[Collapse All]");
    421 }
    422 
    423 
    424 /* HANDLE KEY EVENTS
    425  * - Listen for Ctrl+F (Cmd on Mac) and expand all inherited members (to aid page search)
    426  */
    427 var agent = navigator['userAgent'].toLowerCase();
    428 var mac = agent.indexOf("macintosh") != -1;
    429 
    430 $(document).keydown( function(e) {
    431 var control = mac ? e.metaKey && !e.ctrlKey : e.ctrlKey; // get ctrl key
    432   if (control && e.which == 70) {  // 70 is "F"
    433     ensureAllInheritedExpanded();
    434   }
    435 });