yuidoc-bootstrap.js (9270B)
1 /* global $:true */ 2 $(function() { 3 'use strict'; 4 5 // ************************************************************************* // 6 // HTML templates 7 // ************************************************************************* // 8 9 // (None) 10 11 12 // ************************************************************************* // 13 // Functions 14 // ************************************************************************* // 15 16 function setUpActiveTab() { 17 if(localStorage.getItem('main-nav')){ 18 $('a[href="'+ localStorage['main-nav'] + '"]').tab('show'); 19 } 20 } 21 22 function setUpOptionsCheckboxes() { 23 if(localStorage.getItem('options')){ 24 var optionsArr = JSON.parse(localStorage.options), 25 optionsForm = $('#options-form'); 26 27 for(var i=0;i<optionsArr.length;i++){ 28 var box = optionsForm.find('input:checkbox').eq(i); 29 box.prop('checked', optionsArr[i]); 30 setOptionDisplayState(box); 31 } 32 } 33 } 34 35 function setUpWidgets() { 36 var sideSource = [], navbarSource = [], sidebarSearch, navbarSearch; 37 38 $('#sidebar .tab-pane.active li a').each(function(index, elem) { 39 sideSource.push($(elem).text()); 40 }); 41 sidebarSearch = $('#sidebar input[type="search"]'); 42 sidebarSearch.typeahead({ 43 source: sideSource, 44 updater : function(item) { 45 $('#sidebar .tab-pane.active a:contains(' + item + ')')[0].click(); 46 return item; 47 } 48 }); 49 50 $('#sidebar .tab-pane li a').each(function(index, elem) { 51 var $el = $(elem), 52 type = $el.parents('.tab-pane').is('#classes') ? 'classes/' : 'modules/'; 53 navbarSource.push(type + $el.text()); 54 }); 55 navbarSearch = $('.navbar input'); 56 navbarSearch.typeahead({ 57 source : navbarSource, 58 updater : function(item) { 59 var type = item.split('/')[0], name = item.split('/')[1], 60 $parent = $('#sidebar .tab-pane#' + type); 61 $parent.find('a:contains(' + name + ')')[0].click(); 62 return item; 63 } 64 }); 65 } 66 67 function setOptionDisplayState(box) { 68 var cssName = $.trim(box.parent('label').text()).toLowerCase(); 69 if(box.is(':checked')){ 70 $('div.'+cssName).css('display', 'block'); 71 $('li.'+cssName).css('display', 'block'); 72 $('span.'+cssName).css('display', 'inline'); 73 }else{ 74 $('.'+cssName).css('display', 'none'); 75 } 76 } 77 78 function scrollToAnchor($anchor) { 79 var navbarHeight = $('.navbar-fixed-top').outerHeight(true); 80 $(document).scrollTop( $anchor.offset().top - navbarHeight); 81 } 82 83 $('[data-toggle=tab]').on('click', function (event, extraArgs) { 84 // Why? If responding to the click of a link or hashchange already, we really 85 // don't want to change window hash 86 if (extraArgs && extraArgs.ignore === true) { 87 return; 88 } 89 window.location.hash = $(this).attr('href'); 90 }); 91 92 $('[data-tabid]').on('click', function(event) { 93 var tabToActivate = $(this).attr('data-tabid'), 94 anchor = $(this).attr('data-anchor'); 95 event.preventDefault(); 96 97 $('[data-toggle=tab][href="'+ tabToActivate + '"]').click(); 98 // ...huh? http://stackoverflow.com/a/9930611 99 // otherwise, can't select an element by ID if the ID has a '.' in it 100 var scrollAnchor = anchor.replace(/\./g, '\\.'); 101 scrollToAnchor($(scrollAnchor)); 102 window.location.hash = anchor; 103 }); 104 105 function moveToWindowHash() { 106 var hash = window.location.hash, 107 tabToActivate = hash, 108 $tabToActivate = false, 109 $scroll = $(hash); 110 111 if (!hash) { 112 return; 113 } 114 115 if (hash.match(/^#method_/)) { 116 tabToActivate = '#methods'; 117 } 118 else if (hash.match(/^#property_/)) { 119 tabToActivate = '#properties'; 120 } 121 else if (hash.match(/^#event_/)) { 122 tabToActivate = '#event'; 123 } 124 else if (hash.match(/#l\d+/)) { 125 var lineNumber = /#l(\d+)/.exec(hash)[1]; 126 var whichLi = parseInt(lineNumber, 10) - 1; //e.g. line 1 is 0th element 127 $scroll = $('ol.linenums > li').eq(whichLi); 128 } 129 130 $tabToActivate = $('[data-toggle=tab][href="'+ tabToActivate + '"]'); 131 if ($tabToActivate.length) { 132 $tabToActivate.trigger('click', { ignore: true }); 133 } 134 135 if ($scroll.length) { 136 scrollToAnchor($scroll); 137 } 138 } 139 140 // ************************************************************************* // 141 // Initializations + Event listeners 142 // ************************************************************************* // 143 144 // 145 // Store last clicked tab in local storage 146 // 147 $('#main-nav li').on('click', function(e) { 148 e.preventDefault(); 149 localStorage['main-nav'] = $(this).find('a').attr('href'); 150 }); 151 152 // 153 // Refresh typeahead source arrays when user changes tabs 154 // 155 $('#main-nav li').on('shown', function(e) { 156 e.preventDefault(); 157 setUpWidgets(); 158 }); 159 160 // 161 // Bind change events for options form checkboxes 162 // 163 $('#options-form input:checkbox').on('change', function(){ 164 setOptionDisplayState($(this)); 165 166 // Update localstorage 167 var optionsArr = []; 168 $('#options-form input:checkbox').each(function(i,el) { 169 optionsArr.push($(el).is(':checked')); 170 }); 171 localStorage.options = JSON.stringify(optionsArr); 172 }); 173 174 // 175 // Keyboard shortcut - 's' key 176 // This brings the api search input into focus. 177 // 178 $(window).keyup(function(e) { 179 // Listen for 's' key and focus search input if pressed 180 if(e.keyCode === 83){ // 's' 181 $('#api-tabview-filter input').focus(); 182 } 183 }); 184 185 // 186 // Keyboard shortcut - 'ctrl+left', 'ctrl+right', 'up', 'down' 187 // These shortcuts offer sidebar navigation via keyboard, 188 // *only* when sidebar or any element within has focus. 189 // 190 var nextIndex; 191 $('#sidebar').keydown(function(e) { 192 var $this = $(this); 193 194 // Determine if the control/command key was pressed 195 if(e.ctrlKey){ 196 if(e.keyCode === 37){ // left arrow 197 $('#main-nav li a:first').tab('show'); 198 } else if(e.keyCode === 39){ // right arrow 199 $('#main-nav li a:last').tab('show'); 200 } 201 } else { 202 if(e.keyCode === 40){ // down arrow 203 if ($('#api-tabview-filter input').is(':focus')) { 204 // Scenario 1: We're focused on the search input; move down to the first li 205 $this.find('.tab-content .tab-pane.active li:first a').focus(); 206 } else if ($this.find('.tab-content .tab-pane.active li:last a').is(':focus')) { 207 // Scenario 2: We're focused on the last li; move up to search input 208 $('#api-tabview-filter input').focus(); 209 } else { 210 // Scenario 3: We're in the list but not on the last element, simply move down 211 nextIndex = $this 212 .find('.tab-content .tab-pane.active li') 213 .find('a:focus') 214 .parent('li').index() + 1; 215 $this.find('.tab-content .tab-pane.active li:eq('+nextIndex+') a').focus(); 216 } 217 e.preventDefault(); // Stop page from scrolling 218 } else if (e.keyCode === 38){ // up arrow 219 if($('#api-tabview-filter input').is(':focus')) { 220 // Scenario 1: We're focused on the search input; move down to the last li 221 $this.find('.tab-content .tab-pane.active li:last a').focus(); 222 }else if($this.find('.tab-content .tab-pane.active li:first a').is(':focus')){ 223 // Scenario 2: We're focused on the first li; move up to search input 224 $('#api-tabview-filter input').focus(); 225 }else{ 226 // Scenario 3: We're in the list but not on the first element, simply move up 227 nextIndex = $this 228 .find('.tab-content .tab-pane.active li') 229 .find('a:focus') 230 .parent('li').index() - 1; 231 $this.find('.tab-content .tab-pane.active li:eq('+nextIndex+') a').focus(); 232 } 233 e.preventDefault(); // Stop page from scrolling 234 } 235 } 236 }); 237 238 function setUpHashChange() { 239 $(window).on('hashchange', moveToWindowHash); 240 } 241 242 243 // ************************************************************************* // 244 // Immediate function calls 245 // ************************************************************************* // 246 247 setUpActiveTab(); 248 setUpOptionsCheckboxes(); 249 setUpWidgets(); 250 setUpHashChange(); 251 if (window.location.hash) { 252 moveToWindowHash(); 253 } 254 255 });