1; 'use strict'; 2 3var t2GA; 4 5if ( /github\.io/i.test(location.hostname) ) { 6 (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ 7 (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), 8 m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) 9 })(window,document,'script','https://www.google-analytics.com/analytics.js','t2GA'); 10} 11 12/* 13if ('ontouchstart' in document.documentElement) { 14 window.onerror = function (msg, url, lineNo, columnNo, error) { 15 var string = msg.toLowerCase(), 16 substring = "script error"; 17 18 if (/script error/i.test(string)) { 19 alert('Script Error: See Browser Console for Detail'); 20 } else { 21 var message = 22 "Message: " + msg + "\nURL: " + url + 23 "\nLine: " + lineNo + "\nColumn: " + columnNo + 24 "\nError object: " + JSON.stringify(error); 25 alert(message); 26 } 27 return false; 28 }; 29}; 30*/ 31 32/* This is an immediate function that wraps everything. It initializes all of 33 * the app constants and variables, and hooks window.onDOMContentLoaded to 34 * {eDOMContent}. Inside of it the Panes module is defined, also an immediate 35 * function. 36 * 37 * Many functions accept a content parameter. On first load, this is the main 38 * document div#content element. After that, the parameter is the div#content 39 * element in the documentFragment from the XHR request. This is done so that 40 * all document modifications / additions are done **before** the element 41 * replaces the document element. Simply put, faster rendering. 42 * @js_module_new App 43 */ 44(function(_t2Info, undefined) { 45 46var t2GAInit = false; 47 48if (t2GA instanceof Function) { 49 t2GA( 'create', 'UA-79746991-1', 'auto'); 50 t2GA( 'set', 'anonymizeIp', true); 51 t2GAInit = true; 52}; 53 54//{ Constants 55 56/*### Constants */ 57var ST_VERS = '0.6.0', // state version (local storage object) 58 VERSION = '0.7.0'; 59 60/*#### Window Metrics */ 61var SML_MED = 110 , // char width 0 to 1 type 62 MED_LRG = 160 , // char width 1 to 2 type 63 ZOOM = 95.0, // char width for touch device zoom 64 FS = 15.0; // default fontSize px30em 65 66/*#### Size Metrics */ 67var FLT_TOP = 4.4, // Top of Floating Pane em 68 FLT_HGT = 4.8; // Top + bottom (0.4 em) em 69 WAIT_NO_TOUCH = 6.0 // Wait indicator em 70 WAIT_TOUCH = 9.0 // Wait indicator em 71 72/*#### CSS Class Names */ 73var CN_CLICKED = 'clicked', // used for 'clicked' highlight 74 CN_HIDDEN = 'h', // used with summaries, lists, & header buttons 75 CN_VISIBLE = 'o', 76 CN_WAIT = 'w', // shows wait cursor 77 CN_BTN_VIS = 'vis'; // Used with button elements 78 79/*#### Text Strings */ 80var T_VIEW_SRC = 'view source', 81 T_HIDE_SRC = 'hide source'; 82 83/*#### clickedBy enumeration */ 84var CB_CONTENT = 0, 85 CB_OBJ_PATH = 1, 86 CB_LIST = 2, 87 CB_TOC = 3, 88 CB_POP_STATE = 4; 89 90/*#### Valid List search characters */ 91var RE_LIST_SEARCH = /[a-z0-9$!%&\*\+\-\/<=>\?\[\]\^_\|\~]/i; 92 93/*#### Pane Button ids */ 94var HDR_PANE_BTNS = ['list_vis', 'toc_vis']; 95 96/*#### Pane KeyDown Test */ 97var WIN_PANE_KD = 'cdlmpst'; // C-lass D-oc L-ist M-ethod P-roperties S-earch T-OC 98 99//} 100 101/* t2Info.CSEP t2Info.ISEP */ 102 103//{ Variables 104 105/*### Variables */ 106var storage, // set to localStorage, then sessionStorage 107 state; // Display state object 108 109/*#### General Window Metrics & Data */ 110var cS = null, 111 eContent, // main content element 112 winHeight = 0, // current window height 113 winWidth = 0, // current window width 114 fwHdrHgt = 0, 115 winResizeTmrId = null, // SetTimeout id for window.onresize 116 winType = -1, // 0 narrow, 1 medium, 2 wide 117 winTitle = '', // Title from <head><title>, used in history 118 e25vh, // 25vh wide the element 119 px30em = 0.0, // 30em wide px 120 px50Char = 0.0, // 50 monospaced characters wide px 121 waitWidth; // width of wait indicator 122 123/*#### Clicked and Navigation */ 124var aDOMCur = document.createElement('a'), // current window.location 125 aDOMNext = document.createElement('a'), // next window.location 126 clickedBy = -1, // source of navigation click 127 eContentClicked, // Element that is highlighted in main document 128 clickedTop = 0, // screenY coordinate of click (or clicked item) 129 oXHRDoc, // xhr object currently retrieving document 130 oCSSRuleTable; 131 132/*#### App State */ 133var isHttp = /^http(s)?:/.test(window.location.protocol), 134 isFirstLoad = true, 135 isGetElByIdInDocFrag = ('getElementById' in document.createDocumentFragment()), 136 isServer = false, 137 isTouch = ('ontouchstart' in document.documentElement),
138 isVHBad = false, // iOS Safari 100vh != innerHeight 139 isWinHistory = ('history' in window) && ('pushState' in window.history) && 140 (window.history.pushState instanceof Function), 141 isWinKPTimeOut = false, // used to debounce long key presses 142 isZoomed = false; // Touch devices will zoom via FontSize 143 144/*#### Lib Info */ 145var elLibFooter; 146 147/*#### Debug flags & Objects */ 148var dbgDocTiming = false, // logs doc load timing info to console, dbgDocLoad 149 dbgDoc = false, // logs doc info to console, dbgDocInfo 150 dbgListCalls = false, // logs list function calls 151 dbgListTiming = false, // logs list load timing info to console, dbgListLoad 152 dbgListSplit = false, 153 dbgSearchLoad = false, 154 dbgSearchSplit = false, 155 dbgYDebug = false, // use y_debug element 156 oDbgDoc = {}, 157 oDbgList = {}; 158 159/*#### Objects created by Pane module */ 160var oPane, oList, oToc; 161 162var LS_XHR_LOAD = 0, 163 LS_RENDER = 1; 164 165/* t2Opts (t2 Options) holds data from YARD and customization data */ 166 var docLoadState = { xhr: null, cbFunc: null, url: '', state: null }, 167 t2Opts = { NSEP: '', customHeaderId: '' }; 168 169//} 170 171/* This code controls the 'List' and 'TOC' panes. Exported functions are 172 * detailed in the {__loadPublicState} function, which loads oPane, oList, & oToc. 173 * All exported functions have an underscore in their name. 174 * 175 * Three objects are exported: 176 * * oPane - functions that are common to (or affect) both oList & oToc 177 * * oList - functions & properties specific to the 'List' pane 178 * * oToc - functions & properties specific to the 'TOC' pane 179 * 180 * The functions are grouped and named the same. 181 * @js_module_new Panes 182 */ 183(function() { 184 185//{ Pane Constants 186 187/*### Constants 188 *#### Class Names */ 189var CN_DOCKED = 'd', // Used with nav & toc div elements (the panes) 190 CN_FLOATING = 'f', 191 CN_TOUCH = ' t', 192 CN_CLOSED = 'yl_closed'; // Used on list li elements that have buttons 193 194/*#### Size Metrics - oList & oToc */ 195var LIST_MIN = 18.0 , // List pane min width em 196 LIST_MAX = 40.0 , // List pane max width em 197 LIST_HDR = 5.866667, // List pane header height em 198 TOC_MIN = 18.0 , // as above, but oToc 199 TOC_MAX = 30.0 , 200 TOC_HDR = 4.00 , 201 H_CLS = 1.8667 ; // Height Class & oToc Item em 202 203/*#### .type enumeration */ 204var LIST_CLASS = 0, 205 LIST_METHOD = 1, 206 LIST_EXCEPTION = 2, 207 LIST_PROPERTY = 3, 208 LIST_FILE = 4, 209 LIST_UNKNOWN = 5, 210 // array must match enum, see listGetInfo 211 LIST_ENUM = ['class', 'method', 'exception', 'property', 'file', 'Unknown']; 212 213/*#### TOC Generate Strings & RegEx */ 214var RE_METH_CLS = /-class_method$/, 215 RE_METH_INST = /-instance_method$/; 216 217//} 218 219//{ Pane Variables 220 221/*### Variables 222 *#### Resizers start data */ 223var resizerStWid = 0, // starting pane width 224 resizerStX = 0; // mouseDown or TouchStart screenX 225 226/*#### Metrics */ 227var winFloatingTop; // screenY of floating windows 228 229/*#### List Search & Load */ 230var listLastSearchText = '', // used for search cancel 231 listPath = '', // base path for list files 232 listCurPN = null, // pathName of current list 233 234 oListData = {}, // data about lists, key is url 235 oLoad = {}, // object to pass to listLoadSplit 236 oSearches = []; // array of search objects 237 238/*#### TOC Search & Load */ 239var tocLastSearchText = '', // used for search cancel 240 tocSearchInfo = [], 241 re_csep = t2Info.CSEP.replace(/([\?*+^|\.\$\[\]\(\)\{\}])/g, "\\$1"), 242 re_isep = t2Info.ISEP.replace(/([\?*+^|\.\$\[\]\(\)\{\}])/g, "\\$1"), 243 re_meth_sep = new RegExp('^(' + re_csep + '|' + re_isep + ')'); 244 245//} 246 247//{ @!group Public Interface 248 249/* Binds reSize event handlers to oList & oToc 250 * @param me [oList, oToc] this object 251 */ 252function __bind(me) { 253 me.resizeMD = resizeMD.bind(me); 254 me.resizeMM = resizeMM.bind(me); 255 me.resizeMU = resizeMU.bind(me); 256 257 if (isTouch) { 258 me.resizeTS = resizeTS.bind(me); 259 me.resizeTM = resizeTM.bind(me); 260 me.resizeTE = resizeTE.bind(me); 261 } 262}; 263 264/* Initialization - Loads public function properties into oList, oPane, and oToc, 265 * loads state from storage. 266 * @note This is loaded before the DOMContentLoaded event 267 */ 268function __loadPublicState() { 269 var version = ''; 270 271 try { storage = window.localStorage; } catch (e) { 272 try { storage = window.sessionStorage; } catch (e) { }; 273 } 274 275 if (storage && storage.yardState) { 276 state = JSON.parse(storage.yardState); 277 if (state.showSource === undefined) 278 state.showSource = false;
279 version = (state.version !== undefined ? state.version : ''); 280 } 281 if (ST_VERS > version) { 282 state = { 283 'version': ST_VERS, 284 'overviewCollapsed': false, 285 'relationsCollapsed': false, 286 'summaryCollapsed': false, 287 'showSource': false, 288 'fontSize': '15px', 289 'fontSizeSet': null, 290 'display': [ 291 { 'list': { 'docked': false , 'vis': true , 'width': 0 }, 292 'toc' : { 'docked': false , 'vis': false , 'width': 0 } }, 293 294 { 'widthDocked': 0, 295 'list': { 'docked': true , 'vis': true , 'width': 0 }, 296 'toc' : { 'docked': true , 'vis': false , 'width': 0 } }, 297 298 { 'list': { 'docked': true , 'vis': true , 'width': 0 }, 299 'toc' : { 'docked': true , 'vis': true , 'width': 0 } } 300 ] 301 }; 302 Object.seal(state); 303 if (storage) storage.yardState = JSON.stringify(state); 304 } 305 306 oPane = { 307 firstDOMLoad: _FirstDOMLoad, // called by eDOMContent (first load) 308 mainClk: pane_MainClk, // called by clkHdrBtn 309 mainKD: pane_MainKD, // called by winKeyDown 310 locSet: pane_LocSet // called by domLayout 311 }; 312 313 /* e element 314 * s style 315 * d state array item 316 */ 317 oList = { e: null, s: null, d: null, bVis: null, nav: null, 318 clickedA: null, clickedLI: null, clickedLIOld: null, items: null, 319 isOpenClose: false, 320 hdrHeight: 0, 321 type: LIST_UNKNOWN, 322 itemQty: 0, 323 itemsSearch: 0, 324 itemsVis: 0, 325 keyPress: list_KeyPress, // for single key list scroll 326 load: list_Load, // called to navigate to new list 327 showClicked: list_ShowClicked // called by gotoHash & xhrCBDoc 328 }; 329 330 oToc = { e: null, s: null, d: null, bVis: null, nav: null, 331 clickedA: null, clickedLI: null, clickedLIOld: null, items: null, 332 isOpenClose: false, 333 hdrHeight: 0, 334 searchInfo: null, 335 floatingOffset: null, 336 generate: toc_Generate, // called by addContent 337 showClicked: toc_ShowClicked // called by gotoHash 338 }; 339 340 oLoad.isRunning = false; 341 oLoad.cancel = false; 342 343 __bind(oList); 344 __bind(oToc); 345 Object.seal(oPane); 346 Object.seal(oList); 347 Object.seal(oToc); 348 __bind = undefined; 349}; 350 351//} @!endgroup 352 353//{ @!group FirstDOMLoad Functions 354 355/* Called **only** on first YARD document load 356 * @param [Boolean, nil] hookEvents true for events only 357 */ 358function _FirstDOMLoad(hookEvents) { 359 if (hookEvents) { 360 _HookEvents(); 361 _HookEvents = undefined; 362 } else { 363 _CheckState(); 364 _SetDOMProps(); 365 _CheckState = undefined; 366 _SetDOMProps = undefined; 367 }; 368} 369 370/* Checks width's in state, intializes hdrHeights */ 371function _CheckState() { 372 var em = px30em / 30.0, 373 st, 374 writeState = false; 375 376 winFloatingTop = FLT_TOP * em; 377 oList.hdrHeight = LIST_HDR * em; 378 oToc.hdrHeight = TOC_HDR * em; 379 380 // seemed to be a good width... 381 em = (0.6667 * px50Char).toFixed(0); 382 383 // set up state with DOM measurement 384 for (var i = 0; i < 3; i++) { 385 st = state.display[i]; 386 if (st.list.width === 0) { 387 st.list.width = em; 388 writeState = true; 389 } 390 if (st.toc.width === 0) { 391 st.toc.width = em; 392 writeState = true; 393 } 394 } 395 if (state.display[1].widthDocked === 0) { 396 st.widthDocked = em; 397 writeState = true; 398 } 399 if (writeState && storage) 400 storage.yardState = JSON.stringify(state); 401} 402 403/* Hooks oList & oToc events on first load */ 404function _HookEvents() { 405 var el = _id('list_search_text'); 406 el.tabIndex = 1; 407 el.addEventListener('keypress', listSearchKP , false); 408 el.addEventListener('input' , listSearchChg, false); 409 410 el = _id('toc_search_text'); 411 el.tabIndex = 2; 412 el.addEventListener('keypress', tocSearchKP , false); 413 el.addEventListener('input' , tocSearchChg, false); 414 415 _id('list_header').addEventListener('click', listClkHeader, false); 416 _id('toc_header' ).addEventListener('click', tocClkHeader, false); 417 418 oList.nav.addEventListener('click', paneClk.bind(oList), false); 419 oToc.nav.addEventListener('click', paneClk.bind(oToc) , false); 420 421 _id('list_sizer').addEventListener('mousedown', oList.resizeMD, false); 422 _id('toc_sizer' ).addEventListener('mousedown', oToc.resizeMD, false); 423 424 if (isTouch) { 425 _id('list_sizer').addEventListener('touchstart', oList.resizeTS, false); 426 _id('toc_sizer' ).addEventListener('touchstart', oToc.resizeTS, false); 427 } 428} 429 430/* Loads properties of oList & oToc releated to elements on first load */ 431function _SetDOMProps() { 432 oList.e = _id('y_list'); 433 oList.s = _id('y_list').style; 434// oList.bVis = _id('list_vis'); 435 oList.nav = _id('list_nav'); 436 oList.items = _id('list_items'); 437 438 oToc.e = _id('y_toc'); 439 oToc.s = _id('y_toc').style; 440// oToc.bVis = _id('toc_vis'); 441 oToc.nav = _id('toc_nav'); 442 oToc.items = _id('toc_items'); 443} 444 445//} @!endgroup 446 447//{ @!group oPane Functions 448
449/* Only called by domLayout, sets panes to state of state[winType] 450 * @param winTypeLast [Integer] previous winType (-1 on init) 451 */ 452function pane_LocSet(winTypeLast) { 453 cS = state.display[winType]; 454 oList.d = cS.list; 455 oToc.d = cS.toc; 456 paneLocSet(oList, winTypeLast); 457 paneLocSet(oToc , winTypeLast); 458} 459 460/* Called when a button in the main header is clicked 461 * @param id [String] id of the clicked button 462 */ 463function pane_MainClk(id) { 464 // IE11 var oMe = id.startsWith('list') ? oList : oToc; 465 var oMe = /^list/.test(id) ? oList : oToc; 466// if ( id.endsWith('float') ) { 467 if ( /float$/.test(id) ) { 468 oMe.d.docked = false; 469 paneShow(oMe); 470 } else if ( /dock$/.test(id) ) { 471 oMe.d.docked = true; 472 paneShow(oMe); 473 } else if ( /vis$/.test(id) ) { 474 if (oMe.d.vis) paneHide(oMe); 475 else paneShow(oMe); 476 } 477} 478 479/* Called when a key is pressed, from winKeyDown 480 * @param key [String] key pressed 481 */ 482function pane_MainKD(key, which) { 483 484 // Escape key 485 if (which === 27) { 486 listSearchClear(); 487 return; 488 } 489 490 if (WIN_PANE_KD.indexOf(key) < 0) return; 491 switch (key) { 492 case 'c': 493 listGoto('class'); 494 break; 495 case 'd': 496 listGoto('doc'); 497 break; 498 case 'l': 499 if (oList.d.vis) paneHide(oList); 500 else paneShow(oList); 501 break; 502 case 'm': 503 listGoto('method'); 504 break; 505 case 'p': 506 listGoto('properties'); 507 break; 508 case 's': 509 if (!oList.d.vis) paneShow(oList); 510 _id('list_search_text').focus(); 511 break; 512 case 't': 513 if (oToc.d.vis) paneHide(oToc); 514 else paneShow(oToc); 515 break; 516 } 517} 518 519/* @!visibility private */ 520 521/* Event handler for pane list click, bound to oList or oToc in paneHookEvents */ 522function paneClk(e) { 523 var tgt = e.target, 524 eA, 525 eLI, 526 isList = (this === oList), 527 cancel = false, 528 t; 529 530 settingsCheck(); // close settings window 531 if (tgt.tagName === 'NAV' && tgt.classList.contains('y_nav')) return; 532 533 eLI = getPrntByIO(tgt, HTMLLIElement); 534 535 if (dbgListCalls) console.log("paneClk eLI\n" + eLI); 536 537 // clicked button of an open/close node, or an exception 'group' node 538 if ( (tgt instanceof HTMLButtonElement) || 539 (tgt instanceof HTMLDivElement && !tgt.querySelector('a')) ) { 540 541 // close or open clicked node only 542 if (!e.ctrlKey) { eLI.classList.toggle(CN_CLOSED); 543 544 // close or open clicked node along with all children 545 } else { 546 var nl = eLI.querySelectorAll("li > div"); 547 if ( eLI.classList.contains(CN_CLOSED) ) { 548 eLI.classList.remove(CN_CLOSED); 549 for (var i = 0, el; el = nl[i]; i++) { 550 el.parentElement.classList.remove(CN_CLOSED); 551 }; 552 } else { 553 eLI.classList.add(CN_CLOSED); 554 for (var i = 0, el; el = nl[i]; i++) { 555 el.parentElement.classList.add(CN_CLOSED); 556 }; 557 }; 558 }; 559 if (isList && this.isOpenClose) listEvenOdd(); 560 cancel = true; 561 562 // clicked a document link 563 } else if ( eLI && ( eA = eLI.querySelector('a, div > a') ) && !e.ctrlKey) { 564 if (this.clickedLIOld) this.clickedLIOld.classList.remove(CN_CLICKED); 565 this.clickedLIOld = this.clickedLI; 566 clickedTop = eLI.getBoundingClientRect().top - fwHdrHgt; 567 if (!isList) clickedTop -= 1.0; // bottom-border in TOC 568 this.clickedLI = eLI; 569 this.clickedA = eA; 570 clickedBy = ( isList ? CB_LIST : CB_TOC ); 571 572 if (eA.hash !== '') { 573 // craziness for IE11 handling of anchor elements properties 574 t = eA.href.slice( eA.href.search(/[^:/]\//) + 1, eA.href.length - eA.hash.length); 575 if (t !== window.location.pathname) { 576 gotoDoc(eA.pathname + '#' + decodeURIComponent(eA.hash.replace(/%-/, '%25-')).slice(1)); 577 } else { 578 aDOMNext.href = eA.href 579 gotoHash(); 580 } 581 } else if ( !/\/#$/.test(eA.href) ) { 582 t = eA.getAttribute('href'); 583 if ( /^\//.test(t) ) gotoDoc(t); 584 else gotoDoc("/" + t); 585 } 586 cancel = true; 587 }; 588 if (cancel) { 589 e.preventDefault(); 590 e.stopPropagation(); 591 return false; 592 }; 593} 594 595/* Hides a pane 596 * @param me [oList, oToc] 597 */ 598function paneHide(me) { 599 me.bVis.className = CN_HIDDEN; 600 me.d.vis = false;
601 me.e.classList.add(CN_HIDDEN); 602 updateCSS(); 603 if (storage) storage.yardState = JSON.stringify(state); 604} 605 606/* Sets location of panes, only called by pane_LocSet 607 * @param me [oList, oToc] 608 * @param winTypeLast [Integer] previous winType, -1 on first load 609 */ 610function paneLocSet(me, winTypeLast) { 611 var isDocked = me.d.docked, 612 prevSt = winTypeLast >= 0 ? state.display[winTypeLast] : null, 613 cnLoc = isDocked ? CN_DOCKED : CN_FLOATING, 614 meLast = isFirstLoad || (me === oList ? prevSt.list : prevSt.toc), 615 dChng = isFirstLoad || (me.d.docked !== meLast.docked); 616 617 if (dChng) { 618 cnLoc = isDocked ? CN_DOCKED : CN_FLOATING; 619 me.e.className = cnLoc + (isTouch ? CN_TOUCH : ''); 620 } 621 if (me.d.vis) { 622 me.e.classList.remove(CN_HIDDEN); 623 if (me.bVis) me.bVis.className = CN_BTN_VIS; 624 } else { 625 me.e.classList.add(CN_HIDDEN); 626 if (me.bVis) me.bVis.className = CN_HIDDEN; 627 } 628 if (isDocked) { 629 me.s.width = ( winType === 1 ? cS.widthDocked : me.d.width ) + 'px'; 630 } else { 631 me.s.width = ''; 632 } 633 634} 635 636/* Makes a pane list item visible. Only called by paneScrollTo. 637 * @param prnt [HTMLElement] item to make visible 638 * @return [Boolean] true any items were 'opened' to show the item 639 */ 640function paneOpenToItem(prnt) { 641 var notFirst = false, 642 heightChanged = false, 643 open = []; 644 645 do { 646 if (prnt instanceof HTMLLIElement) { 647 if (notFirst) { 648 if ( prnt.classList.contains(CN_CLOSED) ) { 649 open.push(prnt); 650 } 651 } else notFirst = true; 652 } 653 prnt = prnt.parentElement; 654 } 655 while (prnt instanceof HTMLUListElement || prnt instanceof HTMLOListElement || prnt instanceof HTMLLIElement); 656 657 if (open.length > 0) { 658 heightChanged = true; 659 for (var i = 0, el; el = open[i]; i++) { el.classList.remove(CN_CLOSED); } 660 } 661 return heightChanged; 662} 663 664/* Called if a Pane global 'minus' (close) or 'plus' (open) button is clicked. 665 * @param me [oList, oToc] pane to change 666 * @param isOpen [Boolean] 667 */ 668function paneOC(me, isOpen) { 669 var isList = (me === oList), 670 qsa = isList ? 'li > ul' : 'li > ol', 671 nl = me.items.querySelectorAll(qsa); 672 673 if (isOpen) { 674 for (var i = 0, el; el = nl[i]; i++) { 675 el.parentElement.classList.remove(CN_CLOSED); 676 } 677 } else { 678 for (var i = 0, el; el = nl[i]; i++) { 679 el.parentElement.classList.add(CN_CLOSED); 680 }; 681 }; 682 if (isList && me.isOpenClose) listEvenOdd(); 683} 684 685/* Scrolls to a list item and highlights. 686 * @param me [oList, oToc] pane to change 687 * @param eA [HTMLAnchorElement] 688 */ 689function paneScrollTo(me, eA) { 690 var eSTop, 691 offset, 692 eLI, 693 clkTop; 694 695 if (dbgListCalls) 696 console.log( "paneScrollTo " + (me === oList ? "LIST" : "TOC") ); 697 698 699 if (eA) { 700 if (eLI = getPrntByIO(eA, HTMLLIElement) ) { 701 if (eLI !== me.clickedLI && (me.clickedLI instanceof HTMLLIElement) ) 702 me.clickedLI.classList.remove(CN_CLICKED); 703 704 me.clickedLI = eLI; 705 me.clickedA = eA; 706 if (me.isOpenClose) { 707 if (paneOpenToItem(eLI) && me === oList) listEvenOdd(); 708 } 709 eLI.classList.add(CN_CLICKED); 710 offset = me.d.docked ? me.hdrHeight : winFloatingTop; 711 if (clickedBy === CB_OBJ_PATH) 712 clkTop = me.hdrHeight + 3 * H_CLS * px30em / 30.0; 713 else 714 clkTop = Math.max(me.hdrHeight, clickedTop) + - fwHdrHgt; 715 eSTop = eLI.offsetTop - clkTop + offset; 716 me.nav.scrollTop = eSTop - ( me === oToc ? 1 : 0) - fwHdrHgt; 717 } 718 } else { 719 me.nav.scrollTop = 0; 720 if (me.clickedLI) me.clickedLI.classList.remove(CN_CLICKED); 721 me.clickedA = null; 722 me.clickedLI = null; 723 } 724} 725 726/* Shows a pane 727 * @param [oList, oToc] me 728 */ 729function paneShow(me) { 730 var isList = (me === oList), 731 you = isList ? oToc : oList, 732 curDocked = me.e.classList.contains(CN_DOCKED), 733 newDocked = me.d.docked, 734 isDockedChanged = (curDocked !== newDocked), 735 cnLoc = newDocked ? CN_DOCKED : CN_FLOATING; 736 737 if (isDockedChanged) me.e.className = cnLoc + (isTouch ? CN_TOUCH : ''); 738 739 if (newDocked) { 740 me.s.width = ((winType === 1) ? cS.widthDocked : me.d.width) + 'px'; 741 } else { 742 // me.s.width = ''; 743 me.s.width = me.d.width + 'px'; 744 }; 745 746 me.e.classList.remove(CN_HIDDEN); 747 me.d.vis = true; 748 me.bVis.className = CN_BTN_VIS; 749 750 if ( !newDocked && !you.d.docked ) { 751 if (you.d.vis) paneHide(you); 752 } else if (winType === 1) { 753 if (newDocked && you.d.docked && you.d.vis) paneHide(you); 754 } 755 if (isList || aDOMCur.hash) me.showClicked(aDOMCur); 756 if (storage) storage.yardState = JSON.stringify(state); 757 758 updateCSS(); 759}; 760 761/* @!visibility public */ 762 763//} @!endgroup 764 765//{ @!group oList Functions 766 767/* Event Handler for Window keyPress 768 * @param key [String] string of the key pressed 769 */ 770function list_KeyPress(key) { 771 var eA, 772 re, 773 result; 774 775 // return if class, only list nested list 776 if (oListData[listCurPN].type === LIST_CLASS) return; 777 778 txt = key.replace(/([\?*+^|\.\$\[\]\(\)\{\}])/g, "\\$1"); 779 780 if (oListData[listCurPN].type === LIST_METHOD) { 781 re = new RegExp('^[\.#]?' + txt, 'i'); 782 } else { 783 re = new RegExp('^' + txt, 'i'); 784 } 785 786 result = oListData[listCurPN].searchInfo.findIndex( function (o) { return re.test(o.text); } ); 787 788 if (result) { 789 eA = oList.items.children[result]; 790 oList.nav.scrollTop = getPrntByIO(eA, HTMLLIElement).offsetTop; 791 } 792} 793 794/* Loads List Pane. Calls either xhr or cache load. 795 * @param url [String] url of list 796 * @param force [Boolean] force whether to always load page 797 */ 798function list_Load(eA, force) { 799 var el = _id('list_items'), 800 url, pn; 801 802 if (force === undefined) force = false;
803 804 // return if base paths match 805 if ( !force && listPath === eA.pathname.replace(/[^\/]+$/, '') ) return; 806 807 if ( 'classList' in _id('list_search_icon') ) { 808 _id('list_search_icon').classList.remove('s_clr'); 809 } else { 810 _id('list_search_icon').className = ''; 811 }; 812 813 if (dbgListCalls) console.log("list_Load\nlistCurPN\n" + listCurPN + 814 "\neA.pathname\n" + eA.pathname); 815 816 // save previous list state 817 if (listCurPN) { 818 if (oList.clickedLI) oList.clickedLI.classList.remove(CN_CLICKED); 819 oList.clickedLI = null; 820 oList.clickedA = null; 821 oListData[listCurPN].list = el.cloneNode(true); 822 oListData[listCurPN].scrollTop = el.parentElement.scrollTop; 823 }; 824 825 url = eA.href.trim(); 826 pn = eA.pathname; 827 oLoad.pathName = pn; 828 829 // new path, reset data and reload 830 if ( listPath !== pn.replace(/[^\/]+$/, '') ) { 831 oListData = {}; 832 oList.clickedA = null; 833 oList.clickedLI = null; 834 listPath = pn.replace(/[^\/]+$/, ''); 835 oLoad.xhr = xhrSend(url, listXhrCB); 836 } else if (force) { 837 setWait(CB_LIST); 838 // request has been cached, load from cache 839 if ( (oListData[pn] instanceof Object) && 840 (oListData[pn].list instanceof HTMLUListElement) ) 841 listXhrCB(true, '', url, 200, 0, 0) 842 // need to load from file 843 else oLoad.xhr = xhrSend(url, listXhrCB); 844 }; 845}; 846 847/* Highlights an item in the oList list 848 * @param aDOM [HTMLAnchorElement] anchor with object / url info 849 */ 850function list_ShowClicked(aDOM) { 851 // aDOM hash is NOT encoded 852 var pathName = /^\//.test(aDOM.pathname) ? aDOM.pathname : '/' + aDOM.pathname, 853 pathFull = pathName, 854 eLI = oList.clickedLI, 855 hrefA, 856 qs, 857 eA, 858 eNewClickedLI, 859 paneUL, 860 t; 861 862 if (dbgListCalls) { 863 if (aDOM.hash) 864 console.log("list_ShowClicked\n" + pathName + '#' + t2EncodeStr( aDOM.hash.slice(1) )); 865 else 866 console.log("list_ShowClicked\n" + pathName); 867 }; 868 869 if (clickedBy === CB_LIST) { 870 if (oList.clickedLIOld) { 871 oList.clickedLIOld.classList.remove(CN_CLICKED); 872 oList.clickedLIOld = null; 873 } 874 if (eLI) eLI.classList.add(CN_CLICKED); 875 return; 876 } 877 878 if (aDOM.hash) pathFull += '#' + t2EncodeStr( aDOM.hash.slice(1) ); 879 880 if (oList.clickedA) { 881 hrefA = oList.clickedA.getAttribute('href'); 882 if (hrefA === pathFull) { 883 eA = oList.clickedA; 884 } else if (hrefA === pathName) { 885 eA = oList.clickedA; 886 if ( eLI instanceof HTMLLIElement && 887 eLI.classList.contains(CN_CLICKED) ) return; 888 }; 889 if (eA) eNewClickedLI = eLI; 890 }; 891 892 if (!eA) { 893 paneUL = ( t = _id('list_search_items') ) ? t : oList.items; 894 // Quotes should match template 895 qs = 'a[href="' + pathFull + '"]'; 896 eA = paneUL.querySelector(qs); 897 if (!eA) { 898 qs = 'a[href="' + pathName + '"]'; 899 eA = paneUL.querySelector(qs); 900 }; 901 }; 902 903 if (dbgListCalls) console.log("list_ShowClicked Found\n" + eA); 904 905 if (eA) paneScrollTo(oList, eA); 906 else { 907 if (oList.clickedLI) { 908 oList.clickedLI.classList.remove(CN_CLICKED); 909 oList.clickedLI = null; 910 oList.clickedA = null; 911 }; 912 if ( oListData[listCurPN] && oListData[listCurPN].scrollTop > 0) 913 oList.nav.scrollTop = oListData[listCurPN].scrollTop; 914 }; 915}; 916 917/* Event Handler for oList Header click */ 918function listClkHeader(e) { 919 var tgt = e.target, 920 tag = tgt.tagName, 921 cancel = false; 922 923 settingsCheck(); 924 925 switch (tag) { 926 case 'BUTTON': 927 if (tgt.id !== 'list_sizer') 928 paneOC(oList, (tgt.className === 'y_plus')); 929 cancel = true; 930 break; 931 case 'A': 932 if (!e.ctrlKey) { 933 cancel = true; 934 if (oLoad.xhr) { 935 oLoad.xhr.abort(); 936 oLoad.xhr = null; 937 } 938 if (oLoad.isRunning) oLoad.cancel = true; 939 listSearchCancel(); 940 list_Load(tgt, true); 941 } 942 break; 943 case 'path': 944 tag = 'svg'; 945 tgt = tgt.parentElement; 946 /* falls through */ 947 case 'svg': 948 if (tgt.id === 'list_search_icon') { 949 listSearchClear(); 950 cancel = true; 951 } 952 break; 953 case 'INPUT': 954 if (tgt.id === 'list_search_text') { 955 tgt.focus(); 956 cancel = true; 957 } 958 break; 959 } 960 if (cancel) { 961 e.stopPropagation(); 962 e.preventDefault(); 963 return false;
964 } 965} 966 967/* Sets the even / odd shading of oList items */ 968function listEvenOdd(items) { 969 var liVis = [], 970 odd = [], 971 even = [], 972 lenVis = 0; 973 974 if (dbgListCalls) console.log("listEvenOdd\n" + listCurPN); 975 976 if (items === undefined) items = oList.items; 977 978 // array liVis passed by ref, loaded with visible items 979 listGetVis( items.children, liVis ); 980 lenVis = liVis.length; 981 oList.itemsVis = lenVis; 982 983 // find all elements that require changing, push to odd & even arrays 984 for (var j = 0, el; j < lenVis; j++) { 985 el = liVis[j]; 986 if (j % 2 === 0) { 987 if ( !el.classList.contains('odd') ) odd.push(el); 988 } else { 989 if ( !el.classList.contains('even') ) even.push(el); 990 } 991 } 992 993 // now loop thru items in both arrays and change class 994 for (var j = 0, elCL, len = odd.length; j < len; j++) { 995 elCL = odd[j].classList; 996 elCL.remove('even') ; elCL.add('odd'); 997 } 998 for (var j = 0, elCL, len = even.length; j < len; j++) { 999 elCL = even[j].classList; 1000 elCL.remove('odd') ; elCL.add('even'); 1001 } 1002} 1003 1004/* Called after a new url is loaded into oList 1005 * 1006 * Sets the following: 1007 * * type 1008 * * isOpenClose 1009 * 1010 * @param [Object] ld oListData item. 1011 */ 1012function listGetInfo(ld) { 1013 var ul = ld.list, 1014 ulCL = ul.classList; 1015 1016 ld.type = LIST_UNKNOWN; 1017 for (var i = 0, t; t = LIST_ENUM[i]; i++) { 1018 if ( ulCL.contains(t) ) { 1019 ld.type = i; 1020 break; 1021 }; 1022 }; 1023 ld.isOpenClose = (ul.querySelector('button') !== null); 1024 if (dbgListTiming) oDbgList.elements = ul.querySelectorAll('*').length; 1025} 1026 1027/* Gets an ordered list of visible items (LI elements), only used when 1028 * isOpenClose is true. Reentrant. 1029 * @param nl [HTMLCollection] list of nodes to check 1030 * @param liVis [<HTMLLIElement>] array of LI elements that are visible 1031 */ 1032function listGetVis(nl, liVis) { 1033 for (var i = 0, el, ul; el = nl[i]; i++) { 1034 liVis.push(el); 1035 ul = el.lastElementChild; 1036 if (ul instanceof HTMLUListElement && !el.classList.contains(CN_CLOSED)) { 1037 listGetVis( ul.children, liVis ); 1038 } 1039 } 1040} 1041 1042/* Called when Ctrl-Alt combinations are used to goto a list 1043 * @param list [String] 1044 */ 1045function listGoto(list) { 1046 var nl = _id('list_menu').querySelectorAll('a'), 1047 re = new RegExp('^\\s*' + list, 'i'), 1048 url = '', listState; 1049 1050 for (var i = 0, el; el = nl[i]; i++) { 1051 if (re.test(el.textContent)) { 1052 if (oLoad.xhr) { 1053 oLoad.xhr.abort(); 1054 oLoad.xhr = null; 1055 } 1056 if (oLoad.isRunning) oLoad.cancel = true; 1057 listSearchCancel(); 1058 list_Load(el, true); 1059 if (!oList.d.vis) paneShow(oList); 1060 break; 1061 } 1062 } 1063} 1064 1065/* Callback function needed for when {listLoadSplit} completes. */ 1066function listLoadDone() { 1067 var eSearch = _id('list_search_text'), 1068 t; 1069 1070 if (dbgListCalls) console.log("listLoadDone"); 1071 1072 oList.items = _id('list_items'); 1073 oList.itemsSearch = 0; 1074 1075 if (isFirstLoad) { 1076 oList.s.visibility = ''; 1077 clickedBy = CB_POP_STATE; 1078 clickedTop = (oToc.hdrHeight + 3.0 * H_CLS * px30em / 30) - fwHdrHgt; 1079 if (aDOMNext.hash) gotoHash(); 1080 else if (oList.d.vis) list_ShowClicked(aDOMNext); 1081 isFirstLoad = false; 1082 } else if (oList.d.vis) list_ShowClicked(aDOMNext); 1083 1084 if (dbgListCalls) console.log("listLoadDone\nlistCurPN\n" + listCurPN + 1085 "\noListData[listCurPN].scrollTop\n" + oListData[listCurPN].scrollTop); 1086 1087 if (listCurPN && oListData[listCurPN].scrollTop > 0) { 1088 if (!oList.clickedA || (oList.clickedA.href !== aDOMCur.href) ) 1089 oList.nav.scrollTop = oListData[listCurPN].scrollTop; 1090 }; 1091 1092 oLoad.isRunning = false; 1093 if (dbgListTiming) { 1094 oDbgList.render = performance.now() - oDbgList.render; 1095 dbgListLoad(); 1096 } 1097 1098 if ( t = eSearch.value.trim()) { 1099 if (t !== '') listSearchChg(); 1100 } 1101 setWait(); 1102} 1103 1104/* Splits loading of LI elements when list is large, better UI responsiveness. 1105 * @param xhrEl [HTMLElement] element with children to copy from (from xhr docFrag) 1106 * @param docEl [HTMLElement] element to add children to (in document) 1107 * @param qty [Integer] number of children to load in the first loop 1108 * @param qty_next [Integer] number of children to load in the rest of the loops 1109 * @param cbFunc [Function] callback function called when all children have 1110 * been loaded/moved 1111 * @param oState [object] object to pass run to app, and cancel from app 1112 */ 1113function listLoadSplit(xhrEl, docEl, qty, qty_next, cbFunc, oState) { 1114 var func, 1115 tmrIds = [], 1116 rng = xhrEl.ownerDocument ? xhrEl.ownerDocument.createRange() : document.createRange(), 1117 docFrags = []; 1118 1119 setWait(CB_LIST); 1120 //var tSt = performance.now(); 1121 1122 rng.setStart(xhrEl, 0); 1123 rng.setEnd(xhrEl, Math.min( qty, xhrEl.childElementCount) ); 1124 docEl.appendChild( rng.extractContents() ); 1125 qty = qty_next; 1126 1127 // load remaining nodes into docFrags array 1128 while (xhrEl.childElementCount > 0) { 1129 //console.log(xhrEl.firstChild.tagName + " len = " + xhrEl.childElementCount); 1130 rng.setStart(xhrEl, 0); 1131 rng.setEnd(xhrEl, Math.min(qty, xhrEl.childElementCount) ); 1132 docFrags.push( rng.extractContents() ); 1133 } 1134 rng.detach(); 1135 rng = null; 1136 xhrEl = null; 1137 oState.isRunning = true; 1138 //console.log("Split items " + docFrags.length + " " + Math.round(performance.now() - tSt)); 1139 1140 func = function() { 1141 //console.log("Timer " + Math.round(performance.now() - tSt)); 1142 var frag; 1143 if (oState.cancel) { 1144 listClearLoadTimers(tmrIds, oState); 1145 docFrags = null; 1146 } else { 1147 if ( frag = docFrags.shift() ) docEl.appendChild(frag); 1148 frag = null; 1149 if (docFrags.length === 0) { 1150 oState.isRunning = false;
1151 if (cbFunc instanceof Function) setTimeout(cbFunc, 50); 1152 } else { 1153 tmrIds.push( setTimeout( func, 100) ); 1154 }; 1155 }; 1156 }; 1157 tmrIds.push( setTimeout( func, 15) ); 1158}; 1159 1160function listClearLoadTimers(ary, oState) { 1161 var len = ary.length; 1162 // console.log("called clearTimers " + len); 1163 if (len > 0) { 1164 for (var i = 0, tmr; tmr = ary[i]; i++) { 1165 clearTimeout(tmr); 1166 }; 1167 ary = null; 1168 }; 1169 oState.isRunning = false; 1170 setWait(); 1171}; 1172 1173/* xhr callback function when a new List document is ready, called by 1174 * xhrReadyStateChange 1175 * @param docFrag [DocumentFragment] body element of url document 1176 * @param title [String] \<head\>\<title\> textContent 1177 * @param url [String] 1178 * @param status [Integer] 1179 * @param ms [Float] time to parse docFrag 1180 * @param msRcv {Float] time from xhrSend to xhrRSC 1181 */ 1182function listXhrCB(docFrag, title, url, status, ms, msRcv) { 1183 var newMenu, 1184 newUL, 1185 oldUL = _id('list_items'), 1186 hdr = _id('list_header'), 1187 ld, 1188 len, 1189 t, t1; 1190 1191 if (status !== 200 || !docFrag) { 1192 setWait(); 1193 alert('listXhrCB - bad return with status ' + status + " from location\n" + url); 1194 return; 1195 } 1196 1197 oDbgList.xhrRSC = ms; 1198 var tSt = performance.now(), tEnd; 1199 oDbgList.xhrRcv = msRcv; 1200 1201 oLoad.xhr = null; 1202 oLoad.cancel = oLoad.isRunning; 1203 oList.clickedA = null; 1204 oList.clickedLI = null; 1205 1206 listCurPN = oLoad.pathName; 1207 1208 if (oListData[listCurPN] === undefined) { 1209 1210 if (t = getDocFragId(docFrag, 'list_footer')) { 1211 elLibFooter = t.cloneNode(true); 1212 addFooter(document); 1213 } else { 1214 elLibFooter = null; 1215 } 1216 1217 oListData[listCurPN] = {}; 1218 ld = oListData[listCurPN]; 1219 ld.list = getDocFragId(docFrag, 'list_items').cloneNode(true); 1220 clean(ld.list); 1221 if ( t = getDocFragId(docFrag, 'list_menu') ) 1222 ld.menu = t.cloneNode(true); 1223 else 1224 ld.menu = _id('list_menu').cloneNode(true); 1225 listGetInfo(ld); 1226 1227 ld.title = title; 1228 ld.search = ''; 1229 listSearchLoad(ld); 1230 listEvenOdd(ld.list); 1231 docFrag = null; 1232 } else { 1233 ld = oListData[listCurPN]; 1234 } 1235 oList.itemQty = ld.searchInfo.length; 1236 oList.isOpenClose = ld.isOpenClose; 1237 1238 newUL = ld.list.cloneNode(true); 1239 newMenu = ld.menu.cloneNode(true); 1240 1241 // remove event listeners 1242 if ( t = _id('list_sizer') ) { 1243 t.removeEventListener('mousedown', oList.resizeMD); 1244 if (isTouch) 1245 t.removeEventListener('touchstart', oList.resizeTS); 1246 }; 1247 1248 _id('list_search_text').value = ld.search; 1249 if (ld.search === '') { 1250 if (t = _id('list_search_items') ) oList.nav.removeChild(t); 1251// _id('list_search_icon').classList.remove('s_clr'); 1252 } else { 1253 _id('list_search_icon').classList.add('s_clr'); 1254// newUL.style.display = 'none'; 1255 len = 0; 1256 } 1257 1258 t = oList.isOpenClose; 1259 hdr.querySelector('button.y_minus').disabled = !t; 1260 hdr.querySelector('button.y_plus' ).disabled = !t; 1261 1262 _id('list_title').textContent = ld.title; 1263 1264 len = newUL.childElementCount; 1265 1266 if (dbgListTiming) { 1267 oDbgList.render = performance.now(); 1268 oDbgList.cbProc = oDbgList.render - tSt; 1269 tSt = performance.now(); 1270 } 1271 1272 hdr.replaceChild(newMenu, _id('list_menu') ); 1273 // rebind events 1274 if ( t = _id('list_sizer') ) { 1275 t.addEventListener('mousedown', oList.resizeMD, false); 1276 if (isTouch) 1277 t.addEventListener('touchstart', oList.resizeTS, false); 1278 }; 1279 1280 if (len > 2000) { 1281 t = newUL.cloneNode(false); 1282 oList.nav.replaceChild(t, oldUL); 1283 oLoad.cancel = false; 1284 listLoadSplit(newUL, t, 1000, 4000, listLoadDone, oLoad); 1285 } else { 1286 setTimeout(listLoadDone, 15); 1287 oList.nav.replaceChild(newUL, oldUL); 1288 } 1289 newUl = null; 1290} 1291 1292//} @!endgroup 1293 1294//{ @!group oList Search Functions 1295 1296/* Event handler for oList search input change */ 1297function listSearchChg(e) { 1298 var text = e ? e.target.value.trim() : _id('list_search_text').value.trim(), 1299 t; 1300 1301 if (text !== '') { 1302 // IE issue ? 1303 if ( 'classList' in _id('list_search_icon') ) { 1304 _id('list_search_icon').classList.add('s_clr'); 1305 } else { 1306 _id('list_search_icon').className = 's_clr'; 1307 }; 1308 if (listLastSearchText !== text) listSearchCancel(); 1309 listLastSearchText = text; 1310 listSearchExec(text); 1311 } else { 1312 listSearchClear(); 1313 } 1314} 1315 1316/* Event handler for oList search input keypress */ 1317function listSearchKP(e) { 1318 var key = String.fromCharCode(e.which); 1319 if ( !RE_LIST_SEARCH.test(key) ) { 1320 e.stopPropagation(); 1321 return true; 1322 } 1323} 1324 1325function listSearchCancel() { 1326 for (var i = 0, o; o = oSearches[i]; i++) { 1327 if (o && o.running) o.cancel = true; 1328 } 1329} 1330 1331/* Clears List search list 1332 */ 1333function listSearchClear() { 1334 var t; 1335 oList.itemsSearch = 0; 1336 _id('list_search_text').value = ''; 1337 if ( 'classList' in _id('list_search_icon') ) { 1338 _id('list_search_icon').classList.remove('s_clr'); 1339 } else { 1340 _id('list_search_icon').className = ''; 1341 }; 1342 oListData[listCurPN].search = ''; 1343 setWait(CB_LIST); 1344 setTimeout( function() { 1345 listSearchCancel(); 1346 if (t = _id('list_search_items') ) oList.nav.removeChild(t); 1347 oList.items.style.display = ''; 1348 oList.clickedA = null; 1349 oList.clickedLI = null; 1350 if (clickedBy === CB_LIST) clickedBy = null; 1351 if (aDOMCur) list_ShowClicked(aDOMCur); 1352 setWait(); 1353 }, 10); 1354} 1355 1356/* Create elements from search result array 1357 * @param list [<object>] 1358 * @param re [RegEx] regex string for highlighting search result text 1359 */ 1360function listSearchCreate(list, re) { 1361 var li = document.createElement('li'), 1362 docFrag = document.createDocumentFragment(), 1363 a, findText, replText, inHTML, 1364 emptyRe = re.test(''); 1365 1366 for (var i = 0, sObj, small, newLI; sObj = list[i]; i++) { 1367 newLI = li.cloneNode(false); 1368 1369 a = sObj.a.cloneNode(true); 1370 findText = a.firstChild.textContent; 1371// txt = findText.replace(/&/g, '&'); 1372// txt = txt.replace(/</g, '<'); 1373 txt = findText.replace(/</g, '<'); 1374 txt = txt.replace(/>/g, '>'); 1375 1376 replText = txt.replace(re, "<em>$1</em>"); 1377 1378 if (!emptyRe) { 1379 a.innerHTML = a.textContent.replace(findText, replText); 1380 }; 1381 1382 newLI.appendChild(a); 1383 if (sObj.small) { 1384 small = sObj.small.cloneNode(true); 1385 small.className = ''; 1386 small.textContent = small.textContent.trim(); 1387 newLI.appendChild( small ); 1388 } 1389 if (sObj.cl) { 1390 newLI.className = sObj.cl; 1391 if (i % 2 === 0) newLI.classList.add('odd'); 1392 else newLI.classList.add('even'); 1393 } else { 1394 if (i % 2 === 0) newLI.className = 'odd'; 1395 else newLI.className = 'even'; 1396 } 1397 docFrag.appendChild(newLI); 1398 } 1399 return docFrag; 1400} 1401 1402/* Performs the List search
1403 * @note If result set is large, calls {listLoadSplit} so UI is responsive 1404 * while loading search results. This allows search input text changes to 1405 * cancel the search result display. 1406 * @param text [String] text string to search for 1407 */ 1408function listSearchExec(text) { 1409 var re, 1410 results, 1411 ul = document.createElement('ul'), 1412 oldUl, 1413 txt, pre, t, 1414 isStart, 1415 reNS, 1416 ld = oListData[listCurPN], 1417 tSt = performance.now(), tS; 1418 1419 text = text.replace(/\s+/g, ''); 1420 ld.search = text; 1421 1422 1423 if ( t2Info.NSEP === '::' && text.match(/[a-z][\.#]\S/i) ) { 1424 aText = text.split(/[\.#]/); 1425 } else { 1426 aText = text.split(t2Info.NSEP); 1427 } 1428 if (aText.length === 2) { 1429 reNS = new RegExp(aText[0]); 1430 text = aText[1]; 1431 } else if (aText.length > 2) { 1432 text = aText.pop(); 1433 reNS = new RegExp( aText.join("([^:]*" + t2Info.NSEP + "[^:]*)+?") ); 1434 } else { 1435 reNS = null; 1436 }; 1437 1438 pre = text.charAt(0); 1439 if (pre === t2Info.CSEP || pre === t2Info.ISEP) { 1440 text = text.slice(1); 1441 if (pre === '.') pre = '\\.'; 1442 } else pre = null; 1443 1444 // isStart = ( /^[^!=?<>+|*\^\]_]/.test(text.charAt(0)) && ( 1445 // text.charAt(0) === text.charAt(0).toUpperCase() ) ); 1446 isStart = /[A-Z]/.test(text.charAt(0)); 1447 1448 1449 // create RegEx for search, dependent on whether 1st letter is uppercase 1450 // escapes ? * + ^ | . $ [ ] ( ) { } in search string 1451 txt = text.replace(/([\?*+^|\.\$\[\]\(\)\{\}])/g, "\\$1"); 1452 if (isStart) { 1453 if (ld.type === LIST_METHOD) { 1454 if (pre) 1455 re = new RegExp('^' + pre + txt, 'i'); 1456 else 1457 re = new RegExp('(^#' + txt + '|^\\.' + txt + '|^' + txt + ')', 'i'); 1458 } else 1459 re = new RegExp('^' + txt, 'i'); 1460 } else { 1461 if (ld.type === LIST_METHOD && pre ) { 1462 re = new RegExp('^' + pre + '.*?' + txt, 'i'); 1463 } else { 1464 re = new RegExp(txt, 'i'); 1465 } 1466 } 1467 if (reNS) { 1468 results = ld.searchInfo.filter( function (o) { return (re.test(o.text) && 1469 !!o.small && reNS.test(o.small.textContent)); } ); 1470 } else { 1471 results = ld.searchInfo.filter( function (o) { return re.test(o.text); } ); 1472 } 1473 1474 oList.itemsSearch = results.length; 1475 1476 if (oList.itemsSearch > 0) { 1477 // sort objects via name then namespace 1478 if (oList.isOpenClose) { 1479 results = results.sort( function(a, b) { 1480 var at = a.text.toLowerCase(), 1481 bt = b.text.toLowerCase(), 1482 as = a.small ? a.small.textContent : '', 1483 bs = b.small ? b.small.textContent : ''; 1484 1485 if (at > bt) return 1; 1486 else if (at < bt) return -1; 1487 else if (as > bs) return 1; 1488 else if (bs > as) return -1; 1489 else return 0; 1490 } ); 1491 } 1492 1493 if (ld.type === LIST_UNKNOWN || ld.type === LIST_FILE) 1494 ul.className = 'file'; 1495 else 1496 ul.className = LIST_ENUM[LIST_METHOD]; 1497 1498 // Create RegEx (re) for search string highlight 1499// txt = txt.replace(/&/g, '&'); 1500 txt = txt.replace(/</g, '<'); 1501 txt = txt.replace(/>/g, '>'); 1502 if (isStart) { 1503 if (oListData[listCurPN].type === LIST_METHOD) { 1504 if (pre) 1505 re = new RegExp('^(' + pre + txt + ')', 'i'); 1506 else 1507 re = new RegExp('^([#\.]?' + txt + ')', 'i'); 1508 } else 1509 re = new RegExp('^(' + txt + ')', 'i'); 1510 } else { 1511 re = new RegExp('(' + txt + ')', 'ig'); 1512 } 1513 } 1514 1515 if (dbgSearchLoad) { 1516 tS = fmtTL(performance.now() - tSt, oList.itemsSearch); 1517 console.log('Search exec ' + tS + ' ' + text); 1518 } 1519 1520 oList.items.style.display = 'none'; 1521 ul.id = 'list_search_items'; 1522 oldUl = _id('list_search_items'); 1523 // If less than 600 matches, throw them all in, otherwise use splitLoad 1524 if (oList.itemsSearch < 600) { 1525 ul.appendChild( listSearchCreate(results, re) ); 1526 if (oldUl) 1527 oList.nav.replaceChild(ul, oldUl); 1528 else 1529 oList.nav.appendChild(ul); 1530 listSearchExec2(); 1531 } else { 1532 var sUL = ul.cloneNode(false), 1533 oSearch = { 1534 list: results, 1535 re: re, 1536 ul: sUL, 1537 qty: 200, 1538 text: text, 1539 running: true, 1540 cancel: false, 1541 cb: listSearchExec2 1542 }; 1543 oSearches.push(oSearch); 1544 if (oldUl) oList.nav.replaceChild(sUL, oldUl); 1545 else oList.nav.appendChild(sUL); 1546 listSearchSplit(oSearch); 1547 } 1548 t = null; 1549} 1550 1551/* Callback function needed for when search display {listLoadSplit} completes. */ 1552function listSearchExec2() { 1553 var len = oSearches.length - 1, 1554 o; 1555 if (oList.itemsSearch > 0) { 1556 oList.clickedA = null; 1557 oList.showClicked(aDOMCur); 1558 if (!oList.clickedLI) oList.nav.scrollTop = 0; 1559 } 1560 if (len >= 0) { 1561 for (var i = len; i >= 0; i--) { 1562 o = oSearches[i]; 1563 if (o && !o.running) { 1564 o = null; 1565 oSearches.pop(); 1566 } 1567 } 1568 } 1569} 1570 1571/* Splits loading of LI elements when list is large, better UI responsiveness. 1572 * @note Used for both large (+2,000) lists and large (+500) search result sets. 1573 * @param xhrEl [HTMLElement] element with children to copy from (from xhr frag) 1574 * @param docEl [HTMLElement] element to add children to (in document) 1575 * @param qty [Integer] number of children to load in each loop 1576 * @param cbFunc [Function] callback function called when all children have 1577 * been loaded/moved 1578 * @param oState [object] object to pass run to app, and cancel from app 1579 */ 1580function listSearchSplit(o) { 1581 var tmrFunc, 1582 tmrIds = [], 1583 list, 1584 len; 1585 1586 var tSt = performance.now(), tS; 1587
1588 tmrFunc = function() { 1589 return function() { 1590 if (o.list.length > 0) { 1591 list = o.list.splice(0, o.qty); 1592 o.ul.appendChild( listSearchCreate(list, o.re) ); 1593 if (!o.cancel) { 1594 if (o.list.length > 0) { 1595 if (dbgSearchSplit) { 1596 tS = fmtTL(performance.now() - tSt, o.list.length + 0); 1597 console.log('Search split ' + tS + ' ' + 1598 LIST_ENUM[oListData[listCurPN].type] + ' ' + o.text); 1599 } 1600 tmrIds.push(setTimeout(tmrFunc, 20)); 1601 } else { 1602 o.running = false; 1603 if (o.cb !== undefined) setTimeout(o.cb, 0); 1604 return; 1605 } 1606 } else { 1607 len = tmrIds.length; 1608 if (len > 0) { 1609 for (var i = 0; i < len; i++) { 1610 if (tmrIds[i]) clearTimeout(tmrIds[i]); 1611 } 1612 } 1613 setWait(-1); 1614 o.running = false; 1615 if (dbgSearchSplit) { 1616 tS = fmtTL(performance.now() - tSt, o.list.length); 1617 console.log('Search split ' + tS + ' ' + 1618 LIST_ENUM[oListData[listCurPN].type] + ' Cancel'); 1619 } 1620 } 1621 } 1622 }; 1623 }(); 1624 tmrIds.push(setTimeout(tmrFunc, 0)); 1625} 1626 1627/* Loads ld.searchInfo array, sets all href's to the correct path 1628 * @param ul [HTMLUListElement] the top UL element to parse 1629 * @param menu [HTMLDivElement] the list menu element 1630 */ 1631function listSearchLoad(ld) { 1632 var nl = ld.list.querySelectorAll('a'), 1633 cl, 1634 tSt = performance.now(), tEnd; 1635 1636 ld.searchInfo = []; 1637 // Load searchInfo and set list href's 1638 if (isServer) { 1639 for (var i = 0, eA, sObj, _small, eLI; eA = nl[i]; i++) { 1640 _small = eA.nextElementSibling; 1641 if (_small && _small.tagName === 'SMALL') 1642 sObj = { a: eA, small: _small, text: eA.childNodes[0].textContent }; 1643 else { 1644 sObj = { a: eA, small: null , text: eA.childNodes[0].textContent }; 1645 1646 } 1647 if (eLI = getPrntByIO(eA, HTMLLIElement)) { 1648 cl = eLI.className.replace(/even|odd/, '').trim(); 1649 if (cl !== '') sObj.cl = cl; 1650 } 1651 if ( eA.classList.contains('nodoc') ) sObj.cl += ' nodoc'; 1652 ld.searchInfo.push(sObj); 1653 } 1654 } else { 1655 for (var i = 0, eA, sObj, _small, eLI; eA = nl[i]; i++) { 1656 eA.setAttribute('href', listPath + eA.getAttribute('href') ); 1657 _small = eA.nextElementSibling; 1658 if (_small && _small.tagName === 'SMALL') 1659 sObj = { a: eA, small: _small, text: eA.childNodes[0].textContent }; 1660 else { 1661 sObj = { a: eA, small: null , text: eA.childNodes[0].textContent }; 1662 }; 1663 if (eLI = getPrntByIO(eA, HTMLLIElement)) { 1664 cl = eLI.className.replace(/even|odd/, '').trim(); 1665 if (cl !== '') sObj.cl = cl; 1666 }; 1667 if ( eA.classList.contains('nodoc') ) sObj.cl += ' nodoc'; 1668 ld.searchInfo.push(sObj); 1669 }; 1670 // Set list menu href's 1671 nl = ld.menu.querySelectorAll('a'); 1672 for (var i = 0, eA; eA = nl[i]; i++) { 1673 eA.setAttribute('href', listPath + eA.getAttribute('href') ); 1674 }; 1675 }; 1676 1677 if (dbgSearchLoad) { 1678 tEnd = performance.now() - tSt; 1679 console.log('Search load ' + fmtTL(tEnd, oList.itemQty) + 1680 ' ' + LIST_ENUM[ld.type]); 1681 } 1682} 1683 1684//} @!endgroup 1685 1686//{ @!group oToc Functions 1687 1688/* Generates a table of contents and returns the new OL element 1689 * @param content [HTMLElement] the node containg the doc content 1690 * @param isCode [Boolean] true is the doc is a 'code' doc 1691 * @return [HTMLOLElement] an OL element filled with TOC info 1692 */ 1693function toc_Generate(content, isCode) { 1694 var cA = document.createElement('a'), 1695 cBTN = document.createElement('button'), 1696 cDIV = document.createElement('div'), 1697 cLI = document.createElement('li'), 1698 cOL = document.createElement('ol'), 1699 a, div, li, ol, 1700 _toc = cOL.cloneNode(false), 1701 toc = _toc, 1702 counter = 0, 1703 tags = ['h2', 'h3', 'h4', 'h5', 'h6'], 1704 level = 0, 1705 nl, 1706 hTags = [], 1707 proposedId, 1708 qs, 1709 lastLvl, 1710 prntIsH2Details, 1711 thisLvl, 1712 nextLvl, 1713 thisIsA, 1714 thisIsH2Details, 1715 nextIsA, 1716 title, 1717 tmp, tmp1, 1718 itemHref, 1719 elCL, 1720 cls, 1721 leaveOpenLvl = 2; 1722 1723 oToc.clickedA = null; 1724 oToc.clickedLI = null; 1725 if (content.childNodes === 0) return; 1726 1727 if (isCode) tocSearchLoad(content); 1728 1729 cDIV.appendChild( cBTN.cloneNode(false) ); 1730 1731 _toc.id = 'toc_items'; 1732 _toc.className = 'class lvl0'; 1733 1734 tmp = content.querySelectorAll('h1').length - 1735 content.querySelectorAll('h1.title').length - 1736 content.querySelectorAll('h1.alphaindex').length; 1737 1738 if (tmp > 1) { 1739 tags.unshift('h1'); 1740 leaveOpenLvl = 1; 1741 } 1742 1743 lastLvl = parseInt(tags[0][1], 10); 1744// tmp = tags.join(', ') + (isCode ? ', ul.summary.compact:not(.constants) a' : ''); 1745 tmp = tags.join(', '); 1746 nl = content.querySelectorAll(tmp); 1747 // load nl into array hTags 1748 for (var i = 0, el; el = nl[i]; i++) { hTags.push(el); }; 1749 1750 // now, loop array 1751 for (var i = 0, el; el = hTags[i]; i++) { 1752 thisIsA = (isCode && el instanceof HTMLAnchorElement) 1753 1754// if (getPrntByIO(el, HTMLUListElement, true).classList.contains('constants')) 1755// continue; 1756 1757 thisLvl = thisIsA ? 3 : parseInt(el.tagName[1], 10); 1758 1759 thisIsH2Details = (isCode && thisLvl === 2 && 1760 (el.classList.contains('y_details') || el.textContent.match(/Details$/i))); 1761 1762 if ( !thisIsH2Details && prntIsH2Details && 1763 !el.classList.contains('signature') ) { 1764 continue; 1765 } 1766 1767 if (isCode && !thisIsA && thisLvl > 3 && 1768 (getPrntByIO(el, HTMLLIElement) instanceof HTMLLIElement)) { 1769 continue; 1770 } 1771 1772//console.log(thisLvl + ' ' + (thisIsA ? 'T' : 'F') + ' ' + 1773// ( (getPrntByIO(el, HTMLLIElement) instanceof HTMLLIElement) ? 'LI ' : ' ') + el.textContent); 1774 1775 // nextLvl info, skip if in Code Details 1776 if (hTags[i+1] && (!isCode || (thisIsH2Details || !prntIsH2Details) )) { 1777// if (hTags[i+1] && (!isCode || (thisIsH2Details && !prntIsH2Details) )) { 1778 tmp = hTags[i+1]; 1779 if (isCode && tmp instanceof HTMLAnchorElement) { 1780 nextIsA = true; 1781 nextLvl = 3; 1782 } else if (isCode && !(getPrntByIO(tmp, HTMLLIElement) instanceof HTMLLIElement)) { 1783 nextLvl = parseInt(tmp.tagName[1], 10); 1784 } else if (!isCode) nextLvl = parseInt(tmp.tagName[1], 10); 1785 } else nextLvl = thisLvl; 1786 1787 // need something for rendered objects in md files ?? 1788 1789 if (thisIsA) { 1790 // el is a 'summary.compact a', no children, title already parsed 1791 a = el.cloneNode(false); 1792 a.textContent = el.textContent; 1793 li = cLI.cloneNode(false); 1794 } else { 1795 // Get text for toc entry 1796 if (isCode) { 1797 title = tocCodeTitle(el, content, cls); 1798 cls = ''; 1799 elCL = el.classList; 1800 if (thisLvl === 3 && elCL.contains('signature')) { 1801 // set up classes for method type indicators
1802 if (el.querySelector('strong.nodoc, div.note.nodoc') || 1803 el.classList.contains('nodoc')) 1804// (el.nextElementSibling && 1805// el.nextElementSibling.classList.contains('nodoc')) ) 1806 cls += 'nodoc '; 1807 if (el.parentElement.querySelector('div.note.deprecated')) 1808 cls += 'deprecated '; 1809 if (el.querySelector('span.readonly')) cls += 'ro '; 1810 if (elCL.contains('rw')) cls += 'rw '; 1811 if (el.querySelector('span.writeonly')) cls += 'wo '; 1812 if (el.querySelector('span.priv')) cls += 'priv '; 1813 if (el.querySelector('span.prot')) cls += 'prot '; 1814 if (el.querySelector('span.mod_func')) cls += 'mf '; 1815 cls = cls.trim(); 1816 } 1817 } else { 1818 title = el.getAttribute('toc-title') || el.textContent; 1819 } 1820 // Set id on h tag if undefined 1821 if (isCode && thisLvl === 3 && el.parentElement.tagName === 'SECTION') { 1822 itemHref = el.parentElement.id; 1823 } else { 1824 itemHref = el.id; 1825 } 1826 if (itemHref.length === 0) { 1827 proposedId = el.getAttribute('toc-id') || el.textContent.toLowerCase().replace(/& /g, '-').replace(/[^a-z0-9-]+/g, '-'); 1828 qs = /^[0-9]/.test(proposedId) ? '#\\' : '#'; 1829 if ( /^-/.test(proposedId) ) proposedId = "_" + proposedId; 1830 if (proposedId === null || proposedId === '' || 1831 content.querySelector(qs + proposedId) ) { 1832 proposedId = title.toLowerCase().replace(/& /g, '-').replace(/[^a-z0-9-]+/g, '-'); 1833 // selectors can't start with an unescaped number 1834 if ( /\s*/.test(proposedId) ) proposedId = "_" + counter; counter++; 1835 qs = /^[0-9]/.test(proposedId) ? '#\\' : '#'; 1836 if ( content.querySelector(qs + proposedId) ) 1837 proposedId += counter; counter++; 1838 } 1839 el.id = proposedId; 1840 itemHref = proposedId; 1841 1842 } 1843 // load a with title & href 1844 a = cA.cloneNode(false); 1845 if (cls !== '' && cls !== undefined) a.className = cls; 1846 a.setAttribute('href','#' + itemHref); 1847 1848 if ( el.classList.contains('inherited') && /ed$/.test(title) && / - /.test(title) ) { 1849 tmp = document.createTextNode(/^\S+/.exec(title) + ' - '); 1850 a.appendChild(tmp); 1851 tmp = document.createElement("I"); 1852 tmp.textContent = /\S+$/.exec(title); 1853 a.appendChild(tmp); 1854 } else a.textContent = title; 1855 1856 // move back up 1857 if (thisLvl < lastLvl && toc) { 1858 for (var k = 0, newToc; k < lastLvl - thisLvl; k++) { 1859 level --; 1860 toc = getPrntByIO(toc, HTMLOListElement, true); 1861 } 1862 } 1863 } 1864 li = cLI.cloneNode(false); 1865 1866 if (thisLvl < nextLvl) { 1867 // Has children, needs buttons, div, ol, etc 1868 level ++ 1869 if (thisLvl > leaveOpenLvl) li.className = CN_CLOSED; 1870 1871 div = cDIV.cloneNode(true); 1872 div.appendChild(a); 1873 li.appendChild(div); 1874 1875 ol = cOL.cloneNode(); 1876 ol.className = 'lvl' + level; 1877 li.appendChild(ol); 1878 for (var k = thisLvl + 1, t; k < nextLvl; k++) { 1879 level++; 1880 t = cOL.cloneNode(); 1881 t.className = 'lvl' + level; 1882 ol.appendChild(t); 1883 ol = t; 1884 } 1885 if (toc) toc.appendChild(li); 1886 toc = ol; 1887 } else { 1888 li.appendChild(a); 1889// if (cls !== '') li.className = cls; 1890// toc.appendChild(li); 1891 if (toc) toc.appendChild(li); 1892 } 1893 lastLvl = thisLvl; 1894 if (isCode) 1895 prntIsH2Details = prntIsH2Details || thisIsH2Details; 1896 } 1897 1898 // Done with toc, check for summary vs detail children, and maybe remove some 1899 //if (isCode) tocRemoveSummaryChildren(_toc); 1900 1901 oToc.isOpenClose = (_toc.querySelector('button') !== null); 1902// oToc.nav.replaceChild(_toc, oToc.items); 1903// oToc.items = _id('toc_items'); 1904 return _toc; 1905} 1906 1907/* Highlights an item in the TOC pane 1908 * @param aDOM [HTMLAnchorElement] anchor with object / url info, 1909 * only the hash is used 1910 */ 1911function toc_ShowClicked(aDOM) { 1912 var qs = 'a[href="' + decodeURIComponent(aDOM.hash.replace(/%-/, '%25-')) + '"]', 1913 eA = oToc.items.querySelector(qs); 1914 1915 if (clickedBy === CB_TOC) { 1916 if (oToc.clickedLIOld) { 1917 oToc.clickedLIOld.classList.remove(CN_CLICKED); 1918 oToc.clickedLIOld = null; 1919 } 1920 if (oToc.clickedLI) oToc.clickedLI.classList.add(CN_CLICKED); 1921 return; 1922 } 1923 paneScrollTo(oToc, eA); 1924}; 1925 1926/* Event handler for TOC header click */ 1927function tocClkHeader(e) { 1928 var tgt = e.target, 1929 tag = tgt.tagName, 1930 cancel = false;
1931 1932 settingsCheck(); 1933 switch (tag) { 1934 case 'BUTTON': 1935 if (tgt.id !== 'toc_sizer') 1936 paneOC(oToc, (tgt.className === 'y_plus')); 1937 cancel = true; 1938 break; 1939 case 'path': 1940 tag = 'svg'; 1941 tgt = tgt.parentElement; 1942 /* falls through */ 1943 case 'svg': 1944 if (tgt.id === 'toc_search_icon') { 1945 tocSearchClear(); 1946 cancel = true; 1947 } 1948 break; 1949 } 1950 if (cancel) { 1951 e.stopPropagation(); 1952 e.preventDefault(); 1953 return false; 1954 } 1955} 1956 1957/* Used with code documents, generates a table of contents entry from an element 1958 * @param el [HTMLElement] element to extract title from 1959 * @return [String] TOC title / entry 1960 */ 1961function tocCodeTitle(el) { 1962 var title = ( el.getAttribute('toc-title') || el.textContent).trim(), 1963 thisLvl = parseInt(el.tagName[1], 10), 1964 rePlus = /^[\+\*\|\^]/, 1965 re, 1966 titleMain, 1967 titleSuf, 1968 pre = '', 1969 prnt, 1970 prntId, 1971 t; 1972 1973 if (thisLvl === 2) { 1974 // removes small text, typically expand / collapse 1975 if (t = el.querySelector('small')) { 1976 titleSuf = t.textContent; 1977 if (titleSuf) { 1978 title = title.replace(titleSuf, '').trim(); 1979 } 1980 } 1981 title = title.replace(/Attributes & Methods/, 'A & M'); 1982 } else if (thisLvl === 3) { 1983 if ( el.classList.contains('signature') ) { 1984 if ( el.classList.contains('aws_waiter') ) { 1985 title = el.querySelector('strong').textContent.replace(/'/g, ''); 1986 } else { 1987 // check id of section element 1988 prnt = el.parentElement; 1989 if (prnt.tagName === 'SECTION' && 1990 prnt.classList.contains('method_details') ) { 1991 prntId = prnt.id; 1992 1993 if ( t = el.querySelector('strong') ) { 1994 if (t.previousSibling && t.previousSibling.nodeType === 3 ) 1995 pre = t.previousSibling.nodeValue.trim(); 1996 } 1997 1998 if ( RE_METH_CLS.test(prntId) ) 1999 title = pre + prntId.replace(RE_METH_CLS, ''); 2000 else if ( RE_METH_INST.test(prntId) ) 2001 title = pre + prntId.replace(RE_METH_INST, ''); 2002 2003// title = t2Info.CSEP + prntId.replace(RE_METH_CLS, ''); 2004// title = t2Info.ISEP + prntId.replace(RE_METH_INST, ''); 2005 2006 if (title) return title.replace(/[\(\s].*$/, ''); 2007 } 2008 2009 if (t = el.querySelector('small')) { 2010 title = title.replace(t.textContent, '').trim(); 2011 } 2012 title = title.replace(/[( ][\s\S]*$/g, ''); 2013 if (t = el.querySelector('strong')) { 2014 titleMain = t.textContent.replace(/\?/, "\\?"); 2015 if ( rePlus.test(titleMain) ) 2016 re = new RegExp('[#.]?\\' + titleMain); 2017 else 2018 re = new RegExp('[#.]?' + titleMain); 2019 if ( t = title.match(re) ) title = t[0]; 2020 } 2021 } 2022 } else if ( el.classList.contains('inherited') ) { 2023 title = title.replace(/^.*?(inherited|included)[ ]+from/, "<i>$1 -"); 2024 } 2025 } 2026 title = title.trim(); 2027 return title; 2028} 2029 2030/* Removes children from 'Summary' entries if they are similar to the 'Details' 2031 * entries 2032 * @param toc [HTMLOLElement] 2033 */ 2034function tocRemoveSummaryChildren(toc) { 2035 var RE_SUMMARY = / Summary$/, 2036 RE_DETAILS = / Details$/, 2037 summaries = [], 2038 details = [], 2039 checked, 2040 nl, i, j, txtS, txtD, el, elS, elD, qtyS, qtyD, a, t; 2041 2042 nl = toc.childNodes; 2043 for (i = 0; el = nl[i]; i++) { 2044 txtS = el.firstElementChild.textContent; 2045 // push all entries that end in SUMMARY or DETAILS to arrays 2046 if (RE_SUMMARY.test(txtS)) summaries.push(el); 2047 if (RE_DETAILS.test(txtS)) details.push(el); 2048 } 2049 // loop thru summaries and look for matching details 2050 for (i = 0; elS = summaries[i]; i++) { 2051 checked = false; 2052 txtS = elS.firstElementChild.textContent.replace(RE_SUMMARY, ''); 2053 for (j = 0; elD = details[j]; j++) { 2054 txtD = elD.firstElementChild.textContent.replace(RE_DETAILS, ''); 2055 if (txtD === txtS) { 2056 nl = elS.querySelectorAll('ol > li'); 2057 qtyS = nl.length - elS.querySelectorAll('a > i').length; 2058 qtyD = elD.querySelectorAll('ol > li').length; 2059 2060 if (qtyS + 1 >= qtyD) { 2061 if ( elS.querySelector('a > i') ) { 2062 console.log('Remove ' + txtS); 2063 nl = elS.querySelectorAll('li'); 2064 console.log(txtS + ' ' + nl.length); 2065 for (var k = 0, el; el = nl[k]; k++) { 2066 if ( !el.querySelector('a > i') ) 2067 el.parentElement.removeChild(el); 2068 } 2069 } else { 2070 if ( t = elS.querySelector('ol') ) elS.removeChild(t); 2071 a = elS.querySelector('a').cloneNode(true); 2072 if (t = elS.querySelector('div')) 2073 elS.removeChild(t); 2074 elS.className = ''; 2075 elS.appendChild(a); 2076 } 2077 } 2078 // break because a match was found 2079 break; 2080 checked = true; 2081 } 2082 } 2083 // Probably a constructor in class methods 2084 if (!checked && elS.querySelectorAll('ol > li').length === 1) { 2085 elS.removeChild(elS.querySelector('ol')); 2086 a = elS.querySelector('a').cloneNode(true); 2087 elS.removeChild(elS.querySelector('div')); 2088 elS.className = ''; 2089 elS.appendChild(a); 2090 } 2091 } 2092} 2093 2094//} @!endgroup 2095 2096//{ @!group oToc Search Functions 2097 2098/* Event handler for oList search input keypress */ 2099function tocSearchKP(e) { 2100 var key = String.fromCharCode(e.which); 2101 if ( !RE_LIST_SEARCH.test(key) ) { 2102 e.stopPropagation(); 2103 return true; 2104 } 2105} 2106 2107function tocSearchCancel() { 2108 // console.log('tocSearchCancel'); 2109}; 2110 2111/* Event handler for oTOC search input change */ 2112function tocSearchChg(e) { 2113 var text = e ? e.target.value.trim() : _id('toc_search_text').value.trim(), 2114 t; 2115 2116 if (text !== '') { 2117 _id('toc_search_icon').classList.add('s_clr'); 2118 if (tocLastSearchText !== text) { 2119 tocSearchCancel(); 2120 } 2121 tocLastSearchText = text; 2122 tocSearchExec(text); 2123 } else { 2124 tocSearchClear(); 2125 } 2126} 2127 2128/* Clears Toc search list 2129 */ 2130function tocSearchClear() { 2131 var t; 2132 //oList.itemsSearch = 0; 2133 _id('toc_search_text').value = ''; 2134 _id('toc_search_icon').classList.remove('s_clr'); 2135 setWait(CB_LIST); 2136 setTimeout( function() { 2137 if (t = _id('toc_search_items') ) oToc.nav.removeChild(t); 2138 oToc.items.style.display = ''; 2139 oToc.clickedA = null; 2140 oToc.clickedLI = null; 2141 if (aDOMCur) toc_ShowClicked(aDOMCur); 2142 setWait(); 2143 }, 10); 2144} 2145 2146/* Creates the html DocFrag of search results 2147 * @param [array] array of search matches 2148 * @param [re] regex for text highlighting 2149 * @return [DocumentFragment] 2150 */ 2151function tocSearchCreate(list, re) { 2152 var li = document.createElement('li'), 2153 aa = document.createElement('a'), 2154 ss = document.createElement('small'), 2155 docFrag = document.createDocumentFragment(), 2156 a, sml, 2157 findText, replText, inHTML; 2158 2159 for (var i = 0, sObj, newLI; sObj = list[i]; i++) { 2160 newLI = li.cloneNode(false); 2161 a = aa.cloneNode(false); 2162 2163 findText = sObj.text; 2164 txt = findText.replace(/&/g, '&'); 2165 txt = txt.replace(/</g, '<'); 2166 txt = txt.replace(/>/g, '>'); 2167 2168 sml = ss.cloneNode(false); 2169 sml.textContent = sObj.small; 2170 2171 a.innerHTML = txt.replace(re, "<em>$1</em>"); 2172 a.href = sObj.href; 2173 newLI.className = sObj.cls; 2174 2175 newLI.appendChild(a); 2176 newLI.appendChild(sml); 2177 2178 docFrag.appendChild(newLI); 2179 } 2180 return docFrag; 2181} 2182 2183/* Performs the TOC search
2184 * @param text [String] text string to search for 2185 */ 2186function tocSearchExec(text) { 2187 var re, 2188 results, 2189 ul = document.createElement('ul'), 2190 oldUl, 2191 txt, pre, t, 2192 isStart, 2193 reNS, 2194 tSt = performance.now(), tS; 2195 2196 text = text.replace(/\s+/g, ''); 2197 2198 pre = text.charAt(0); 2199 if (pre === t2Info.CSEP || pre === t2Info.ISEP) { 2200 text = text.slice(1); 2201 if (pre === '.') pre = '\\.'; 2202 } else pre = null; 2203 2204 isStart = /[A-Z]/.test(text.charAt(0)); 2205 2206 // create RegEx for search, dependent on whether 1st letter is uppercase 2207 // escapes ? * + ^ | . $ [ ] ( ) { } in search string 2208 txt = text.replace(/([\?*+^|\.\$\[\]\(\)\{\}])/g, "\\$1"); 2209 if (isStart) { 2210 if (pre) 2211 re = new RegExp('^' + pre + txt, 'i'); 2212 else 2213 re = new RegExp('(^' + re_csep + txt + '|^' + re_isep + txt + '|^' + txt + ')', 'i'); 2214 } else { 2215 if (pre) 2216 re = new RegExp('^' + pre + '.*?' + txt, 'i'); 2217 else 2218 re = new RegExp(txt, 'i'); 2219 } 2220 results = tocSearchInfo.filter( function (o) { return re.test(o.text); } ); 2221 2222 if (results.length > 0) { 2223 // sort objects via name then namespace 2224 results = results.sort(); 2225 2226 ul.className = LIST_ENUM[LIST_METHOD]; 2227 2228 // Create RegEx (re) for search string highlight 2229 txt = txt.replace(/&/g, '&'); 2230 txt = txt.replace(/</g, '<'); 2231 txt = txt.replace(/>/g, '>'); 2232 if (isStart) { 2233 if (pre) 2234 re = new RegExp('^(' + pre + txt + ')', 'i'); 2235 else 2236 re = new RegExp('^([#\.]?' + txt + ')', 'i'); 2237 } else { 2238 re = new RegExp('(' + txt + ')', 'ig'); 2239 } 2240 } 2241 2242 if (dbgSearchLoad) { 2243 tS = fmtTL(performance.now() - tSt, results.length); 2244 console.log('Search exec ' + tS + ' ' + text); 2245 } 2246 2247 oToc.items.style.display = 'none'; 2248 ul.id = 'toc_search_items'; 2249 oldUl = _id('toc_search_items'); 2250 ul.appendChild( tocSearchCreate(results, re) ); 2251 if (oldUl) 2252 oToc.nav.replaceChild(ul, oldUl); 2253 else 2254 oToc.nav.appendChild(ul); 2255// listSearchExec2(); 2256 2257// t = null; 2258} 2259 2260/* Used for tocSearchInfo array. Mostly so results sort can be done using 2261 * @param cls [String] 2262 */ 2263function TocSObj(cls, href, idx, small, text) { 2264 this.cls = cls; 2265 this.href = href; 2266 this.idx = idx; 2267 this.small = small; 2268 this.text = text; 2269} 2270 2271TocSObj.prototype.toString = function TocSObjToString() { 2272// return this.text.replace(re_meth_sep, '').toLowerCase() + 2273// (" " + this.idx).slice(-5); 2274 return this.text.replace(re_meth_sep, '').toLowerCase(); 2275}; 2276 2277/* Loads an array of TocSObj objects with method info. 2278 */ 2279function tocSearchLoad(content) { 2280 var int_meths = content.querySelectorAll('ul.compact a'), 2281 ext_meths = content.querySelectorAll('a.i_m'), 2282 i, j, el, cls, small, 2283 reMethTrim = new RegExp( '(' + re_csep + '|' + re_isep + ')\\S+?$' ); 2284 2285 tocSearchInfo = []; 2286 for (j = 0; el = int_meths[j]; j++) { 2287 tocSearchInfo.push( new TocSObj(el.className, el.href, i + j, '', el.textContent) ); 2288 } 2289 2290 for (i = 0; el = ext_meths[i]; i++) { 2291 cls = el.className.replace(/private/, 'priv').replace(/protected/, 'prot'); 2292 2293 new_id = decodeURIComponent(el.getAttribute('href')); 2294 new_id = new_id.replace(/(\.html)?#/, '_'); 2295 new_id = new_id.replace(/^\.+\//, ''); 2296 new_id = new_id.replace(/\//g, '_'); 2297 2298 el.id = new_id; 2299 2300 cls = cls.replace(/i_m /, '').trim(); 2301 small = el.title.match(/^\S+/)[0]; 2302 if (small) small = small.replace(reMethTrim, ''); 2303// tocSearchInfo.push( new TocSObj(cls, el.href, i, small, el.textContent) ); 2304 tocSearchInfo.push( new TocSObj(cls, '#' + new_id, i, small, el.textContent) ); 2305 } 2306} 2307 2308//} @!endgroup 2309 2310//{ @!group Resizer Event Functions 2311 2312/* event MouseDown 2313 */ 2314function resizeMD(e) { 2315 var stateWid; 2316 2317 e.preventDefault(); 2318 e.stopPropagation(); 2319 2320 if (e.which !== 1) { 2321 e.preventDefault(); 2322 e.stopPropagation(); 2323 return false; 2324 } else if (e.altKey || e.ctrlKey) { 2325 var elWid = this.e.offsetWidth, 2326 em = px30em/30.0, 2327 min, max; 2328 if (this === oList) { 2329 max = (LIST_MAX * em).toFixed(0); min = (LIST_MIN * em).toFixed(0); 2330 } else { 2331 max = ( TOC_MAX * em).toFixed(0); min = ( TOC_MIN * em).toFixed(0); 2332 } 2333 2334 if (winType === 1 && this.d.docked) 2335 stateWid = state.display[1].widthDocked; 2336 else 2337 stateWid = this.d.width; 2338 2339 if (e.altKey) { 2340 if (elWid == this.d.width) { 2341 this.s.width = (this.d.docked ? max : min) + 'px'; 2342 } else { 2343 this.s.width = stateWid + 'px'; 2344 } 2345 } else if (e.ctrlKey) { 2346 if (elWid == this.d.width) { 2347 this.s.width = (this.d.docked ? min : max) + 'px'; 2348 } else { 2349 this.s.width = stateWid + 'px'; 2350 } 2351 } 2352 return false;
2353 } 2354 2355 resizerStWid = this.e.offsetWidth; 2356 this.s.width = resizerStWid + 'px'; 2357 resizerStX = e.screenX; 2358 2359 window.addEventListener('mousemove', this.resizeMM, false); 2360 window.addEventListener('mouseup' , this.resizeMU, false); 2361 return false; 2362} 2363 2364/* MouseMove */ 2365function resizeMM(e) { 2366 var offset = e.screenX - resizerStX, 2367 newWidth = resizerStWid + (this.d.docked ? offset : -offset), 2368 em = px30em/ 30.0, 2369 minW = em * (this === oList ? LIST_MIN : TOC_MIN), 2370 maxW = em * (this === oList ? LIST_MAX : TOC_MAX); 2371 2372 newWidth = Math.max( Math.min(newWidth, maxW), minW); 2373 newWidth = newWidth.toFixed(0); 2374 this.s.width = newWidth + 'px'; 2375 this.s.flexBasis = newWidth + 'px'; 2376 if (winType === 1 && this.d.docked) cS.widthDocked = newWidth; 2377 else this.d.width = newWidth; 2378 // hdrDbg(newWidth + (this === oList ? '_List' : '_TOC') ); 2379} 2380 2381/* MouseUp */ 2382function resizeMU(e) { 2383 var newWidth = this.e.offsetWidth; 2384 this.s.width = newWidth + 'px'; 2385 this.s.flexBasis = newWidth + 'px'; 2386 if (winType === 1 && this.d.docked) cS.widthDocked = newWidth; 2387 else this.d.width = newWidth; 2388 window.removeEventListener('mousemove', this.resizeMM); 2389 window.removeEventListener('mouseup' , this.resizeMU); 2390 if (storage) storage.yardState = JSON.stringify(state); 2391 updateCSS(); 2392} 2393 2394/* TouchStart */ 2395function resizeTS(e) { 2396 resizerStWid = this.e.offsetWidth; 2397 this.s.width = resizerStWid + 'px'; 2398 resizerStX = e.touches[0].screenX; 2399 e.preventDefault(); 2400 e.stopPropagation(); 2401 window.addEventListener('touchmove', this.resizeTM, false); 2402 window.addEventListener('touchend' , this.resizeTE, false); 2403} 2404 2405/* TouchMove */ 2406function resizeTM(e) { this.resizeMM( e.touches[0] ); } 2407 2408/* TouchEnd */ 2409function resizeTE(e) { 2410 window.removeEventListener('touchmove', this.resizeTM); 2411 window.removeEventListener('touchend' , this.resizeTE); 2412 this.resizeMU(e); 2413} 2414 2415//} @!endgroup 2416 2417__loadPublicState(); 2418__loadPublicState = undefined; 2419 2420})(); 2421 2422//{ @!group Debug Functions 2423 2424/* Debug info about document size, element count, etc 2425 * @param content [HTMLDIVElement] 2426 */ 2427function dbgDocInfo(content) { 2428 var lenTC = content.textContent.length / 1024.0, 2429 lenInnerHTML = content.innerHTML.length / 1024.0, 2430 lenChildren = content.querySelectorAll('*').length; 2431 2432 console.log( aDOMNext.href.match(/[^\/]+$/)[0].replace(/\.html/, '') + 2433 "\n textContent " + fmtL(lenTC) + ' KB' + 2434 "\n innerHTML " + fmtL(lenInnerHTML) + ' KB' + 2435 "\n elements " + fmtL(lenChildren) 2436 ) 2437} 2438 2439/* Debug info about doc loading timing 2440 */ 2441function dbgDocLoad() { 2442 var ttl = oDbgDoc.xhrRSC + oDbgDoc.cbAdd + oDbgDoc.cbToDOM + oDbgDoc.render, 2443 xhrRSC = oDbgDoc.xhrRSC, 2444 cbAdd = oDbgDoc.cbAdd, 2445 cbToDOM = oDbgDoc.cbToDOM, 2446 render = oDbgDoc.render, 2447 xhrRcv = oDbgDoc.xhrRcv, 2448 hgt = 'na', 2449 t; 2450 2451 if ( t = _id('footer') ) { 2452 hgt = t.offsetTop + t.offsetHeight; 2453 hgt = hgt / 1000.0; 2454 } 2455 2456 ttl = (' ' + Math.round(ttl)).slice(-7); 2457 2458 console.log( aDOMCur.href.match(/[^\/]+$/)[0].replace(/\.html/, '') + 2459 "\n DOC TOTAL " + fmtT( ttl ) + 2460 "\n xhrRSC parse " + fmtT( xhrRSC ) + 2461 "\n xhrCBDoc add " + fmtT( cbAdd ) + 2462 "\n xhrCBDoc > DOM " + fmtT( cbToDOM ) + 2463 "\n render " + fmtT( render ) + 2464 "\n xhrRcv " + fmtT( xhrRcv ) + 2465 "\n hgt pixels/1k " + fmtL( hgt ) 2466 ); 2467} 2468 2469/* Debug info about list loading timing 2470 */ 2471function dbgListLoad() { 2472 var ttl = oDbgList.xhrRSC + oDbgList.cbProc + oDbgList.render; 2473 xhrRSC = oDbgList.xhrRSC, 2474 cbAdd = oDbgList.cbProc, 2475 render = oDbgList.render, 2476 xhrRcv = oDbgList.xhrRcv, 2477 items = oList.itemQty, 2478 itemsVis = oList.itemsVis, 2479 elements = oDbgList.elements, 2480 hgt = oList.items.getBoundingClientRect().height / 1000.0; 2481 2482 console.log( (oList.libRoot.replace(/\//g, '') + ' ').slice(0,17) + 2483 ' ' + _id('list_title').textContent + 2484 "\n LIST TOTAL " + fmtT( ttl ) + 2485 "\n xhrRSC parse " + fmtT( xhrRSC ) + 2486 "\n xhrCB proc " + fmtT( cbAdd ) + 2487 "\n render " + fmtT( render ) + 2488 "\n xhrRcv " + fmtT( xhrRcv ) + 2489 "\n hgt pixels/1k " + fmtL( hgt ) + 2490 "\n ItemsVis " + fmtL( itemsVis) + 2491 "\n Items " + fmtL( items ) + 2492 "\n Elements " + fmtL( elements) 2493 ); 2494} 2495 2496/* Formats a time for console 2497 * @param t [Number] 2498 * @return [String] 2499 */ 2500function fmtT(t) {
2501 return ( ' ' + Math.round(t).toLocaleString() ).slice(-6) + ' ms'; 2502} 2503 2504/* Formats an integer for console 2505 * @param l [Number] 2506 * @return [String] 2507 */ 2508 function fmtL(l) { 2509 return (' ' + Math.round(l).toLocaleString()).slice(-7); 2510} 2511 2512function fmtTL(t, l) { 2513 return fmtT(t) + ' ' + fmtL(l); 2514} 2515 2516/* Debug to text area in main header */ 2517function hdrDbg(str) { 2518 var el = _id('y_debug'), 2519 ary; 2520 if (!dbgYDebug || !el) return; 2521 ary = el.textContent.split(' '); 2522 ary[0] = str; 2523 el.textContent = ary.join(' '); 2524} 2525 2526//} @!endgroup 2527 2528//{ @!group Navigation & XHR Functions 2529 2530/* Called when new documents finish rendering 2531 */ 2532function finishDocLoad() { 2533 setWait(); 2534 if (oXHRDoc instanceof XMLHttpRequest) oXHRDoc = null; 2535 docReady(); 2536 eContent.tabIndex = 1; 2537 eContent.focus(); 2538 clickedBy = -1; 2539 if (dbgDocTiming) { 2540 console.timeStamp('xhrCBDoc Render Done'); 2541 oDbgDoc.render = performance.now() - oDbgDoc.render; 2542 dbgDocLoad(); 2543 }; 2544}; 2545 2546/* Called anytime an anchor element is clicked, determines whether to call 2547 * xhrSend or gotoHash, loads url into aDOMNext 2548 * @param url [string] url to load 2549 */ 2550function gotoDoc(url) { 2551 if (!isServer && url.slice(0,6) === '/file.') { 2552 aDOMNext.href = (oList.libRoot || '') + url.replace(/%-/, '%25-').slice(1); 2553 } else { 2554 aDOMNext.href = url.replace(/%-/, '%25-'); 2555 } 2556 2557 if (aDOMCur.origin !== aDOMNext.origin) { 2558 window.location = url; 2559 return false; 2560 } 2561 2562 if (aDOMCur.pathname === aDOMNext.pathname && aDOMNext.hash) { 2563 gotoHash(); 2564 } else { 2565 if (dbgDocTiming) console.timeStamp('xhrSend'); 2566 if (oXHRDoc instanceof XMLHttpRequest) oXHRDoc.abort(); 2567 setWait(CB_CONTENT); 2568 oXHRDoc = xhrSend(aDOMNext.href, xhrCBDoc); 2569 } 2570 return true; 2571} 2572 2573/* Called when hash navigation is required, uses aDOMNext for info. Always 2574 * called by TOC list 'clicks', as TOC links are always for the document 2575 */ 2576function gotoHash() { 2577 var hash = decodeURIComponent(aDOMNext.hash.replace(/%-/, '%25-') ), 2578 title = winTitle + hash, 2579 el = _id(hash.slice(1)), 2580 prnt, 2581 nl, 2582 t, 2583 elOffTop; 2584 2585 if (!el) return; 2586 2587 if (el.tagName === 'SECTION' && el.firstElementChild.tagName === 'H3') 2588 el = el.firstElementChild; 2589 if ( /-constant$/.test(hash) && (t = _id('t2_cnst')) ) { 2590 if (t.classList.contains('h') ) t.classList.remove('h'); 2591 } 2592 2593 if (eContentClicked) eContentClicked.classList.remove(CN_CLICKED); 2594 2595 // for constants 2596 if (el.tagName === 'DT') { 2597 prnt = el.parentElement; 2598 if (prnt.classList.contains('constants')) 2599 // prnt is DL, DL > div > h2 2600 prnt.parentElement.previousElementSibling.classList.remove(CN_HIDDEN); 2601 } 2602 2603 if (el instanceof HTMLAnchorElement && el.classList.contains('i_m') ) { 2604 nl = eContent.querySelectorAll('h2.h2_sum'); 2605 for (var i = nl.length - 1, h2; h2 = nl[i]; i--) { 2606 if (el.compareDocumentPosition(h2) & 2) { 2607 h2.classList.remove(CN_HIDDEN); 2608 break; 2609 } 2610 } 2611 } 2612 2613 if (el) { 2614 eContentClicked = el; 2615 el.classList.add(CN_CLICKED); 2616 if (oList.d.vis) oList.showClicked(aDOMNext); 2617 if ( oToc.d.vis) oToc.showClicked(aDOMNext); 2618 } else { 2619 el = eContent.querySelector('a[name="' + hash.slice(1) +'"]'); 2620 } 2621 2622 if (el) { 2623 elOffTop = getOffsetTop(el); 2624 if (elOffTop === 0) {
2625 // constants have ids and maybe hidden by collapsed section 2626 if (el.parentElement.style.display === 'none') { 2627 el.parentElement.style.display = ''; 2628 elOffTop = getOffsetTop(el); 2629 } else if (el.parentElement.parentElement.style.display === 'none') { 2630 el.parentElement.parentElement.style.display = ''; 2631 elOffTop = getOffsetTop(el); 2632 } 2633 } 2634 if (clickedTop) { 2635 eContent.scrollTop = elOffTop - clickedTop; 2636 } else { 2637 el.scrollIntoView(true); 2638 } 2639// eContent.focus(); 2640 el.focus(); 2641 } 2642 2643 if (aDOMCur.href === aDOMNext.href) return; 2644 2645 aDOMCur.href = aDOMNext.href; 2646 hash = aDOMCur.href; 2647 if (isWinHistory && (clickedBy !== CB_POP_STATE) ) { 2648 window.history.pushState({name: title, url: hash}, 2649 title, hash.replace(/%-/, '%25-') ); 2650 } 2651} 2652 2653/* xhr callback function when a new main document is ready, called by 2654 * xhrReadyStateChange 2655 * @param docFrag [DocumentFragment] body element of url document 2656 * @param title [String] \<head\>\<title\> textContent 2657 * @param url [String] 2658 * @param status [Integer] 2659 * @param ms [Float] time to parse docFrag 2660 * @param msRcv {Float] time from xhrSend to xhrRSC 2661 */ 2662function xhrCBDoc(docFrag, title, url, status, ms, msRcv) { 2663 2664 if (status !== 200 || docFrag === null) { 2665 setWait(-1); 2666 alert('xhrCBDoc - bad return with status ' + status + " from location\n" + url); 2667 if (clickedBy === CB_LIST) { 2668 oList.clickedLI = oList.clickedLIOld; 2669 oList.clickedA = null; 2670 } 2671 return; 2672 } 2673 2674 var hash = decodeURIComponent(aDOMNext.hash).slice(1), 2675 oldMenu = document.getElementById('y_menu'), 2676 oldContent = eContent, 2677 oldLibRoot, 2678 newContentClicked, 2679 newToc, 2680 newContent, 2681 newMenu, 2682 loadMenu = false, 2683 eAList, 2684 aDOMTemp = document.createElement('a'), 2685 tEl, 2686 t, t1, nl, tSt, tEnd; 2687 2688 if (dbgDocTiming) { 2689 console.timeStamp('xhrCBDoc Start'); 2690 oDbgDoc.xhrRSC = ms; 2691 tSt = performance.now(); 2692 oDbgDoc.xhrRcv = msRcv; 2693 } 2694 2695 // get content and objectPath from docFrag, along with list url 2696 if ( t = getDocFragId(docFrag, 'content') ) { 2697 if (hash) newContentClicked = getDocFragId(docFrag, hash); 2698 t1 = t.parentElement; 2699 newContent = t1.removeChild(t); 2700 }; 2701 2702 // Can't load without both 2703 if (newContent === undefined || oldContent === undefined) return; 2704 2705 if ( t = getDocFragId(docFrag, 'y_header') ) { 2706 if (t1 = getDocFragId(docFrag, 'y_menu') ) 2707 newMenu = t.removeChild(t1); 2708 if (t1 = getDocFragId(docFrag, 'list_href') ) 2709 eAList = t.removeChild(t1); 2710 }; 2711 2712 docFrag = null; 2713 2714 if (newMenu) { 2715 isServer = (newMenu.className === 'server'); 2716 if (oldMenu) { 2717 oldMenu.removeEventListener('click', clkMenu); 2718 loadMenu = true; 2719 }; 2720 }; 2721 2722 // Update history 2723 if (aDOMNext.href !== aDOMCur.href) { 2724 t = aDOMNext.pathname + (hash ? "#" + hash : ''); 2725 if (isWinHistory && (clickedBy !== CB_POP_STATE) ) { 2726 window.history.pushState({name: title, url: t}, title, url); 2727 }; 2728 aDOMCur.href = aDOMNext.href; 2729 }; 2730 2731//console.log("eAList\n" + eAList.getAttribute('href') + "\nurl\n" + aDOMNext.href.replace(/[^\/]+$/, '')); 2732//console.log(aDOMNext.href.replace(/[^\/]+$/, '') + eAList.getAttribute('href')); 2733 2734 if (eAList) { 2735 eAList.href = aDOMNext.href.replace(/[^\/]+$/, '') + eAList.getAttribute('href'); 2736 oList.load(eAList, false); 2737 } 2738 2739 if (dbgDoc) dbgDocInfo(newContent); 2740 2741 var eTitle = document.documentElement.querySelector('head title'), 2742 eMain = _id('y_main'), 2743 eHeader = _id('y_header'); 2744 2745 isZoomed = false; 2746 2747 winTitle = title; 2748 2749 oldContent.removeEventListener('click', clkContent); 2750 eContentClicked = null; 2751 newToc = addContent(newContent); 2752 2753 if (!newContentClicked) { 2754 newContentClicked = newContent.querySelector('a[name="' + hash.slice(1) +'"]'); 2755 } else if (newContentClicked.tagName === 'SECTION' && newContentClicked.firstElementChild.tagName === 'H3') { 2756 newContentClicked = newContentClicked.firstElementChild; 2757 } 2758 2759 if (newContentClicked) { 2760 newContentClicked.classList.add(CN_CLICKED); 2761 eContentClicked = newContentClicked; 2762 } 2763 2764 // below wraps tables in div element with overflow-x: auto 2765 t = Array.prototype.slice.call( newContent.querySelectorAll('table') ); 2766 if (t.length > 0) { 2767 tEl = document.createElement('div'); 2768 tEl.className = 'y_table'; 2769 for (var i = 0, div, prnt, repl, tbl; tbl = t[i]; i++) { 2770 if (tbl.className === '') { 2771 div = tEl.cloneNode(false); 2772 prnt = tbl.parentElement; 2773 repl = prnt.replaceChild(div, tbl); 2774 div.appendChild(repl); 2775 } 2776 } 2777 } 2778 2779 if (dbgDocTiming) { 2780 console.timeStamp('xhrCBDoc Add Done'); 2781 oDbgDoc.cbAdd = performance.now() - tSt; 2782 tSt = performance.now(); 2783 } 2784 2785 // timeout to allow rendering 2786 setTimeout( finishDocLoad, 15); 2787 2788 // all the replacements at once 2789 eMain.replaceChild(newContent, oldContent); 2790 oToc.nav.replaceChild(newToc, oToc.items); 2791 if (t = _id('toc_search_items')) oToc.nav.removeChild(t); 2792 2793 if (loadMenu) eHeader.replaceChild(newMenu, oldMenu); 2794 eTitle.textContent = title; 2795 2796 // Shows or hides TOC search (none for doc content) 2797 if (!isFirstLoad) tocSearchShowHide(newContent); 2798 2799 // Scroll oList & oToc 2800 if (oList.d.vis) oList.showClicked(aDOMNext); 2801 oToc.items = _id('toc_items'); 2802 if ( oToc.d.vis) { 2803 if (hash) oToc.showClicked(aDOMNext); 2804 else oToc.nav.scrollTop = 0; 2805 } 2806 2807 newContent = null; 2808 newToc = null; 2809 newMenu = null; 2810 2811 eContent = _id('content'); 2812 2813 if (eContentClicked) { 2814 // open constants section if closed 2815 if ( /-constant$/.test(hash) && (t = _id('t2_cnst')) ) { 2816 if (t.classList.contains('h') ) t.classList.remove('h'); 2817 } 2818 if (clickedTop) { 2819 eContent.scrollTop = eContentClicked.offsetTop - clickedTop; 2820 } else { 2821 eContentClicked.scrollIntoView(true); 2822 } 2823 } 2824 2825 if (dbgDocTiming) { 2826 console.timeStamp('xhrCBDoc ToDom Done'); 2827 oDbgDoc.render = performance.now(); 2828 oDbgDoc.cbToDOM = oDbgDoc.render - tSt; 2829 } 2830} 2831 2832/* xhr onerror function 2833 * @param _url [String] 2834 * @param _func [Function] The function to call when done processing 2835 * @param status [Integer] 2836 */ 2837function xhrOnError(url, func, xhr) { 2838 var status = xhr.status; 2839 xhr.onreadystatechange = null; 2840 xhr.onerror = null; 2841 setWait(-1); 2842 func(null, null, url, status, 0, 0); 2843 return false;
2844} 2845 2846/* Receives xhr.responseXML, parses, loads into a DocumentFragment, which is 2847 * returned to func callback. 2848 * 2849 * * Parses title element string 2850 * * Parses to just children of the body element 2851 * * Removes any script elements 2852 * @param url [String] 2853 * @param func [Function] callback 2854 * @param xhr [XMLHttpRequest] 2855 * @param pn [Float] performance.now 2856 */ 2857function xhrReadyStateChange(url, func, xhr, pn) { 2858 if (xhr.readyState === 4) { 2859 if (xhr.status === 200) { 2860 var title, 2861 docFrag = document.createDocumentFragment(), 2862 topDiv = document.createElement('div'), 2863 doc = xhr.responseXML, 2864 tRcv, tSt, tParse, nl, temp; 2865 2866 if (dbgDocTiming || dbgListTiming) { 2867 console.timeStamp('xhrRSC Start'); 2868 tSt = performance.now(); 2869 tRcv = tSt - pn; 2870 } 2871 if (doc === '') { 2872 func(null, null, url, 404, 0, tRcv); 2873 return; 2874 } 2875 2876 if (temp = doc.querySelector("head > title")) { 2877 title = temp.innerHTML; 2878 title = title.replace(/[\v\n\r]+/g, ' '); 2879 title = title.replace(/ /g, ' '); 2880 title = title.replace(/ [^\w\d] /, ' - ').trim(); 2881 } else title = ''; 2882 2883 if (temp = doc.querySelector("head")) { 2884 // console.log("Deleting head"); 2885 temp.parentElement.removeChild(temp); 2886 }; 2887 2888 nl = doc.body.querySelectorAll('script'); 2889 for (var k = 0, el; el = nl[k]; k++) { 2890 el.parentElement.removeChild(el); 2891 }; 2892 2893 docFrag.appendChild(doc.body); 2894 // console.log(doc.body); 2895 doc = null; 2896 xhr.onreadystatechange = null; 2897 xhr.onerror = null; 2898 2899 if (dbgDocTiming || dbgListTiming) 2900 tParse = performance.now() - tSt; 2901 2902 func(docFrag, title, url, 200, tParse, tRcv); 2903 docFrag = null; 2904 xhr.onreadystatechange = null; 2905 xhr.onerror = null; 2906 xhr = null; 2907 } else if (xhr.status === 404) { 2908 // below is for RDoc links 2909 if (/classes\//.test(url) ) { 2910 url = url.replace(/classes\//, ''); 2911 aDOMNext.href = aDOMNext.href.replace(/classes\//, ''); 2912 xhr.open("GET", url , true); 2913 xhr.responseType = 'text'; 2914 xhr.setRequestHeader('Content-Type', 'text/html'); 2915 xhr.send(); 2916 return false; 2917 } 2918 xhr.onreadystatechange = null; 2919 xhr.onerror = null; 2920 func(null, null, url, 404, tParse, tRcv); 2921 } 2922 } 2923} 2924 2925/* Preps, opens, and sends the xhr request 2926 * @param url [String] 2927 * @param func [Function] The function to call when done processing 2928 * @return [XMLHttpRequest] xhr object, used for abort 2929 */ 2930function xhrSend(url, func) { 2931 var aDOM = document.createElement('a'), 2932 xhr = new XMLHttpRequest(), 2933 tSt, 2934 reFullHost = /^[^:]+:\/\/[^\/]+/; 2935 2936 aDOM.setAttribute('href', url); 2937 2938 if (reFullHost.exec(aDOM.href)[0] !== reFullHost.exec(location.href)[0]) { 2939 func(null, url); 2940 return; 2941 }; 2942 tSt = performance.now(); 2943 xhr.onreadystatechange = xhrReadyStateChange.bind({}, url, func, xhr, tSt); 2944 xhr.onerror = xhrOnError.bind({}, url, func, xhr); 2945 2946 xhr.open("GET", url , true); 2947 xhr.responseType = 'document'; 2948 xhr.setRequestHeader('Content-Type', 'text/html'); 2949 xhr.send(); 2950 return xhr; 2951} 2952 2953//} @!endgroup 2954 2955//{ @!group Misc & Helper Functions 2956 2957/* Convenience method for document.getElementById() 2958 * @param id [String] 2959 * @return [HTMLElement] 2960 */ 2961function _id(id) { 2962 //if (id === '' || !id) debugger; 2963 return document.getElementById(id); 2964} 2965 2966/* Changes font size in state, then calls {setFontSize}. 2967 * @param [Boolean] up up for increased fontSize, otherwise decrease. 2968 */ 2969function changeFontSize(up) { 2970 var fs = parseInt(state.fontSize.replace('px', '') || '15px') + (up ? 1 : -1); 2971 if (fs <= 12) fs = 12; 2972 else if (fs >= 18) fs = 18; 2973 state.fontSize = fs + 'px'; 2974 if (storage) storage.yardState = JSON.stringify(state); 2975 setFontSize(); 2976 if (_id('settings').className === 'show') settingsSetData(); 2977}; 2978 2979/* Cleans white space nodes from prnt. 2980 * @param [HTMLElement] prnt 2981 */ 2982function clean(prnt) { 2983 for (var i = 0, el; el = prnt.childNodes[i]; i++) { 2984 if ( (el.nodeType === Node.TEXT_NODE && !/\S/.test(el.nodeValue)) || 2985 el.nodeType === Node.COMMENT_NODE) { 2986 prnt.removeChild(el); 2987 i --; 2988 }
2989 else if (el.nodeType === Node.ELEMENT_NODE) clean(el); 2990 }; 2991}; 2992 2993function commonLoad() { 2994 var foundHRef; 2995 for (var i = 0, ss; ss = document.styleSheets[i]; i++) { 2996 if ( /y_style\.css$/.test(ss.href) ) { 2997 foundHRef = ss.href.replace(/css\/y_style.css$/, 'xhr/common.html'); 2998 xhrSend(foundHRef, commonXhrCB); 2999 break; 3000 }; 3001 }; 3002}; 3003 3004function commonInsert(docFrag, elId) { 3005 var newPrnt = _id(elId), 3006 oldPrnt = isGetElByIdInDocFrag ? docFrag.getElementById(elId) : docFrag.querySelector("#" + elId), 3007 el; 3008 clean(oldPrnt); 3009 while (el = oldPrnt.firstElementChild) { newPrnt.appendChild(el); }; 3010}; 3011 3012function commonXhrCB(docFrag, title, url, status, ms, msRcv) { 3013 var eAList = _id('list_href').cloneNode(false), 3014 el; 3015 if (status !== 200 || !docFrag) { 3016 setWait(); 3017 return; 3018 }; 3019 3020 if (_id('y_header').children.length === 5) { 3021 commonInsert(docFrag, 'y_header'); 3022// setFSTitles(); 3023 }; 3024 if (!_id('list_header').firstElementChild) { 3025 commonInsert(docFrag, 'list_header'); 3026 }; 3027 if (!_id('toc_header').firstElementChild) { 3028 commonInsert(docFrag, 'toc_header'); 3029 }; 3030 if (!_id('settings').firstElementChild) { 3031 commonInsert(docFrag, 'settings'); 3032 }; 3033 3034 // Add events to items added above 3035 oPane.firstDOMLoad(true); 3036 _id('hdr_button').addEventListener('click' , clkHdrBtn , false); 3037 _id('settings' ).addEventListener('click' , clkSettingWindow , false); 3038 3039 // Load list 3040 if (eAList) oList.load(eAList); 3041 // Set LIST and TOC button state in main header 3042 oList.bVis = _id('list_vis'); 3043 oList.bVis.className = oList.d.vis ? CN_BTN_VIS : CN_HIDDEN; 3044 oToc.bVis = _id('toc_vis'); 3045 oToc.bVis.className = oToc.d.vis ? CN_BTN_VIS : CN_HIDDEN; 3046 // Set source button state 3047 _id('src').className = state.showSource ? 'o' : 'c'; 3048 _id('src').disabled = !eContent.querySelector('a.toggleSource') 3049 // Shows or hides TOC search (none for doc content) 3050 tocSearchShowHide(eContent); 3051}; 3052 3053/* To match Ruby CGI.escape /([^ a-zA-Z0-9_.-]+)/ 3054 * @param str [String] unescaped string 3055 * @return [String] escaped string 3056 */ 3057function encodeStr(str) { 3058 return str.replace(/[^ a-zA-Z0-9_.-]/g, encodeChar ); 3059} 3060 3061/* Escape string as valid regex 3062 * @param str [String] unescaped string 3063 * @return [String] escaped string 3064 */ 3065function escapeRegEx(str) { 3066 return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); 3067} 3068 3069/* IE fun... 3070 * 3071 */ 3072function getDocFragId(frag, id) { 3073 if (isGetElByIdInDocFrag) 3074 return frag.getElementById(id); 3075 else 3076 var escId = id.replace(/[`<>&\[\]/{}()*+?!.\^$|=@-]/g, "\\$&") 3077 // console.log(escId); 3078 return frag.querySelector('#' + escId); 3079}; 3080 3081function tocSearchShowHide(content) { 3082 cls = content.className; 3083 if (cls === 'module' || cls === 'class' || cls === 'method') { 3084 _id('toc_search_text').style.display = ''; 3085 _id('toc_search_text').value = ''; 3086 _id('toc_search_icon').style.display = ''; 3087 3088 } else { 3089 _id('toc_search_text').style.display = 'none'; 3090 _id('toc_search_icon').style.display = 'none'; 3091 } 3092} 3093 3094/* Used to match encoding of method list, two % replace statements for FireFox's 3095 * handling of '<' and '>' 3096 * @param str [String] unescaped string 3097 * @return [String] escaped string 3098 */ 3099function t2EncodeStr(str) { 3100 //str = str.replace(/[\/\.?+%]/g, encodeChar); 3101 // encode + 2B / 2F ? 3F 3102 // str = str.replace(/[\/\.?+]/g, encodeChar); 3103 3104 str = str.replace(/[`\/?+%^]/g, encodeChar); 3105 str = str.replace(/%3C/g, '\<' ); 3106 str = str.replace(/%3E/g, '\>' ); 3107//str = str.replace(/%3F/g, '\?>' ); 3108 return str; 3109} 3110 3111/* Return escaped char 3112 * @param c [Char] single character string 3113 * @return [String] escaped string, ie '!' => '%21' 3114 */ 3115function encodeChar(c) { 3116 return '%' + c.charCodeAt(0).toString(16).toUpperCase(); 3117} 3118 3119/* Finds a css rule. 3120 * @param [String] file base file name of stylesheet 3121 * @param {String] rule selectorText of rule 3122 */ 3123function getCSSRule(file, rule) { 3124 var foundRule, 3125 re = new RegExp( escapeRegEx(file) ); 3126 for (var i = 0, ss; ss = document.styleSheets[i]; i++) { 3127// if ( ss.href.endsWith(file) ) { 3128 3129 if ( re.test(ss.href) ) { 3130 cssRules = ss.cssRules; 3131 for (var j = 0, cssRule; cssRule = cssRules[j]; j++) { 3132 // style 3133 if (cssRule.selectorText === rule) { 3134 foundRule = cssRule; 3135 break; 3136 }; 3137 }; 3138 break; 3139 }; 3140 }; 3141 return foundRule; 3142}; 3143 3144/* Finds the first parent element whose class matches using instanceof. 3145 * @param el [HTMLElement] 3146 * @param io [class HTMLElement] instanceof comparision class 3147 * @param notCurrent [Boolean] optional, whether to not test el parameter, 3148 * if not specified, function will test el 3149 * @return [HTMLElement] the parent element matching io 3150 */ 3151function getPrntByIO(el, io, notCurrent) { 3152 if (!notCurrent && el instanceof io) return el; 3153 var prnt = el.parentElement; 3154 while ( prnt && !(prnt instanceof io)) { prnt = prnt.parentElement; } 3155 return prnt; 3156} 3157
3158/* returns offsetTop of element 3159 * @param el [HTMLElement] 3160 * @return [Integer] total offsetTop 3161 */ 3162function getOffsetTop(el) { 3163 var y = el.offsetTop; 3164 while (el = el.offsetParent) { y += el.offsetTop; } 3165 return y; 3166} 3167 3168/* Shows 'wait' svg 3169 * @param type [Integer, null] CB_CONTENT or CB_LIST, null to clear 3170 */ 3171function setWait(type) { 3172 var oBCR, 3173 oBCRW, 3174 itemsX, 3175 eWait = _id('y_wait'), 3176 cls = isTouch ? 'text' : 'run', 3177 halfWid = 0.5 * waitWidth, 3178 t; 3179 3180 if (type === CB_CONTENT) { 3181 oBCR = eContent.getBoundingClientRect(); 3182 eWait.style.top = Math.round(oBCR.top + halfWid) + 'px'; 3183 eWait.style.left = Math.round(oBCR.left + oBCR.width/2.0 - halfWid) + 'px'; 3184 eWait.setAttribute('class', cls); 3185 } else if (type === CB_LIST) { 3186 // oList.items maybe hidden due to search 3187 if (t = _id('list_search_items') ) { 3188 oBCRW = t.getBoundingClientRect(); 3189 itemsX = oBCRW.left + oBCRW.width/2.0; 3190 } 3191 if ( !(itemsX > 15 )) { 3192 if (oList.items) { 3193 oBCRW = oList.items.getBoundingClientRect(); 3194 itemsX = oBCRW.left + oBCRW.width/2.0; 3195 } 3196 } 3197 if ( !(itemsX > 15 )) { 3198 oBCR = oList.nav.getBoundingClientRect(); 3199 itemsX = oBCR.left + oBCR.width/2.0; 3200 } 3201 oBCR = _id('list_header').getBoundingClientRect(); 3202 eWait.style.top = Math.round(oBCR.top + oBCR.height + halfWid) + 'px'; 3203 eWait.style.left = Math.round(itemsX - halfWid) + 'px'; 3204 eWait.setAttribute('class', cls); 3205 } else 3206 eWait.setAttribute('class', ''); 3207} 3208 3209/* Globally shows / hides source code 3210 * @param content [HTMLElement] the content element 3211 * @param showCode [Boolean] true to show source 3212 */ 3213function sourceShowHide(content, showCode) { 3214 var src = content.querySelectorAll('section div.source_code'), 3215 sToggle = content.querySelectorAll('span.showSource a.toggleSource'), 3216 len, 3217 top = 0.0, 3218 eShow, 3219 hdrBottom = _id('y_header').getBoundingClientRect(); 3220 3221 hdrBottom = hdrBottom.top + hdrBottom.height; 3222 3223 if (eContentClicked) { 3224 top = Math.round(eContentClicked.getBoundingClientRect().top); 3225 } 3226 if (hdrBottom < top && top < winHeight) { 3227 eShow = eContentClicked; 3228 } else { 3229 var nl = eContent.querySelectorAll('h2, h3'); 3230 // eContentClicked not visible 3231 for (var i = 0, el, topTest; el = nl[i]; i++) { 3232 topTest = el.getBoundingClientRect().top; 3233 if (hdrBottom < topTest && topTest < winHeight) { 3234 top = Math.round(topTest); 3235 eShow = el; 3236 break; 3237 } 3238 } 3239 } 3240 3241 len = src.length - 1; 3242 3243 if (showCode) { 3244 _id('src').className = 'o'; 3245 for (var i = len; i >= 0; i--) { 3246 src[i].classList.remove(CN_HIDDEN); 3247 sToggle[i].textContent = sToggle[i].textContent.replace(/^view/, 'hide'); 3248 } 3249 } else { 3250 _id('src').className = 'c'; 3251 for (var i = len; i >= 0; i--) { 3252 src[i].classList.add(CN_HIDDEN); 3253 sToggle[i].textContent = sToggle[i].textContent.replace(/^hide/, 'view'); 3254 } 3255 } 3256 3257 if (top !== 0.0) { 3258 top = eContent.scrollTop + Math.round(eShow.getBoundingClientRect().top) - top; 3259 eContent.scrollTop = top; 3260 } 3261} 3262 3263/* Called when Summary h2 elements are clicked 3264 * @param tgt [HTMLAnchorElement] 3265 */ 3266function summaryToggle(tgt) { 3267 var nlToggles = eContent.querySelectorAll('h2.h2_sum'), 3268 rTop = tgt.offsetTop - eContent.scrollTop, 3269 isHidden = tgt.classList.contains(CN_HIDDEN), 3270 a, h2El; 3271 3272 nlToggles = Array.prototype.slice.call(nlToggles); 3273 3274// if (nlToggles.length > 0) { 3275 // code below for js constants & variables, assumes they're 3276 // singular and at the top of the nodelist 3277// h2El = nlToggles[0]; 3278// if (h2El.id === 'js_h2_cv') { 3279// a = nlToggles.shift(); 3280// a.textContent = text; 3281// grandParent.nextElementSibling.style.display = (text === 'collapse') ? '' : 'none'; 3282// } 3283// } 3284 3285 len = nlToggles.length - 1; 3286 if (isHidden) { 3287 for (var i = len; i >= 0; i--) { nlToggles[i].classList.remove(CN_HIDDEN); } 3288 } else { 3289 for (var i = len; i >= 0; i--) { nlToggles[i].classList.add(CN_HIDDEN); } 3290 } 3291 eContent.scrollTop = tgt.offsetTop - rTop; 3292 state.summaryCollapsed = !isHidden; 3293 if (storage) storage.yardState = JSON.stringify(state); 3294} 3295 3296/* Sets width and height of Settings transition style. 3297 * @param [Integer] wid width of Settings div 3298 * @param [Integer] hgt height of Settings div 3299 */ 3300function settingsSetCSS(type) { 3301 var el = _id('settings'); 3302 3303 if (type === 'in') el.className = 'show'; 3304 else if (type === 'out') el.className = ''; 3305 else alert("Parameter Error setSettingsCSS!"); 3306}; 3307 3308/* Sets settings 'window' items */ 3309function settingsSetData() {
3310 var scrnChar = Math.floor(50.0 * screen.availWidth / px50Char), 3311 scrnType = scrnChar > MED_LRG ? 2 : (scrnChar > SML_MED ? 1 : 0), 3312 fs = state.fontSize; 3313 settingsSetTitles(fs); 3314 _id('b2').textContent = winType; 3315 _id('c2').textContent = scrnType; 3316 _id('b3').textContent = Math.floor(50.0 * winWidth / px50Char); 3317 _id('c3').textContent = scrnChar; 3318 _id('a5').textContent = 'Font ' + fs; 3319 3320 if (fs === '12px') changeClass( _id('font_sml'), CN_BTN_VIS, null , true, true); 3321 else changeClass( _id('font_sml'), null , CN_BTN_VIS, true, false); 3322 3323 if (fs === '18px') changeClass( _id('font_lrg'), CN_BTN_VIS, null , true, true); 3324 else changeClass( _id('font_lrg'), null , CN_BTN_VIS, true, false); 3325 3326 if (winType === 0) { 3327 changeClass( _id('list_dock' ), CN_BTN_VIS, null , null, true); 3328 changeClass( _id('toc_dock' ), CN_BTN_VIS, null , null, true); 3329 changeClass( _id('list_float' ), null , 'selected', null, true); 3330 changeClass( _id('toc_float' ), null , 'selected', null, true); 3331 } else { 3332 changeClass( _id('list_dock' ), null, 'selected', oList.d.docked, null); 3333 changeClass( _id('list_float'), null, 'selected', !oList.d.docked, null); 3334 changeClass( _id('toc_dock' ), null, 'selected', oToc.d.docked, null); 3335 changeClass( _id('toc_float' ), null, 'selected', !oToc.d.docked, null); 3336 }; 3337}; 3338 3339/* Sets title of font size buttons */ 3340function settingsSetTitles(_fs) { 3341 var fs = parseInt( (_fs || state.fontSize).replace('px', '') ); 3342 if (fs <= 12) { 3343 _id('font_sml').title = '12px' ; _id('font_lrg').title = '13px'; 3344 } else if (fs >= 18) { 3345 _id('font_sml').title = '17px' ; _id('font_lrg').title = '18px'; 3346 } else { 3347 _id('font_sml').title = (fs - 1) + 'px'; _id('font_lrg').title = (fs + 1) + 'px'; 3348 }; 3349}; 3350 3351/* Used to check whether settings 'window' is open and shoud be closed. Called 3352 * from various event handlers. 3353 */ 3354function settingsCheck() { 3355 var el = _id('settings'); 3356 if ( el && el.className === 'show') settingsSetCSS('out'); 3357} 3358 3359/* Adds / removes classes from an element, also can disable. 3360 * @param [HTMLElement] el id of element 3361 * @param [String, null] rmvCls class to remove 3362 * @param [String, null] addCls class to add 3363 * @param [Integer, null] blnAdd null no action, false remove addCls, 3364 * true adds addCls 3365 * @param [Integer, null] blnDis disable flag if not null 3366 */ 3367function changeClass(el, rmvCls, addCls, blnAdd, blnDis) { 3368 var cl = el.classList; 3369 if (rmvCls) cl.remove(rmvCls); 3370 if (addCls) { 3371 if (blnAdd === true) cl.add(addCls); 3372 else if (blnAdd === false) cl.remove(addCls); 3373 }; 3374 if (blnDis !== null) el.disabled = blnDis; 3375} 3376 3377//} @!endgroup 3378 3379//{ @!group Add Doc Content Functions 3380 3381/* Main function that calls the remainder of the 'add' functions 3382 * @param content [HTMLDIVElement] the content div element 3383 */ 3384function addContent(content) { 3385 var cls = content.className, 3386 toc, t, footer; 3387 3388 if (t2GA instanceof Function) t2GA('send', 'pageview', aDOMNext.pathname); 3389 3390 // for javascript files 3391 if ( typeof hljs !== 'undefined' && 3392 hljs.highlightElement instanceof Function ) { 3393// var nl = content.querySelectorAll('pre.code.javascript, pre.code.cpp'); 3394 var nl = content.querySelectorAll('pre.code'); 3395 for (var i = 0, el; el = nl[i]; i++) { 3396 if ( !(el.classList.contains('ruby') || el.classList.contains('example') ) ) 3397 hljs.highlightElement(el); 3398 } 3399 } 3400 3401 if (cls === 'module' || cls === 'class' || cls === 'method') { 3402 removeEmptyDocString(content); 3403 3404 t = content.querySelector('#h2_overview'); 3405 if (state.overviewCollapsed && t) t.classList.add(CN_HIDDEN); 3406 3407 t = content.querySelector('#t2_relations'); 3408 if (state.relationsCollapsed && t) { 3409 t.classList.add(CN_HIDDEN); 3410 // td > tr > thead > table 3411 var tbody = t.parentElement.parentElement.parentElement.querySelector('tbody'); 3412 tbody.style.display = 'none'; 3413 } 3414 3415 addWhiteSpace(content); 3416 addLineNumbers(content); 3417 addShowSource(content); 3418 addSummaryCompact(content); 3419 toc = oToc.generate(content, true); 3420 if (isServer && cls !== 'method') addPermaLinks(content); 3421 t = content.querySelector('a.toggleSource'); 3422 } else { 3423 toc = oToc.generate(content, false); 3424 t = false;
3425 } 3426 if ( _id('src') ) _id('src').disabled = !t; // Source open/close button 3427 3428 addFooter(content); 3429 3430 return toc; 3431} 3432 3433/* Adds footer children 3434 * @param content [HTMLDIVElement] the content div element 3435 */ 3436function addFooter(content) { 3437 var footer = content.querySelector('#footer'), 3438 el; 3439 3440 if (footer && footer.children.length === 0 && 3441 elLibFooter && elLibFooter.children.length > 0) { 3442 while (el = footer.firstElementChild) { footer.removeChild(el); }; 3443 for (var i = 0, node; node= elLibFooter.childNodes[i]; i++) { 3444 footer.appendChild(node.cloneNode(true)); 3445 }; 3446 // console.log("elLibFooter " + elLibFooter.textContent.length + " footer " + footer.textContent.length); 3447 }; 3448}; 3449 3450/* Adds Line number text to code segments 3451 * @param content [HTMLDIVElement] the content div element 3452 */ 3453function addLineNumbers(content) { 3454 var nl = content.querySelectorAll('div.source_code pre.lines_num'), 3455 numStart, 3456 numEnd, 3457 str; 3458 3459 for (var i = 0, el; el = nl[i]; i++) { 3460 if (el.textContent == '') { 3461 numStart = Number(el.dataset.start); 3462 numEnd = Number(el.dataset.end); 3463 if (numStart > 0) { 3464 str = "\n\n"; 3465 for (var j = numStart; j <= numEnd; j++) { 3466 str += j + "\n"; 3467 } 3468 el.textContent = str; 3469 } 3470 } 3471 } 3472} 3473 3474/* If running server, adds the 'permalink' to method signatures in 3475 * detail sections 3476 * @param content [HTMLDIVElement] the content div element 3477 */ 3478function addPermaLinks(content) { 3479 var nl = content.querySelectorAll('section h3.signature'), 3480 a = document.createElement('a'), 3481 docPath = aDOMNext.pathname; 3482 3483 a.className = 'permalink'; 3484 a.textContent = 'permalink'; 3485 3486 for (var i = 0, el, aa, href; el = nl[i]; i++) { 3487 aa = a.cloneNode(true); 3488 href = el.parentElement.id; 3489 if ( /-class_method$/.test(href) ) 3490 href = '.' + href.replace(/-class_method$/, ''); 3491 else 3492 href = ':' + href.replace(/-[a-z_]+$/, ''); 3493 href = href.replace(/\?$/, '%3F'); 3494 aa.setAttribute('href', docPath + href); 3495// el.appendChild(aa); 3496 el.insertBefore(aa, el.firstChild); 3497 } 3498} 3499 3500/* Adds the 'view / hide source' elements for source code 3501 * @param content [HTMLDIVElement] the content div element 3502 */ 3503function addShowSource(content) { 3504 var nl = content.querySelectorAll('section.method_details div.source_code'), 3505 span = document.createElement('span'), 3506 spc = String.fromCharCode(8202), 3507 showSource = state.showSource; 3508 3509 span.className = 'showSource'; 3510 span.innerHTML = "[" + spc + "<a href='#' class='toggleSource'>" + 3511 (showSource ? T_HIDE_SRC : T_VIEW_SRC) + "</a>" + spc + "]"; 3512 3513 if ( _id('src') ) _id('src').disabled = (nl.length === 0); 3514 3515 for (var i = 0, el; el = nl[i]; i++) { 3516 if (showSource) el.classList.remove(CN_HIDDEN); 3517 else el.classList.add(CN_HIDDEN); 3518 if (el.previousElementSibling.className === 'link_repo') 3519 el = el.previousElementSibling; 3520 el.parentElement.insertBefore( span.cloneNode(true) , el); 3521 } 3522} 3523 3524/* Add elements for compact summaries 3525 * @param content [HTMLDIVElement] the content div element 3526 */ 3527function addSummaryCompact(content) { 3528//var nl = content.querySelectorAll('ul.summary.full'), 3529 var nl = content.querySelectorAll('ul.summary'), 3530 ulFull, 3531 ulCompact, 3532 isConstant, 3533 remove, 3534 nlChildren, 3535 prnt, 3536 grandParent, 3537 fullVis = !state.summaryCollapsed, 3538 compactVis = state.summaryCollapsed, 3539 eANew, 3540 eId, 3541 eA = document.createElement('a'), 3542 eUL = document.createElement('ul'), 3543 eLI = document.createElement('li'), 3544 t; 3545 3546 // Loop thru all the 'summary full' ul elements, clone for compact summaries, 3547 // then remove content 3548 for (var i = 0; ulFull = nl[i]; i++) { 3549 ulCompact = eUL.cloneNode(false); 3550 ulFull.classList.add('full'); 3551 ulCompact.className = ulFull.className.replace(' full', ' compact'); 3552 isConstant = ulFull.classList.contains('constants'); 3553 // get anchor elements, clean up, append to ulCompact 3554 if (isConstant) 3555 nlChildren = ulFull.querySelectorAll('span.summary_signature'); 3556 else 3557 nlChildren = ulFull.querySelectorAll('span.summary_signature a'); 3558 3559 for (var j = 0, a, li, cls; a = nlChildren[j]; j++) { 3560 if (isConstant) { 3561 cls = a.className.replace(/^summary_signature/, 'cnst_a').trim(); 3562 eANew = eA.cloneNode(); 3563 eANew.href = '#' + a.id; 3564 eANew.textContent = a.textContent.replace(/ =$/, ''); 3565 } else { 3566 cls = a.parentElement.className.replace('summary_signature', '').trim(); 3567 if (a.parentElement.parentElement.classList.contains('deprecated')) 3568 cls += ' deprecated'; 3569 eANew = a.cloneNode(true); 3570 // remove text in anchor but only after strong 3571 for (var k = 0, child, del = false; child = eANew.childNodes[k]; k++) { 3572 if (del) { 3573 eANew.removeChild(child); 3574 k--; 3575 } else { 3576 del = (child.nodeType === 1 && child.tagName === 'STRONG'); 3577 } 3578 }
3579 // remove anything after anchor 3580 while (t = eANew.nextSibling) { 3581 eANew.parentElement.removeChild(t); 3582 } 3583 } 3584 3585 if (cls !== '') eANew.className = cls; 3586 3587 li = eLI.cloneNode(false); 3588 li.appendChild(eANew); 3589 ulCompact.appendChild(li); 3590 } 3591 ulFull.parentElement.insertBefore(ulCompact, ulFull); 3592 } 3593 3594 if (compactVis) { 3595 nl = content.querySelectorAll('h2.h2_sum'); 3596 for (var i = 0, el; el = nl[i]; i++) { el.classList.add(CN_HIDDEN); } 3597 } 3598} 3599 3600/* Adds small unicode space characters to long document titles, long class names 3601 * in particular. This allows the text to wrap. Without this, the long names 3602 * would force the document window width larger than the UI accomodates. 3603 * @param content [HTMLDIVElement] the content div element 3604 */ 3605function addWhiteSpace(content) { 3606 var title = content.querySelector('h1'), 3607 spc = String.fromCharCode(8202); 3608 3609 if (title && title.textContent.length > 40) { 3610 for (var i = 0, node; node = title.childNodes[i]; i++) { 3611 if (node.nodeType === 3) { 3612 node.nodeValue = node.nodeValue.replace(/::/g, '::' + spc); 3613 node.nodeValue = node.nodeValue.replace(/([a-z])([A-Z])/g, "\$1" + spc + "\$2"); 3614 } 3615 } 3616 } 3617} 3618 3619/* removes empty docstring divs 3620 * @param content [HTMLDIVElement] the content div element 3621 */ 3622function removeEmptyDocString(content) { 3623 var nl = content.querySelectorAll('div.docstring, div.tags'), 3624 prnt; 3625 for (var i = 0, el; el = nl[i]; i++) { 3626 if (el.textContent.trim() === '') { 3627 prnt = el.parentElement; 3628 prnt.removeChild(el); 3629 } 3630 } 3631 nl = null; 3632} 3633 3634//} @!endgroup 3635 3636//{ @!group Window & Main Doc Event Handlers 3637 3638/* Event handler for main header button click. At present, the only active 3639 * controls are the four Pane control button, which are called via oPane.mainClk. 3640 */ 3641function clkHdrBtn(e) { 3642 var tgt = e.target, 3643 tag = tgt.tagName, 3644 cls = tgt.className, 3645 id = tgt.id; 3646 3647 if (tag === 'CODE' || tag === 'svg' || tag === 'SPAN') { 3648 // move up to button (code element used for the triangles) 3649 tgt = tgt.parentElement; 3650 tag = tgt.tagName; 3651 cls = tgt.className; 3652 id = tgt.id; 3653 } else if (tag === 'rect' || tag === 'path') { 3654 tgt = tgt.parentElement.parentElement; 3655 tag = tgt.tagName; 3656 cls = tgt.className; 3657 id = tgt.id; 3658 } 3659 3660 if (tgt instanceof HTMLButtonElement) { 3661 if (tgt.disabled) return; 3662 switch (id) { 3663 case 'src': 3664 settingsCheck(); 3665 state.showSource = (_id('src').className === 'c'); 3666 if (storage) storage.yardState = JSON.stringify(state); 3667 sourceShowHide(eContent, state.showSource); 3668 break; 3669 case 'sh_settings': 3670 el = _id('settings'); 3671 el.style.willChange = 'opacity, max-height, max-width'; 3672 settingsSetData(); 3673// if (el.className === 'hidden') { 3674 if (el.className !== 'show') { 3675// el.className = ''; 3676 settingsSetCSS('in'); 3677 } else { 3678 settingsSetCSS('out'); 3679 }; 3680 break; 3681 default: 3682 settingsCheck(); 3683 if ( HDR_PANE_BTNS.indexOf(id) > -1 ) 3684 oPane.mainClk(id); 3685 break; 3686 }; 3687 } else settingsCheck(); 3688}; 3689 3690/* Event handler for main header Namespace/Object path click. Locates the URL, 3691 * then calls gotoDoc. 3692 */ 3693function clkMenu(e) { 3694 var tgt = e.target, 3695 url, 3696 cancel = false; 3697 3698 settingsCheck(); 3699 3700 if (tgt instanceof HTMLAnchorElement) { 3701 if (tgt.id === 't2_doc_top') { 3702 eContent.scrollTop = 0; 3703 cancel = true 3704 } else if (!e.ctrlKey) { 3705 if (tgt.id === 'home_no_xhr') { return true } 3706 url = tgt.href; 3707 if (url) { 3708 clickedBy = CB_OBJ_PATH; 3709 if ( /github\.io/i.test(url) && /\/_index\.html$/.test(url) ) 3710 url = url.replace(/\/_index\.html$/, '/y_index.html'); 3711 gotoDoc(url); 3712 cancel = true; 3713 } 3714 } 3715 } 3716 if (cancel) { 3717 e.stopPropagation(); 3718 e.preventDefault(); 3719 return false; 3720 } 3721} 3722 3723/* Event handler for content click. Manages the content UI. */ 3724function clkContent(e) { 3725 var tgt = e.target, 3726 tag = tgt.tagName, 3727 cls = tgt.className, 3728 clsList, 3729 id = tgt.id, 3730 eA, 3731 hash, 3732 prnt, 3733 len, 3734 cancel = false, 3735 reCls = /(toggleSource|summary_signature|h2_sum|h2_sum nodoc|cnst_a)/, 3736 reIds = /(h2_overview|t2_defined_in|t2_relations|t2_inherits)/, 3737 attrHRef = tgt.getAttribute('href'); 3738 3739 settingsCheck(); 3740 3741 // standard internal link 3742 if (attrHRef && /^#\S+/.test(attrHRef)) { return true }; 3743 3744 if (reIds.test(id)) { 3745 var t; 3746 clsList = tgt.classList; 3747 switch (id) { 3748 case 'h2_overview': 3749 state.overviewCollapsed = tgt.classList.toggle(CN_HIDDEN); 3750 if (storage) storage.yardState = JSON.stringify(state); 3751 cancel = true; 3752 break; 3753 case 't2_defined_in': 3754 t = getPrntByIO(tgt, HTMLTableRowElement).querySelector("span.defines") 3755 if (clsList.contains(CN_HIDDEN)) { 3756 clsList.remove(CN_HIDDEN); 3757 clsList.add(CN_VISIBLE); 3758 if (t) t.style.display = 'none'; 3759 } else if (clsList.contains(CN_VISIBLE)) { 3760 clsList.remove(CN_VISIBLE); 3761 clsList.add(CN_HIDDEN); 3762 if (t) t.style.display = 'inline'; 3763 } 3764 cancel = true; 3765 break; 3766 case 't2_inherits': 3767 if (clsList.contains(CN_HIDDEN)) { 3768 clsList.remove(CN_HIDDEN); 3769 clsList.add(CN_VISIBLE); 3770 } else if (clsList.contains(CN_VISIBLE)) { 3771 clsList.remove(CN_VISIBLE); 3772 clsList.add(CN_HIDDEN); 3773 } 3774 cancel = true; 3775 break; 3776 case 't2_relations': 3777 var tbody = getPrntByIO(tgt, HTMLTableElement).querySelector('tbody'); 3778 if (clsList.contains(CN_HIDDEN)) { 3779 clsList.remove(CN_HIDDEN); 3780 tbody.style.display = 'table-row-group'; 3781 state.relationsCollapsed = false;
3782 } else { 3783 clsList.add(CN_HIDDEN); 3784 tbody.style.display = 'none'; 3785 state.relationsCollapsed = true; 3786 } 3787 if (storage) storage.yardState = JSON.stringify(state); 3788 cancel = true; 3789 break; 3790 } 3791 } 3792 3793 if (!cancel && reCls.test(cls)) { 3794 if (reCls.test(tgt.parentElement.className)) { 3795 tgt = tgt.parentElement; 3796 cls = tgt.className; 3797 } else if (reCls.test(tgt.parentElement.parentElement.className)) { 3798 tgt = tgt.parentElement.parentElement; 3799 cls = tgt.className; 3800 } 3801 } 3802 cls = reCls.exec(tgt.className); 3803 if (!cancel && cls && cls[0]) { 3804 switch (cls[0]) { 3805 case 'toggleSource': 3806 var sourceCode = tgt.parentElement.parentElement.querySelector('div.source_code'); 3807 if ( /^view/.test(tgt.textContent) ) { 3808 tgt.textContent = tgt.textContent.replace(/^view/, 'hide'); 3809 sourceCode.classList.remove(CN_HIDDEN); 3810 } else { 3811 tgt.textContent = tgt.textContent.replace(/^hide/, 'view'); 3812 sourceCode.classList.add(CN_HIDDEN); 3813 } 3814 cancel = true; 3815 break; 3816 case 'summary_signature': 3817 if (eA = tgt.querySelector('a')) { 3818 cancel = true; 3819 clickedBy = CB_CONTENT; 3820 clickedTop = tgt.getBoundingClientRect().top - fwHdrHgt; 3821 if (e.ctrlKey) { 3822 window.open(eA.href, '_blank'); 3823 } else if (hash = eA.hash) { 3824 hash = decodeURIComponent(hash.slice(1)); 3825 gotoDoc(eA.pathname + '#' + hash); 3826 } else gotoDoc(eA.href); 3827 } 3828 break; 3829 case 'h2_sum nodoc': 3830 case 'h2_sum': 3831 summaryToggle(tgt); 3832 cancel = true; 3833 break; 3834 case 'cnst_a': 3835 prnt = getPrntByIO(tgt, HTMLUListElement); 3836 // ul >> div >> h2 3837 clickedBy = CB_CONTENT; 3838 clickedTop = tgt.getBoundingClientRect().top - fwHdrHgt; 3839 if (e.ctrlKey) { 3840 window.open(tgt.href, '_blank'); 3841 cancel = true; 3842 } else if (hash = tgt.hash) { 3843 hash = decodeURIComponent(hash.slice(1)); 3844 prnt.parentElement.previousElementSibling.classList.remove(CN_HIDDEN); 3845 gotoDoc(tgt.pathname + '#' + hash); 3846 } else gotoDoc(tgt.href); 3847 cancel = true; 3848 break; 3849 } 3850 } 3851 3852 // Index page 'Listings' 3853 if (tag === 'LI' && (cls === 'r1' || cls === 'r2') ) { 3854 tgt = tgt.firstElementChild; 3855 tag = 'A'; 3856 } 3857 3858 if (!cancel && !e.ctrlKey) { 3859 clickedTop = tgt.getBoundingClientRect().top - fwHdrHgt; 3860 if (tag === 'A') { 3861 eA = tgt; 3862 cancel = true; 3863 } else if (eA = tgt.parentElement) { 3864 if (eA instanceof HTMLAnchorElement) { 3865 cancel = true; 3866 } else if (eA = eA.parentElement) { 3867 if (eA instanceof HTMLAnchorElement) cancel = true; 3868 } 3869 } 3870 if (cancel && eA) { 3871 if (eA.className === 'repo') return true; 3872 clickedBy = CB_CONTENT; 3873 if (hash = eA.hash) { 3874 var a = eA.href.split('#'); 3875 // console.log(a[0] + '#' + decodeURIComponent(a[1])); 3876 cancel = gotoDoc( a[0] + '#' + decodeURIComponent(a[1]) ); 3877 } else 3878 cancel = gotoDoc(eA.href); 3879 } 3880 } 3881 if (cancel) { 3882 e.preventDefault(); 3883 e.stopPropagation(); 3884 return false; 3885 } 3886} 3887 3888function clkSettingWindow(e) { 3889 var tgt = e.target, 3890 tag = tgt.tagName, 3891 cls = tgt.className, 3892 id = tgt.id; 3893 3894 if (tag === 'SPAN' || tag === 'CODE' || tag === 'svg') { 3895 // move up to button (code element used for the triangles) 3896 tgt = tgt.parentElement; 3897 tag = tgt.tagName; 3898 cls = tgt.className; 3899 id = tgt.id; 3900 } else if (tag === 'rect' || tag === 'path') { 3901 tgt = tgt.parentElement.parentElement; 3902 tag = tgt.tagName; 3903 cls = tgt.className; 3904 id = tgt.id; 3905 } 3906 3907 if (tgt instanceof HTMLButtonElement) { 3908 if (tgt.disabled) return; 3909 switch (id) { 3910 case 'font_lrg': 3911 changeFontSize(true); 3912 break; 3913 case 'font_sml': 3914 changeFontSize(false); 3915 break; 3916 default: 3917 oPane.mainClk(id); 3918 settingsSetData(); 3919 }; 3920 }; 3921 e.preventDefault(); 3922 e.stopPropagation(); 3923 return false; 3924}; 3925 3926/* Event handler for browser forward & back navigation events. */ 3927function popState(e) { 3928 var loc; 3929 clickedBy = CB_POP_STATE; 3930 if (e.state) { 3931 gotoDoc(e.state.url); 3932 } else { 3933 loc = window.location; 3934 gotoDoc(loc.pathname + loc.hash); 3935 } 3936 e.preventDefault(); 3937} 3938 3939/* Event handler for window keydown, used for Esc & Ctrl-Alt combinations. */ 3940function winKeyDown(e) { 3941 var key = String.fromCharCode(e.which), 3942 keyU = key.toUpperCase(), 3943 keyD = key.toLowerCase(), 3944 isCtrlAlt = e.altKey && e.ctrlKey, 3945 url, 3946 cancel; 3947 3948 if (e.which === 27) { 3949 oPane.mainKD(keyD, 27); 3950 eContent.focus(); 3951 cancel = true; 3952 3953 } else if (!isCtrlAlt) { 3954 return; 3955 3956 } else if (WIN_PANE_KD.indexOf(keyD) > -1 ) { 3957 oPane.mainKD(keyD, e.which); 3958 cancel = true; 3959 3960 } else {
3961 switch (keyD) { 3962 case 'i': 3963 var nl = document.querySelectorAll('#y_menu a'); 3964 for (var i = 0, el; el = nl[i]; i++) { 3965 if (/^index/i.test(el.textContent)) { 3966 url = el.href; 3967 clickedBy = CB_OBJ_PATH; 3968 if ( /github\.io/i.test(url) && /\/_index\.html$/.test(url) ) 3969 url = url.replace(/\/_index\.html$/, '/y_index.html'); 3970 cancel = true; 3971 gotoDoc(url); 3972 break; 3973 } 3974 } 3975 break; 3976 } 3977 } 3978 if (cancel) { 3979 isWinKPTimeOut = true; 3980 e.preventDefault(); 3981 e.stopPropagation(); 3982 setTimeout( function(){ isWinKPTimeOut = false; }, 1000); 3983 return false; 3984 } 3985} 3986 3987/* Event handler window keypress, at present, only used for jumping locations in 3988 * the Method List. Does not handle Ctrl-Alt, which uses winKeyDown. 3989 */ 3990function winKeyPress(e) { 3991 var key = String.fromCharCode(e.which), 3992 cancel; 3993 3994 if (isWinKPTimeOut || document.activeElement === _id('list_search_text') || 3995 document.activeElement === _id('toc_search_text') ) 3996 return; 3997 3998 // Add main keyPress code here 3999 4000 if (e.altKey || e.ctrlKey) return; 4001 4002 if ( RE_LIST_SEARCH.test(key) ) { 4003 oList.keyPress(key); 4004 cancel = true; 4005 } 4006 if (cancel) { 4007 e.preventDefault(); 4008 e.stopPropagation(); 4009 return false; 4010 } 4011} 4012 4013/* Event handler for window resize. Sets up a timer so the screen refreshes are limited. */ 4014function winResize() { 4015 var eAct = document.activeElement, 4016 contentS = eContent.style; 4017 4018 if (contentS && contentS.fontSize !== '') { 4019 //console.log('set_FS ' + contentS.fontSize + ' ' + (typeof contentS.fontSize)); 4020 contentS.fontSize = ''; 4021 } 4022 4023 if (isTouch && eAct && eAct.id === 'list_search_text' && 4024 window.innerWidth === winWidth) { 4025 eAct.focus(); 4026 } else if (winResizeTmrId) { 4027 window.clearTimeout(winResizeTmrId); 4028 winResizeTmrId = window.setTimeout( domLayout, 200); 4029 } else { 4030 winResizeTmrId = window.setTimeout( domLayout, 200); 4031 } 4032} 4033 4034//} @!endgroup 4035 4036//{ @!group Load & Layout 4037 4038/* Called on first load and anytime the window is resized */ 4039function domLayout() { 4040 var winHeightLast = winHeight, 4041 winTypeLast = winType, 4042 charWid = 0, 4043 dockDisabled = false; 4044 4045// window.devicePixelRatio 4046 4047 e25vh = _id('y_measure_vh'); 4048 px30em = _id('y_measure_em').offsetWidth; 4049 px50Char = _id('y_measure_50pre').offsetWidth; 4050 4051 winHeight = window.innerHeight; 4052 winWidth = window.innerWidth; 4053 4054 charWid = Math.floor(50.0 * winWidth / px50Char); 4055 4056 if (charWid > MED_LRG) winType = 2; 4057 else if (charWid > SML_MED) winType = 1; 4058 else { dockDisabled = true; winType = 0; } 4059 4060// if (winTypeLast !== winType && oList) 4061 4062 if (winHeight !== winHeightLast) { 4063// if (isVHBad) vhFix(); 4064 if (winHeight < clickedTop) { 4065 clickedTop = 0.6 * winHeight; 4066 } 4067 } 4068 4069 if (winType !== winTypeLast) { 4070 oPane.locSet(winTypeLast); 4071 if (_id('settings') && _id('settings').className === '') settingsSetData(); 4072 }; 4073 // if (dbgYDebug) _id('y_debug').textContent = ' ' + charWid + ' ' + winType; 4074}; 4075 4076/* Called anytime a new doc is loaded */ 4077function docReady() { 4078 eContent.tabIndex = 1; 4079 _id('y_menu').addEventListener('click', clkMenu, false); 4080 eContent.addEventListener('click', clkContent, false); 4081} 4082 4083/* Hooks events on first doc load; these events are not affected when a doc 4084 * is loaded via XMLHttpRequest. 4085 */ 4086function hookEvents() { 4087 window.addEventListener('keydown' , winKeyDown , false); 4088 window.addEventListener('keypress', winKeyPress , false); 4089 window.addEventListener('resize' , winResize , false); 4090 window.addEventListener('popstate', popState , false); 4091} 4092 4093/* Read options */ 4094function readOptions() { 4095 if (_t2Info !== undefined) { 4096 if ('NSEP' in _t2Info) 4097 t2Opts.NSEP = _t2Info.NSEP.trim(); 4098 if ('customHeaderId' in _t2Info) 4099 t2Opts.customHeaderId = _t2Info.customHeaderId.trim(); 4100 } 4101} 4102 4103/* Used for table overflow, see method --- */ 4104function updateCSS() { 4105 var wid, t; 4106 if (oCSSRuleTable instanceof CSSRule) { 4107 wid = window.innerWidth; 4108 if (oList.d.docked && oList.d.vis) 4109 wid -= oList.e.getBoundingClientRect().width; 4110 if (oToc.d.docked && oToc.d.vis) 4111 wid -= oToc.e.getBoundingClientRect().width; 4112 wid -= 2.0 * (px30em)/30.0; 4113 oCSSRuleTable.maxWidth = Math.floor(wid) + 'px'; 4114 }; 4115}; 4116 4117function setFontSize() { 4118 var rule = getCSSRule('y_style.css', 'html, body'); 4119 if (rule && rule.style.fontSize !== state.fontSize) 4120 rule.style.fontSize = state.fontSize; 4121 px30em = _id('y_measure_em').offsetWidth; 4122 px50Char = _id('y_measure_50pre').offsetWidth; 4123 waitWidth = (isTouch ? WAIT_TOUCH : WAIT_NO_TOUCH ) * px30em/30.0; 4124 4125 if (!isFirstLoad) { 4126 settingsSetTitles(); 4127 domLayout(); 4128 }; 4129}; 4130 4131/* Changes cssRules to pixels for devices with bad vh 4132 * units, see isVHBad in {eDOMContent} 4133 */ 4134function vhFix() { 4135 var i, j, maxH, 4136 fw_hdr = _id(t2Opts.customHeaderId), 4137 winH = winHeight - 2 - (fw_hdr ? fw_hdr.offsetHeight : 0), 4138 ss, 4139 cntr, 4140 cssRules, 4141 cssRule; 4142 4143 for (i = 0; ss = document.styleSheets[i]; i++) { 4144 if ( /y_list\.css$/.test(ss.href) ) { 4145 cssRules = ss.cssRules; 4146 cntr = 0; 4147 for (j = 0; cssRule = cssRules[j]; j++) { 4148 // style 4149 switch (cssRule.selectorText) { 4150 case '#y_list.f #list_nav': 4151 maxH = (winH - oList.hdrHeight - FLT_HGT * px30em / 30.0).toFixed(0); 4152 cssRule.style.maxHeight = maxH + 'px'; 4153 cntr ++; 4154 break; 4155 case '#y_toc.f #toc_nav': 4156 maxH = (winH - oToc.hdrHeight - FLT_HGT * px30em / 30.0).toFixed(0); 4157 cssRule.style.maxHeight = maxH + 'px'; 4158 cntr ++; 4159 break; 4160 } 4161 if (cntr === 2) break; 4162 } 4163 } 4164 } 4165} 4166 4167function svgAddPath(el, opacity, d) { 4168 var p = document.createElementNS('http://www.w3.org/2000/svg', 'path'); 4169 p.setAttribute('opacity', opacity); 4170 p.setAttribute('d', d); 4171 el.appendChild(p); 4172}; 4173 4174/* Set html of SVG wait element, no need to have it in all of the content 4175 * pages 4176 */ 4177function waitHTML() { 4178 var eWait = _id('y_wait'), el; 4179 if (isTouch) { 4180 eWait.setAttribute('viewBox', '0 0 135 45'); 4181 eWait.setAttribute('width' , '135'); 4182 eWait.setAttribute('height', '45'); 4183 el = document.createElementNS('http://www.w3.org/2000/svg', 'text'); 4184 el.setAttribute('opacity', '0.6'); 4185 el.setAttribute('x', '67'); 4186 el.setAttribute('y', '30'); 4187 el.setAttribute('text-anchor', 'middle'); 4188 el.textContent = 'Waiting...'; 4189 eWait.appendChild(el); 4190 } else { 4191 eWait.setAttribute('viewBox', '0 0 90 90'); 4192 eWait.setAttribute('width' , '90'); 4193 eWait.setAttribute('height', '90'); 4194 4195 svgAddPath(eWait, '0.1', 'M 58.46 7.28 L 62.16 8.81 52.59 31.91 48.89 30.38 ' + 4196 'M 71.87 15.3 L 74.7 18.13 57.02 35.81 54.19 32.98 ' + 4197 'M 81.19 27.84 L 82.72 31.54 59.62 41.11 58.09 37.41' + 4198 'M 85 43 L 85 47 60 47 60 43 ' +
4199 'M 82.72 58.46 L 81.19 62.16 58.09 52.59 59.62 48.89 ' + 4200 'M 74.7 71.87 L 71.87 74.7 54.19 57.02 57.02 54.19 ' + 4201 'M 62.16 81.19 L 58.46 82.72 48.89 59.62 52.59 58.09 ' + 4202 'M 47 85 L 43 85 43 60 47 60 ' + 4203 'M 31.54 82.72 L 27.84 81.19 37.41 58.09 41.11 59.62 ' + 4204 'M 18.13 74.7 L 15.3 71.87 32.98 54.19 35.81 57.02 ' + 4205 'M 8.81 62.16 L 7.28 58.46 30.38 48.89 31.91 52.59'); 4206 4207 svgAddPath(eWait, '0.2', 'M 5 47 L 5 43 30 43 30 47'); 4208 svgAddPath(eWait, '0.4', 'M 7.28 31.54 L 8.81 27.84 31.91 37.41 30.38 41.11'); 4209 svgAddPath(eWait, '0.6', 'M 15.3 18.13 L 18.13 15.3 35.81 32.98 32.98 35.81'); 4210 svgAddPath(eWait, '0.8', 'M 27.84 8.81 L 31.54 7.28 41.11 30.38 37.41 31.91'); 4211 svgAddPath(eWait, '1.0', 'M 43 5 L 47 5 47 30 43 30'); 4212 } 4213} 4214 4215function firstLoad() { 4216 var newToc, 4217 t, xhr, vhHgt, 4218 url, listState, 4219 oldLibRoot = oList.libRoot; 4220 4221 waitHTML = undefined; 4222 eContent = _id('content'); 4223 e25vh = _id('y_measure_vh'); 4224// px30em = _id('y_measure_em').offsetWidth; 4225// px50Char = _id('y_measure_50pre').offsetWidth; 4226 4227 isServer = (_id('y_menu').className === 'server'); 4228 readOptions(); 4229 4230 winTitle = document.querySelector('head title').textContent; 4231 4232 oPane.firstDOMLoad(); 4233 4234 aDOMCur.href = window.location.href; 4235 aDOMNext.href = window.location.href; 4236 4237 for (var i = 0, cssRules, ss; ss = document.styleSheets[i]; i++) { 4238 if ( /y_style\.css$/.test(ss.href)) { 4239 cssRules = ss.cssRules; 4240 cntr = 0; 4241 for (var j = 0, cssRule; cssRule = cssRules[j]; j++) { 4242 if (cssRule.selectorText === 'div.y_table') { 4243 oCSSRuleTable = cssRule; 4244 break; 4245 } 4246 } 4247 } 4248 } 4249 4250 vhHgt = (4 * e25vh.getBoundingClientRect().width).toFixed(0); 4251 winHeight = window.innerHeight; 4252 4253 //hdrDbg('v' + vhHgt + '_w' + winHeight); 4254 4255 // for iOS 4256 if ( Math.abs(winHeight - vhHgt)/winHeight > 0.01 || t2Opts.customHeaderId ) { 4257 t = _id(t2Opts.customHeaderId); 4258 if (t) fwHdrHgt = t.offsetHeight; 4259 isVHBad = true; 4260 // hdrDbg('v' + vhHgt + '_w' + winHeight + ' called vhFix'); 4261 vhFix(); 4262 } 4263 4264 domLayout(); 4265 updateCSS(); 4266 oList.e.tabIndex = 2; 4267 4268 // must run before addContent 4269 if (t2GA instanceof Function && !t2GAInit) { 4270 t2GA( 'create', 'UA-79746991-1', 'auto'); 4271 t2GA( 'set', 'anonymizeIp', true); 4272 t2GAInit = true; 4273 } 4274 4275 newToc = addContent(eContent, document); 4276 oToc.nav.replaceChild(newToc.cloneNode(true), oToc.items); 4277 oToc.items = _id('toc_items'); 4278 newToc = null; 4279 4280 hookEvents(); 4281 docReady(); 4282 window.removeEventListener('DOMContentLoaded', eDOMContent); 4283 hookEvents = undefined; 4284 isFirstLoad = false; 4285} 4286 4287/* Event handler for DOMContentLoaded */ 4288function eDOMContent(e) { 4289 eContent = _id('content'); 4290 setFontSize(); 4291 waitHTML(); 4292 commonLoad(); 4293 firstLoad(); 4294 4295 if ( typeof hljs !== 'undefined' && hljs.highlightElement instanceof Function ) { 4296 hljs.configure({ 4297 ignoreUnescapedHTML: true 4298 }); 4299 }; 4300} 4301 4302//} @!endgroup 4303 4304window.addEventListener('DOMContentLoaded', eDOMContent, false); 4305 4306})(t2Info);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.