1/* 2 * Responsible for flyout menus within the editor + on a published page. 3 * Also responsible for condensing overflowing nav and making a "more..." link. 4 * 5 6 * Author: Adam Shaw 7 */ 8 9(function($) { 10 11 12 /****************************** publicly available functions ****************************/ 13 14 var moreItemHTML; 15 var activeLiId; 16 var currentPageId; 17 var stylePrefix = window.STYLE_PREFIX || 'weebly'; 18 var SLIDE_DURATION = 300; 19 20 // called from a published page 21 window.initPublishedFlyoutMenus = function(topLevelSummary, cpid, moreItemHTML, aLiId, isPreview) { 22 currentPageId = cpid; 23 if (topLevelSummary.length > 0) { 24 var go = function() { 25 activeLiId = aLiId; 26 var container = $("<div id='" + stylePrefix + "-menus' />").appendTo('body'); 27 var firstItem = navElm(topLevelSummary[0].id); 28 if (firstItem) { 29 window.navFlyoutMenu = new FlyoutMenu(firstItem.parent(), { 30 relocate: container, 31 aLiId: aLiId 32 }); 33 condenseNav(topLevelSummary, moreItemHTML); 34 } 35 } 36 if (isPreview) { 37 go(); // css has been written in html <style> tag, no need to check if loaded 38 }else{ 39 whenThemeCSSLoaded(go); 40 } 41 } 42 }; 43 44 // called from the editor 45 window.initEditorFlyoutMenus = function() { 46 whenThemeCSSLoaded(function() { 47 function go() { 48 var topLevelSummary = Weebly.PageManager.getTopLevelSummary(); 49 if (topLevelSummary.length > 0) { 50 var listItem0 = navElm(topLevelSummary[0].id); 51 if (listItem0) { 52 var listElement = listItem0.parent(); 53 if (!listElement.is('table,tbody,thead,tr')) { 54 window.navFlyoutMenu = new FlyoutMenu(listElement, { 55 relocate: '#' + stylePrefix + '-menus' 56 }); 57 58 moreItemHTML = renderItem({ title: /*tl(*/'more...'/*)tl*/ }, false, currentNormalItem); 59 moreItemHTML = 60 "<span class='" + stylePrefix + "-nav-handle " + stylePrefix + "-nav-more'>" + 61 moreItemHTML + 62 "</span>"; 63 condenseNav(topLevelSummary, moreItemHTML); 64 }else{ 65 window.navFlyoutMenu = null; 66 } 67 }else{ 68 window.navFlyoutMenu = null; 69 } 70 }else{ 71 window.navFlyoutMenu = null; 72 } 73 } 74 if ($.browser.webkit) { 75 // this solves a webkit bug where the <span>s within the <ul> are displayed as block 76 // this problem has nothing to do with the flyout code, but this was the most convenient place to put it ~ashaw 77 var handles = $('#icontent span.' + stylePrefix + '-nav-handle'); 78 handles.hide(); 79 setTimeout(function() { 80 handles.show(); 81 go(); 82 },0); 83 }else{ 84 go(); 85 } 86 }); 87 }; 88 89 // called from the editor when nav positioning might have changed 90 window.refreshNavCondense = function(callback) { 91 if (window.navFlyoutMenu) { 92 //console.log('refresh'); 93 condenseNav(Weebly.PageManager.getTopLevelSummary(), moreItemHTML); 94 } 95 }; 96 97 window.disableFlyouts = false; 98 99 100 101 /*********************************** flyout menu class ************************************/ 102 103 window.FlyoutMenu = function(mainList, options) { 104 105 mainList = $(mainList); // the element that contains all the nav elements 106 options = options || {}; 107 108 // settings (an attempt at making FlyoutMenu portable) 109 var listTag = options.listTag ? options.listTag.toLowerCase() : 'ul'; 110 var itemTag = options.itemTag ? options.itemTag.toLowerCase() : 'li'; 111 var delay = (options.delay || 0.5) * 1000; 112 113 // if specified, all submenus will be detached from original place in DOM and put in here 114 var relocate = options.relocate ? $(options.relocate) : false; 115 116 // FYI 117 // a 'handle' is an element that contains the templatable HTML for each page's nav link 118 // a 'handle' may be a wrapping SPAN element (with className 'PREFIX-nav-handle') 119 // OR it may be the item itself (such as an LI) 120 121 var allItems; // list of all nav items 122 // (the first child within a handle OR the handle itself) 123 124 125 // 126 // attach all event handlers and do state-keeping for flyout menus 127 // 128 129 function initItem(item) { 130 131 item.css('position', 'relative'); // this gives more accurate offsets 132 item.find('a').css('position', 'relative'); // more accurate offset (prevents IE bug) 133 134 // states 135 var isSliding = false;
136 var isExpanded = false; 137 var isMouseoverItem = false; 138 var mouseoverCnt = 0; 139 140 var slidVertically = false; 141 var slidRight = false; 142 143 var sublistWrapper; // a DIV.PREFIX-menu-wrap OR null 144 var sublist; // a UL.PREFIX-menu OR null 145 146 147 // 148 // expand a sublist on mouseover 149 // 150 151 function itemMouseover() { 152 if (disableFlyouts) return false; 153 mouseoverCnt++; 154 isMouseoverItem = true; 155 if (!isExpanded && !isSliding) { 156 if (sublist) { 157 // when a sublist is expanded, immediately contract all siblings' sublists 158 getSiblings(item).each(function(i, siblingNode) { 159 if (siblingNode._flyoutmenu_contract) { 160 siblingNode._flyoutmenu_contract(); 161 } 162 }); 163 expandSublist(); 164 } 165 } 166 } 167 168 169 // 170 // contract sublist on mouseout (after delay) 171 // 172 173 function itemMouseout() { 174 if (disableFlyouts) return false; 175 isMouseoverItem = false; 176 if (isExpanded) { 177 var mouseoverCnt0 = mouseoverCnt; 178 setTimeout(function() { 179 if (mouseoverCnt == mouseoverCnt0 && isExpanded && !isSliding) { 180 contractSublist(); 181 } 182 }, delay); 183 } 184 } 185 186 187 // 188 // prevent contracting when sublist is moused over 189 // 190 191 function sublistWrapperMouseover() { 192 if (disableFlyouts) return false; 193 mouseoverCnt++; 194 } 195 196 197 // 198 // do item's sublist's expand animation 199 // 200 201 function expandSublist() { 202 isSliding = true; 203 var opts = { 204 wrapper: sublistWrapper, 205 duration: SLIDE_DURATION, 206 complete: function() { // when animation has finished 207 isSliding = false; 208 isExpanded = true; 209 if (!isMouseoverItem) { 210 // if mouse was not over when animation finished, immediately contract 211 contractSublist(); 212 }else{ 213 // attach methods for later hiding/contracting 214 item[0]._flyoutmenu_contract = contractSublist; // assign to DOM node 215 item[0]._flyoutmenu_hide = function() { // 216 isSliding = false; 217 isExpanded = false; 218 isMouseoverItem = false; 219 item[0]._flyoutmenu_contract = null; 220 item[0]._flyoutmenu_hide = null; 221 sublistWrapper.hide(); 222 }; 223 } 224 } 225 }; 226 var massCoords = getItemMassCoords(item); 227 228 // need to show it for IE8 to get the correct offsetParent 229 sublistWrapper.css('left', -10000); 230 sublistWrapper.show(); 231 232 var localOriginElement = sublistWrapper.offsetParent(); 233 var localOrigin = localOriginElement.is('body') ? {top:0,left:0} : localOriginElement.offset(); 234 // ^ special case body. jQuery provides inaccurate offset for body. always 0,0 235 236 sublistWrapper.hide(); 237 sublist.show(); // so calls to sublistWrapper.outerWidth() are correct 238 239 if (inVerticalList(item, true, options.aLiId)) { 240 // slide right/left on vertical nav 241 slidVertically = false; 242 sublistWrapper.css('top', -localOrigin.top + massCoords[0].top); 243 var w = sublistWrapper.outerWidth(); 244 if (massCoords[1].left + w > $('body').outerWidth()) { 245 slidRight = false; 246 sublistWrapper.css('left', -localOrigin.left + massCoords[0].left - w); 247 opts.direction = 'right'; 248 sublist.show('slide', opts); 249 }else{ 250 slidRight = true; 251 sublistWrapper.css('left', -localOrigin.left + massCoords[1].left); 252 opts.direction = 'left'; 253 sublist.show('slide', opts); 254 } 255 }else{ 256 // slide down on horizontal nav 257 slidVertically = true; 258 sublistWrapper.css('top', -localOrigin.top + massCoords[1].top); 259 var w = sublistWrapper.outerWidth(); 260 if (massCoords[0].left + w > $('body').outerWidth()) { 261 sublistWrapper.css('left', -localOrigin.left + massCoords[1].left - w); 262 }else{ 263 sublistWrapper.css('left', -localOrigin.left + massCoords[0].left); 264 } 265 opts.direction = 'up'; 266 sublist.show('slide', opts); 267 } 268 } 269 270 271 // 272 // do item's sublist's contract animation 273 // 274 275 function contractSublist(mouseoverHack) { 276 if (disableFlyouts || !item.parent().length) { // no parentNode?? removed from dom already? wtf!? 277 // contractSublist is often called from a delay, might have been disabled in that time 278 return; 279 } 280 if (mouseoverHack) { 281 // IE6 wasn't registering the mouseout 282 isMouseoverItem = false;
283 } 284 isSliding = true; 285 item[0]._flyoutmenu_contract = null; 286 item[0]._flyoutmenu_hide = null; 287 var opts = { 288 wrapper: sublistWrapper, 289 duration: SLIDE_DURATION, 290 complete: function() { 291 isSliding = false; 292 isExpanded = false; 293 if (isMouseoverItem) { 294 // if mouseleft, but re-entered before animation finished 295 // immediately expand sublist again 296 expandSublist(); 297 } 298 } 299 } 300 if (slidVertically) { 301 opts.direction = 'up'; 302 sublist.hide('slide', opts); 303 }else{ 304 if (slidRight) { 305 opts.direction = 'left'; 306 sublist.hide('slide', opts); 307 }else{ 308 opts.direction = 'right'; 309 sublist.hide('slide', opts); 310 } 311 } 312 } 313 314 315 // 316 // initialize submenu and attach events 317 // 318 319 sublist = getSublist(item, listTag); 320 if (sublist) { 321 sublistWrapper = sublist.parent(); 322 sublistWrapper.css('position', 'absolute'); 323 sublistWrapper.hide(); // should already be display:none, but just in case 324 if (relocate) { 325 // since sublist is no longer a descendant of the item, mouse events 326 // wont cascade. simulate this 327 sublistWrapper.on('mouseover', itemMouseover); 328 sublistWrapper.on('mouseout', itemMouseout); 329 }else{ 330 // keep the submenu alive... 331 sublistWrapper.on('mouseover', sublistWrapperMouseover); 332 } 333 } 334 item.on('mouseover', itemMouseover); 335 item.on('mouseout', itemMouseout); 336 337 338 // 339 // attach a method for removing registered events 340 // (returns the sublist wrapper) 341 // 342 343 item[0]._flyoutmenu_destroy = function(removeSublist) { // attach to raw DOM node 344 item.off('mouseover', itemMouseover); 345 item.off('mouseout', itemMouseout); 346 if (removeSublist) { 347 if (sublistWrapper) { 348 return sublistWrapper.remove(); // detach before returning 349 } 350 } 351 else if (sublistWrapper) { 352 if (relocate) { 353 sublistWrapper.off('mouseover', itemMouseover); 354 sublistWrapper.off('mouseout', itemMouseout); 355 }else{ 356 sublistWrapper.off('mouseover', sublistWrapperMouseover); 357 } 358 return sublistWrapper; 359 } 360 }; 361 362 } 363 364 365 // 366 // methods for the FlyoutMenu object 367 // 368 369 // close all submenus with an animation 370 this.contract = function() { 371 allItems.each(function(i, itemNode) { 372 if (itemNode._flyoutmenu_contract) { 373 itemNode._flyoutmenu_contract(true); 374 } 375 }); 376 }; 377 378 // hide all submenus immediately 379 this.hideSubmenus = function() { 380 allItems.each(function(i, itemNode) { 381 if (itemNode._flyoutmenu_hide) { 382 itemNode._flyoutmenu_hide(); 383 } 384 }); 385 }; 386 387 // detach all event handlers 388 this.destroy = function() { 389 allItems.each(function(i, itemNode) { 390 if (itemNode._flyoutmenu_destroy) { 391 itemNode._flyoutmenu_destroy(); 392 } 393 }); 394 }; 395 396 // initialize a top level item that has already been placed into mainList 397 this.addItem = function(handle) { // todo: rename initTopLevelItem() 398 handle = $(handle); 399 var item = getRealTopLevelItem(handle); 400 if (item.length) { 401 initItem(item); 402 var sublist = getSublist(item, listTag); 403 if (sublist) { 404 sublist.find(itemTag).each(function(i, itemNode) { // init all subitems 405 initItem($(itemNode)); 406 }); 407 } 408 if (relocate && sublist) { 409 relocate.append(sublist.parent()); // relocate sublist's wrap 410 } 411 allItems = allItems.add(item); 412 writeOrderingClassNames(); 413 } 414 }; 415 416 // detach an item's event handlers and remove from DOM 417 this.removeItem = function(handle) { // todo: rename 418 handle = $(handle); 419 var item = getRealTopLevelItem(handle); 420 if (item.length) { 421 if (item[0]._flyoutmenu_destroy) { 422 item[0]._flyoutmenu_destroy(true); 423 } 424 item.remove(); 425 allItems = allItems.not(item); 426 writeOrderingClassNames(); 427 } 428 }; 429 430 // accessor 431 this.getMainList = function() { 432 return mainList; 433 }; 434 435 436 // 437 // initialize allItems and relocate 438 // 439 440 function writeOrderingClassNames() { 441 var i = 1; 442 getTopLevelItems(mainList).each(function(i, itemNode) { 443 itemNode.className = itemNode.className.replace(/wsite-nav-\w+/, ''); 444 var item = $(itemNode); 445 if (item.css('display') != 'none') { 446 item.addClass('wsite-nav-' + i); 447 i++; 448 } 449 }); 450 } 451 452 allItems = getAllItems(mainList, itemTag); 453 allItems.each(function(i, itemNode) { 454 initItem($(itemNode)); 455 }); 456 writeOrderingClassNames(); 457 458 if (relocate) { 459 getTopLevelItems(mainList).each(function(i, itemNode) { 460 var sublist = getSublist($(itemNode), listTag); 461 if (sublist) { 462 relocate.append(sublist.parent()); 463 } 464 }); 465 } 466 467 }; 468 469 470 471 472 473 /****************************** more... link and menu *****************************/ 474 475 function condenseNav(topLevelSummary, moreItemHTML) { // can be called repeatedly for updating 476 if (window.DISABLE_NAV_MORE) return; 477 //console.log('condenseNav'); 478 var cpid = window.currentPage || currentPageId; 479 var mainList = navFlyoutMenu.getMainList(); 480 var mainListChildren = mainList.children(); 481 var moreHandle; 482 if (mainListChildren.length > 0) { 483 moreHandle = mainListChildren.eq(-1).filter('.' + stylePrefix + '-nav-more'); 484 if (!moreHandle.length) { 485 moreHandle = undefined; 486 } 487 } 488 var alreadyMore = false;
489 if (moreHandle) { 490 moreHandle.hide(); 491 alreadyMore = true; 492 } 493 var isVertical; 494 var handles = []; // holds all the handles up til the breaking element 495 var itemCoords = []; 496 var breakingHandle; 497 var breakingIndex; 498 var verticalContainer; 499 var verticalMaxY; 500 for (var i=0; i<topLevelSummary.length; i++) { 501 var handle = navElm(topLevelSummary[i].id); 502 handle.show(); 503 } 504 for (var i=0; i<topLevelSummary.length; i++) { 505 var handle = navElm(topLevelSummary[i].id); 506 var item = getRealTopLevelItem(handle); 507 if (!item) continue; 508 var coords = getItemMassCoords(item); 509 if (i == 1) { 510 isVertical = Math.abs(coords[0].top - itemCoords[0][0].top) > Math.abs(coords[0].left - itemCoords[0][0].left); 511 if (isVertical) { 512 verticalContainer = item.closest('.wsite-nav-vertical'); 513 if (verticalContainer.length) { 514 verticalMaxY = verticalContainer.offset().top + (parseInt(verticalContainer.css('padding-top')) || 0) + verticalContainer.height(); 515 } 516 } 517 } 518 else if (!isVertical) { 519 if (i > 1 && Math.abs(coords[0].top - itemCoords[i-1][0].top) > 5) { 520 breakingHandle = handle; 521 breakingIndex = i; 522 break; 523 } 524 } 525 else { // is vertical 526 if (coords[1].top > verticalMaxY) { 527 breakingHandle = handle; 528 breakingIndex = i; 529 break; 530 } 531 } 532 handles.push(handle); 533 itemCoords.push(coords); 534 } 535 if (breakingHandle) { 536 if (moreHandle) { 537 moreHandle.show(); 538 }else{ 539 var temp = $("<div/>"); 540 temp.html(moreItemHTML); 541 moreHandle = temp.children().first(); 542 moreHandle.find('a').each(function(i, moreAnchorNode) { 543 $(moreAnchorNode) 544 .on('click', function() { return false }) 545 .css('position', 'relative') // match what initItem does 546 .attr('id', stylePrefix + '-nav-more-a'); 547 }); 548 mainList.append(moreHandle); 549 } 550 var moreItem = getRealTopLevelItem(moreHandle); 551 moreItem.css('position', 'relative'); // match what initItem does 552 var hiddenItemIndices = []; 553 for (var i=breakingIndex; i<topLevelSummary.length; i++) { 554 navElm(topLevelSummary[i].id).hide(); 555 hiddenItemIndices.push(i); 556 } 557 if (!isVertical) { 558 var firstItem = getRealTopLevelItem(navElm(topLevelSummary[0].id)); 559 for (var i=breakingIndex-1; i>=0; i--) { 560 var firstItemCoords = getItemMassCoords(firstItem); 561 var moreCoords = getItemMassCoords(moreItem); 562 if (Math.abs(moreCoords[0].top - firstItemCoords[0].top) > 5) { 563 handles[i].hide(); 564 hiddenItemIndices.unshift(i); 565 }else{ 566 break; 567 } 568 } 569 } 570 if (hiddenItemIndices.length == 0) { 571 // no items were hidden, no need for more... 572 moreHandle.remove(); 573 } 574 else if (hiddenItemIndices.length == topLevelSummary.length) { 575 // all items were hidden, revert back 576 for (var i=0; i<hiddenItemIndices.length; i++) { 577 navElm(topLevelSummary[hiddenItemIndices[i]].id).show(); 578 } 579 moreHandle.remove(); 580 } 581 else { 582 if (!alreadyMore) { 583 var wrap = $("<div/>"); 584 wrap.addClass(stylePrefix+'-menu-wrap'); 585 var ul = $("<ul/>"); 586 ul.addClass(stylePrefix+'-menu'); 587 wrap.append(ul); 588 for (var j=0; j<hiddenItemIndices.length; j++) { 589 var pageSummary = topLevelSummary[hiddenItemIndices[j]]; 590 var liID = stylePrefix + '-nav-' + pageSummary.id; 591 var li = $("<li id='" + liID + "' />"); 592 if (liID == cpid) { 593 li.addClass(stylePrefix + '-nav-current'); 594 } 595 var a = $("<a/>"); 596 if (pageSummary.onclick) { 597 a.attr('href', '#'); 598 a.on('click', pageSummary.onclick); 599 }else{ 600 var url = pageSummary.url; 601 if (window.IS_ARCHIVE || url.match(/^http:\/\//)) { 602 a.attr('href', url); 603 }else{ 604 a.attr('href', '/' + url); 605 } 606 } 607 if (pageSummary.onmouseover) { 608 a.on('mouseover', pageSummary.onmouseover); 609 } 610 if (pageSummary.onmouseout) { 611 a.on('mouseout', pageSummary.onmouseout); 612 } 613 li.append(a); 614 var submenu = getRealTopLevelItem(navElm(topLevelSummary[hiddenItemIndices[j]].id))[0]._flyoutmenu_destroy(); 615 a.html(
616 "<span class='" + stylePrefix + "-menu-title'>" + 617 pageSummary.title + 618 "</span>" + 619 (submenu ? "<span class='" + stylePrefix + "-menu-arrow'>></span>" : '') 620 ); 621 if (submenu) { 622 li.append(submenu); 623 } 624 ul.append(li); 625 } 626 moreItem.append(wrap); 627 navFlyoutMenu.addItem(moreItem); 628 if (window.showEvent) { 629 showEvent('navMore'); 630 } 631 } 632 } 633 } 634 } 635 636 637 638 639 640 /************************ helpers for navigating and querying items/sublists/etc ********************/ 641 642 function inVerticalList(item, strict, aLiId) { 643 var list = item.parent(); 644 if (list.hasClass(stylePrefix + '-nav-handle')) { 645 list = list.parent(); 646 } 647 var allItems = getTopLevelItems(list, strict, aLiId); 648 if (allItems.length >= 2) { 649 var o1 = allItems.eq(0).offset(); 650 var o2 = allItems.eq(1).offset(); 651 var diff = Math.abs(o1.left - o2.left) - Math.abs(o1.top - o2.top); 652 if (diff != 0) { 653 return diff < 0; 654 } 655 } 656 return !isItemTopLevel(item); 657 // default to returning false for top level user-defined css 658 // and true for weebly-created submenus 659 } 660 661 function getTopLevelItems(list, strict, aLiId) { 662 var res = []; 663 list.children().each(function(i, handleNode) { 664 var handle = $(handleNode); 665 if (!strict || 666 handle.hasClass(stylePrefix + '-nav-handle') || 667 handle.hasClass(stylePrefix + '-nav-more') || 668 handleNode.id.match(/^pg/) || 669 (aLiId && handleNode.id==aLiId)) { 670 var item = getRealTopLevelItem(handle); 671 if (item.length) { 672 res.push(item[0]); 673 } 674 } 675 }); 676 return $(res); 677 } 678 679 function getRealTopLevelItem(item) { // todo: rename to getItemFromHandle() 680 if (item.hasClass(stylePrefix + '-nav-handle')) { 681 item = item.children().first(); 682 } 683 if (!item.hasClass(stylePrefix + '-menu-wrap')) { 684 // sometimes with SPAN handles, markup was invalid and DOM messed up 685 // so make sure item is not a menu 686 return item; 687 } 688 } 689 690 function getAllItems(list, itemTag) { 691 // get top level and all descendant items 692 return list.find(itemTag).add(getTopLevelItems(list)); 693 // we want this list to be unique. jQuery already does this for us (for elements in DOM) 694 } 695 696 function getSiblings(item) { 697 if (item.parent().hasClass(stylePrefix + '-nav-handle')) { 698 return item.parent().siblings().children(':first-child'); 699 }else{ 700 // items aren't wrapped by separate handles 701 return item.siblings(); 702 } 703 } 704 705 function getSublist(item, listTag) { 706 var sublist = item.find(listTag).first(); 707 if (!sublist.length) { 708 var next = item.next(); 709 if (next.hasClass(stylePrefix + '-menu-wrap')) { 710 // sometimes with SPAN handles, markup is invalid, and it 711 // makes the sublist a sibling AFTER the item 712 sublist = next.children().first(); 713 } 714 } 715 if (!sublist.length) { 716 sublist = undefined; 717 } 718 return sublist; 719 } 720 721 function isItemTopLevel(item) { 722 var list = item.parent(); 723 if (list.hasClass(stylePrefix + '-nav-handle')) { 724 list = list.parent(); 725 } 726 return !list.hasClass(stylePrefix + '-menu'); 727 } 728 729 function getItemMassCoords(item) { 730 // look at the item and its A tag and return the largest rectangle of space it takes up 731 // NOTE: we are still using offsetHeight/offsetWidth because jQuery 1.7.2 had a bug where 732 // getting curCSS on zero-height inline-displayed elements returned wrong value 733 // (because it converted to block first) 734 var anchor = item.is('a') ? item : item.find('a'); 735 var p1 = item.offset(); 736 var p2 = { top:p1.top+item[0].offsetHeight, left:p1.left+item[0].offsetWidth }; 737 if (!anchor) { 738 // messed up DOM (SPAN's around TD's and such) sometimes pushes A tag outside of item 739 return [p1, p2]; 740 } 741 var p3 = anchor.offset(); 742 var p4 = { top:p3.top+anchor[0].offsetHeight, left:p3.left+anchor[0].offsetWidth }; 743 var p5, p6; 744 if (Math.abs(p1.left - p2.left) < 10) { // a tag is really small, doen't have any mass.. 745 // the inner A tag is probably floated and the LI isn't. lame. just use A tag's coords 746 p5 = p3; 747 p6 = p4; 748 }else{ 749 p5 = { top:Math.min(p1.top, p3.top), left:Math.min(p1.left, p3.left) }; 750 p6 = { top:Math.max(p2.top, p4.top), left:Math.max(p2.left, p4.left) }; 751 } 752 return [p5, p6]; 753 } 754 755 function navElm(id) { // todo: rename to getHandle() 756 var elm = $('#pg' + id); 757 if (!elm.length && activeLiId) { 758 elm = $('#' + activeLiId); 759 } 760 if (elm.length) { 761 return elm; 762 } 763 } 764 765 766 767 768 /************************** helpers for theme-css-loaded detection ***********************/ 769 770 function isThemeCSSLoaded() { 771 for (var i=0; i<document.styleSheets.length; i++) { 772 try { 773 if (document.styleSheets[i].title == stylePrefix+'-theme-css') { 774 var sheet = document.styleSheets[i]; 775 var rules = sheet.cssRules || sheet.rules; 776 return rules && rules.length > 0; 777 } 778 } 779 catch (err) {} 780 } 781 return false;
782 } 783 784 function whenThemeCSSLoaded(callback) { 785 if (isThemeCSSLoaded()) { 786 callback(); 787 }else{ 788 var intervalID = setInterval(function() { 789 if (isThemeCSSLoaded()) { 790 clearInterval(intervalID); 791 callback(); 792 } 793 }, 200); 794 } 795 } 796 797 if (!window.whenThemeCSSLoaded) { 798 window.whenThemeCSSLoaded = whenThemeCSSLoaded; 799 } 800 801 802})(Weebly.jQuery);
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.