1// Copyright: Copyright 2016 Bitsbox. 2// License: All Rights Reserved. 3 4/** 5 * @fileoverview Provide the BitsboxNavBar class. 6 */ 7 8/** 9 * A handy namespace to hang things off of. 10 * @type {Object} 11 */ 12var codepops = codepops || {}; 13 14 15/** 16 * A nested datastructure describing everything on the navbar. 17 * @type {Object} 18 */ 19codepops.navItems = { 20 /*'For Home': { 21 'Overview': { href: '/#overview-panel', 22 id: 'navbar-link-home-overview' }, 23 'Who it\'s for': { href: '/#who-panel', id: 'navbar-link-home-who' }, 24 'How it works': { href: '/#how-panel', id: 'navbar-link-home-how' }, 25 'Why Bitsbox?': { href: '/#why-panel', id: 'navbar-link-home-why' }, 26 'Pricing': { href: 'https://subscribe.bitsbox.com/', 27 id: 'navbar-link-home-store' }, 28 href: '/', 29 id: 'navbar-link-home-home' 30 }, 31 32 'Schools': { 33 'Overview': { href: '/teachers/#bitsbox-school-products', 34 id: 'navbar-link-schools-overview' }, 35 'FAQ': { href: '/teachers/#faq', 36 id: 'navbar-link-schools-started' }, 37 'School Products': { href: 'https://subscribe.bitsbox.com/details/school-products.html', 38 id: 'navbar-link-schools-shopp2' }, 39 href: '/teachers', 40 id: 'navbar-link-schools-home' 41 }, 42 43 'Homeschool': { 44 'Overview': { href: '/homeschool', 45 id: 'navbar-link-homeschool-overview' }, 46 'Subscriptions': { href: 'https://subscribe.bitsbox.com', 47 id: 'navbar-link-homeschool-store' }, 48 href: '/homeschool', 49 id: 'navbar-link-homeschool-home' 50 }, 51 */ 52 'Home': { 53 /*'Subscriptions': { href: 'https://subscribe.bitsbox.com/', 54 id: 'navbar-link-store-subscriptions' }, 55 'School Products': { href: 'https://subscribe.bitsbox.com/details/school-products.html', 56 id: 'navbar-link-store-shopp2' }, 57 'Gift Set': { href: 'https://subscribe.bitsbox.com/shop/product/6170909776_b%27bitsbox-gift-set%27', 58 id: 'navbar-link-store-gift-set' }, 59 'Complete Your Set': { href: 'https://subscribe.bitsbox.com/details/completeyourset.html', 60 id: 'navbar-link-store-shopp3' }, 61 'Other': { href: 'https://subscribe.bitsbox.com/details/otherproducts.html', 62 id: 'navbar-link-store-shopp1' },*/ 63 href: 'https://bitsbox.com/', 64 id: 'navbar-link-store-home' 65 }, 66 67 'Store': { 68 /*'Subscriptions': { href: 'https://subscribe.bitsbox.com/', 69 id: 'navbar-link-store-subscriptions' }, 70 'School Products': { href: 'https://subscribe.bitsbox.com/details/school-products.html', 71 id: 'navbar-link-store-shopp2' }, 72 'Gift Set': { href: 'https://subscribe.bitsbox.com/shop/product/6170909776_b%27bitsbox-gift-set%27', 73 id: 'navbar-link-store-gift-set' }, 74 'Complete Your Set': { href: 'https://subscribe.bitsbox.com/details/completeyourset.html', 75 id: 'navbar-link-store-shopp3' }, 76 'Other': { href: 'https://subscribe.bitsbox.com/details/otherproducts.html', 77 id: 'navbar-link-store-shopp1' },*/ 78 href: 'https://subscribe.bitsbox.com/', 79 id: 'navbar-link-store-home' 80 }, 81 82 'Reviews': { 83 /*'Parent Reviews': { href: '/reviews/#parent-review', 84 id: 'navbar-link-reviews-parent' }, 85 'Teacher Reviews': { href: '/reviews/#teacher-review', 86 id: 'navbar-link-reviews-teacher' }, 87 'Kid Reviews': { href: '/reviews/#kid-review', 88 id: 'navbar-link-reviews-kids' },*/ 89 href: '/reviews/', 90 id: 'navbar-link-reviews-home' 91 }, 92 93 'Blog': { 94 /*'Articles': { href: '/blog/#top', id: 'navbar-link-blog-articles' }, 95 'Contributors': { href: '/blog/#contributors', 96 id: 'navbar-link-blog-contributors' }, 97 'Join Mailing List': { href: '/blog/#join', 98 id: 'navbar-link-blog-email' },*/ 99 href: '/blog/', 100 id: 'navbar-link-blog-home' 101 }, 102 103 'Help': { 104 'Get Help': { href: '/support.html#help', 105 id: 'navbar-link-support-help' }, 106 /*'About Us': { href: '/about.html', 107 id: 'navbar-link-support-about' }, 108 'Jobs': { href: '/about.html', 109 id: 'navbar-link-support-jobs' },*/ 110 'Contact Us': { href: '/support.html#contact', 111 id: 'navbar-link-support-contact' }, 112 'FAQ': { href: '/faq.html', id: 'navbar-link-support-faq' }, 113 'Terms': { href: '/terms.html', id: 'navbar-link-support-terms' }, 114 href: '/support.html', 115 id: 'navbar-link-support-home' 116 } 117 }; 118 119 120/** 121 * An object that creates a consistent navigation bar across the 122 * various Bitsbox websites. 123 * 124 * @param {Object=} opt_settings A hash of optional settings. 125 * @constructor 126 */ 127codepops.BitsboxNavBar = function(opt_settings) { 128 var settings = opt_settings || {}; 129 130 /** 131 * Contains a reference to the window. Useful for dependency injection. 132 * @type {Window} 133 * @private 134 */ 135 this.window_ = settings['window'] || window; 136 137 /** 138 * Contains a reference to the window. Useful for dependency injection. 139 * @type {Document} 140 * @private 141 */ 142 this.document_ = settings['document'] || this.window_.document; 143 144 /** 145 * Contains the hostname the navbar believes it is running under, such as 146 * 'subscribe.bitsbox.com' or 'bitsbox.com' or 'localhost' or 147 * 'bitsboxstaging.firebaseapp.com'. Useful for dependency injection. 148 * @type {string} 149 * @private 150 */ 151 this.hostname_ = settings['hostname'] || this.window_.location.hostname; 152 153 // Time to generate the actual markup. 154 var navPanel = this.document_.createElement('div'); 155 navPanel.className = 'bitsbox-navbar-panel'; 156 157 /** 158 * A pointer to the popdown navigation bar that becomes visible on mobile. 159 * @type {Element} 160 */ 161 this.popdownPanel = this.document_.createElement('div'); 162 this.popdownPanel.className = 'bitsbox-popdown hidden'; 163 164 // Hide the navigation panel until the CSS loads to override it. 165 navPanel.style.visibility = 'hidden'; 166 167 // Load the CSS we need to make the navbar pretty. 168 var css = this.document_.createElement('link'); 169 css.type = 'text/css'; 170 css.rel = 'stylesheet'; 171 if (this.isRunningOnCrateJoy()) { 172 css.href = 'https://bitsbox.com/lib/bitsboxnavbar/bitsboxnavbar.css'; 173 } else { 174 css.href = '/lib/bitsboxnavbar/bitsboxnavbar.css'; 175 } 176 this.document_.head.appendChild(css); 177 178 // Make a categories DIV with one SPAN per top-level nav item. 179 var categoriesDiv = this.document_.createElement('div'); 180 categoriesDiv.id = 'bitsbox-categories-panel'; 181 182 // Append our top-level category links. 183 if (this.shouldShowNavBar()) { 184 for (var key in codepops.navItems) { 185 var item = codepops.navItems[key]; 186 this.addCategory(categoriesDiv, key, item); 187 } 188 } 189 navPanel.appendChild(categoriesDiv); 190 191 // Append our logo. 192 var logo = this.document_.createElement('a'); 193 logo.id = 'bitsbox-navbar-logo'; 194 logo.title = 'Bitsbox Logo'; 195 if (this.shouldShowNavBar()) { 196 logo.href = this.fixHref('/'); 197 } else { 198 logo.href = '/#'; 199 logo.style.cursor = 'default'; 200 } 201 logo.setAttribute('id','navbar-image-logo'); 202 logo.className = 'bitsbox-logo'; 203 navPanel.appendChild(logo); 204 205 // Add a dividing line in the mobile menu, to separate the 206 // top level nav links from the "corner" links. 207 var hr = this.document_.createElement('hr'); 208 this.popdownPanel.appendChild(hr); 209 210 // Append the links that appear in the top-right corner. 211 var cornerPanel = this.document_.createElement('div'); 212 cornerPanel.id = 'corner-panel'; 213 navPanel.appendChild(cornerPanel); 214 215 if (this.shouldShowNavBar()) { 216 this.addCornerLink(cornerPanel, 'Kids Sign In', 217 '/code.html#signin', 'navbar-link-signin', 'navbar-link-signin-mobile'); 218 this.addCornerJSLink(cornerPanel, 'Account', 219 'https://subscribe.bitsbox.com/customer/account', 'navbar-link-account', 220 'navbar-link-account-mobile'); 221 222 if (this.customerIsLoggedInToCratejoy()) { 223 this.addCornerLink(cornerPanel, 'Sign Out', 224 'https://subscribe.bitsbox.com/customer/logout', 'navbar-link-signout', 225 'navbar-link-signout-mobile'); 226 } 227 this.addCornerLink(cornerPanel, 'Cart', 228 'https://subscribe.bitsbox.com/checkout/', 'navbar-link-cart', 229 'navbar-link-cart-mobile'); 230 this.addMobileMenu(cornerPanel); 231 } 232 233 234 // TODO(scott): We should probably create a bind() function in this 235 // object so we can do proper binding. 236 var win = this.window_; 237 var doc = this.document_; 238 var target = this; 239 this.window_.onscroll = function() { 240 241 target.hideAllLinkPanels(); 242 target.deselectAllCategories(); 243 244 var linksPanelTop = '75px'; 245 if (win.scrollY < 32) { 246 navPanel.className = 'bitsbox-navbar-panel'; 247 } else { 248 navPanel.className = 'bitsbox-navbar-panel ' + 249 'scrolled'; 250 linksPanelTop = '42px'; 251 } 252 253 var linkPanels = doc.getElementsByClassName('bitsbox-links-panel'); 254 for (var i = 0; i < linkPanels.length; i++) { 255 linkPanels[i].style.top = linksPanelTop; 256 } 257 }; 258 259 this.document_.body.appendChild(navPanel); 260 this.document_.body.appendChild(this.popdownPanel); 261 262 // Show everything after a timeout. This avoids "popping" during load. 263 this.window_.setTimeout(codepops.bind(function() { 264 navPanel.style.visibility = 'visible'; 265 266 var linkPanels = 267 this.document_.getElementsByClassName('bitsbox-links-panel'); 268 for (var i = 0; i < linkPanels.length; i++) { 269 linkPanels[i].style.visibility = 'visible'; 270 } 271 272 }, this), 350); 273}; 274 275 276/** 277 * Adds a top-level category nav item. 278 * @param {Element} parent The div to add the category to. 279 * @param {string} title The title of the link. 280 * @param {Object} item A hash of sub-links to handle. 281 */ 282codepops.BitsboxNavBar.prototype.addCategory = function(parent, title, item) { 283 var categoryLink = this.document_.createElement('a'); 284 categoryLink.innerHTML = title; 285 categoryLink.href = this.fixHref(item.href || '#'); 286 categoryLink.className = 'bitsbox-category'; 287 if (item.id) {
288 categoryLink.setAttribute('id',item.id); 289 } 290 291 var linksPanel = this.document_.createElement('div'); 292 linksPanel.className = 'bitsbox-links-panel'; 293 294 // Hide the panels until the CSS loads to override it. 295 linksPanel.style.visibility = 'hidden'; 296 297 categoryLink.onmouseover = codepops.bind(function() { 298 this.hideAllLinkPanels(); 299 linksPanel.className = 'bitsbox-links-panel visible'; 300 this.deselectAllCategories(); 301 categoryLink.className = 'bitsbox-category selected'; 302 }, this); 303 parent.appendChild(categoryLink); 304 305 linksPanel.onmouseout = codepops.bind(this.hideAllLinkPanels, this); 306 307 for (var key in item) { 308 if ((key != 'href') && (key != 'id')) { 309 var subItem = item[key]; 310 this.addLink(linksPanel, key, subItem); 311 } 312 } 313 this.document_.body.appendChild(linksPanel); 314 315 // Mobile navigation items. 316 var mobileLink = this.document_.createElement('a'); 317 mobileLink.innerHTML = title; 318 mobileLink.href = this.fixHref(item.href || '#'); 319 if (item.id) { 320 mobileLink.setAttribute('id',item.id + '-mobile'); 321 } 322 this.popdownPanel.appendChild(mobileLink); 323}; 324 325 326/** 327 * Adds a second-level category nav link. 328 * @param {Element} parent The div to add the category to. 329 * @param {string} title The title of the link. 330 * @param {Object} subItem A hash of metadata about this link. 331 */ 332codepops.BitsboxNavBar.prototype.addLink = function(parent, title, subItem) { 333 var link = this.document_.createElement('a'); 334 link.innerHTML = title; 335 link.href = this.fixHref(subItem.href); 336 if (subItem.id) { 337 link.id = subItem.id; 338 } 339 parent.appendChild(link); 340 link.onmouseover = function() { 341 parent.className = 'bitsbox-links-panel visible'; 342 }; 343}; 344 345 346/** 347 * Adds a link to the top right corner. 348 * @param {Element} parent The div to add the link to. 349 * @param {string} title The title of the link. 350 * @param {string} href Link to go to. 351 */ 352codepops.BitsboxNavBar.prototype.addCornerLink = function(parent, title, href, 353 id, mobileId) { 354 355 var fixedHref = this.fixHref(href || '#'); 356 357 var link = this.document_.createElement('a'); 358 link.title = title; 359 link.innerHTML = title; 360 link.className = title.toLowerCase().replace(/\s+/gi, '-'); 361 362 // If the href contains logout, we want to add some additional properties 363 // so we can send the user to our home page instead of the store page. 364 if (href.indexOf('logout') > -1) { 365 link.href = 'https://bitsbox.com/'; 366 link.onclick = this.logoutOfStoreAccount; 367 } else { 368 link.href = fixedHref; 369 } 370 if (id) { 371 link.setAttribute('id',id); 372 } 373 parent.appendChild(link); 374 375 // Mobile navigation items. 376 var mobileLink = this.document_.createElement('a'); 377 mobileLink.innerHTML = title; 378 379 if (href.indexOf('logout') > -1) { 380 mobileLink.href = 'https://bitsbox.com/'; 381 mobileLink.onclick = this.logoutOfStoreAccount; 382 } else { 383 mobileLink.href = fixedHref; 384 } 385 if (mobileId) { 386 mobileLink.setAttribute('id',mobileId); 387 } 388 this.popdownPanel.appendChild(mobileLink); 389}; 390 391 392/** 393 * Function that logs a user out of their store account and sends them to 394 * the bitsbox homepage. 395 */ 396codepops.BitsboxNavBar.prototype.logoutOfStoreAccount = function() { 397 398 // Code taken from support.cratejoy.com to be able to logout, but still 399 // send the user where we want. 400 $.ajax({ 401 url: '/customer/logout', 402 type: 'GET', 403 success: function(response){;} 404 }); 405}; 406 407 408/** 409 * Adds a link to the top right corner, but instead of it being an <a> tag, 410 * build it with and <em> tag with an onclick handler. Useful for keeping 411 * the Account link from being decorated with Google Analytics query parameters 412 * which cause the "blank screen" bug on the Cratejoy side. 413 * @param {Element} parent The div to add the link to. 414 * @param {string} title The title of the link. 415 * @param {string} href Link to go to. 416 */ 417codepops.BitsboxNavBar.prototype.addCornerJSLink = function(parent, title, href, 418 id, mobileId) { 419 420 var fixedHref = this.fixHref(href || '#'); 421 fixedHref = fixedHref.replace(/"/gi, '\"'); 422 423 var link = this.document_.createElement('em'); 424 link.title = title; 425 link.innerHTML = title; 426 link.className = title.toLowerCase().replace(/\s+/gi, '-'); 427 link.onclick = function() { 428 window.location = fixedHref; 429 }; 430 if (id) { 431 link.setAttribute('id', id); 432 } 433 parent.appendChild(link); 434 435 // Mobile navigation items. 436 var mobileLink = this.document_.createElement('em'); 437 mobileLink.innerHTML = title; 438 mobileLink.onclick = function() { 439 window.location = fixedHref; 440 }; 441 if (mobileId) { 442 mobileLink.setAttribute('id', mobileId); 443 } 444 this.popdownPanel.appendChild(mobileLink); 445}; 446 447 448/** 449 * Adds a link to the top right corner. 450 * @param {Element} parent The div to add the link to. 451 * @param {string} title The title of the link. 452 * @param {string} href Link to go to. 453 */ 454codepops.BitsboxNavBar.prototype.addMobileMenu = function(parent) { 455 var menu = this.document_.createElement('span'); 456 menu.innerHTML = '='; 457 menu.className = 'bitsbox-mobile-menu'; 458 parent.appendChild(menu); 459 menu.onclick = codepops.bind(this.onMobileMenuClick, this); 460}; 461 462 463/** 464 * Handles clicks or taps on the mobile nav menu. 465 */ 466codepops.BitsboxNavBar.prototype.onMobileMenuClick = function(parent) { 467 if (this.popdownPanel.className == 'bitsbox-popdown visible') { 468 this.popdownPanel.className = 'bitsbox-popdown hidden'; 469 } else { 470 this.popdownPanel.className = 'bitsbox-popdown visible'; 471 } 472}; 473 474 475/** 476 * Hides all of the link panels in the navigation bar. 477 */ 478codepops.BitsboxNavBar.prototype.hideAllLinkPanels = function() { 479 var linkPanels = this.document_.getElementsByClassName('bitsbox-links-panel'); 480 for (var i = 0; i < linkPanels.length; i++) { 481 linkPanels[i].className = 'bitsbox-links-panel'; 482 } 483}; 484 485 486/** 487 * Deselects all of the top-level category links. 488 */ 489codepops.BitsboxNavBar.prototype.deselectAllCategories = function() { 490 var categories = document.getElementsByClassName('bitsbox-category'); 491 for (var i = 0; i < categories.length; i++) { 492 categories[i].className = 'bitsbox-category'; 493 } 494}; 495 496 497/** 498 * Gets the host the navbar believes it's running under. 499 * @return {string} The hostname 500 */ 501codepops.BitsboxNavBar.prototype.getHost = function() { 502 return this.host_; 503}; 504 505 506/** 507 * Returns whether this file is being loaded from Cratejoy.com. This will drive 508 * logic for figuring out relative links. 509 * @return {boolean} Whether we are running on a vendor site. 510 */ 511codepops.BitsboxNavBar.prototype.isRunningOnCrateJoy = function() { 512 if (this.window_.location.href.indexOf('/subscribe.bitsbox.com') > -1 || 513 this.window_.location.href.indexOf('/cratejoy.com') > -1) { 514 return true; 515 } 516 return false;
517}; 518 519 520/** 521 * Returns whether this file is being loaded from a page where the navbar 522 * should be shown. Most pages hosted on Cratejoy should not show the navigation 523 * bar, as A/B tests show that navigation lowers our conversion rate. 524 * @return {boolean} Whether we should show the nav bar. 525 */ 526codepops.BitsboxNavBar.prototype.shouldShowNavBar = function() { 527 528 // Made the decision on August 9th, 2022 to start showing the navigation 529 // bar again. For now returning true here to make it easy to revert back 530 // just in case we need to. 531 return true; 532 533 if (this.isRunningOnCrateJoy() === false) { 534 return true; 535 } else { 536 537 // We show the navbar on anything that begins with /customer. 538 if (this.window_.location.href.indexOf('/customer') > -1) { 539 return true; 540 } 541 542 // And we show it on the school products and other products landing pages. 543 if (this.window_.location.href.indexOf('/details/school-products') > -1) { 544 return true; 545 } 546 if (this.window_.location.href.indexOf('details/otherproducts') > -1) { 547 return true; 548 } 549 550 // Otherwise, we hide it. 551 return false; 552 } 553}; 554 555 556/** 557 * Takes a relative or absolute URL as input, and returns a new URL corrected 558 * to be either absolute or relative based on which site (bitsbox.com vs. 559 * Cratejoy) the nav bar is being viewed on. 560 * @param {string} href The URL to fix. 561 * @return {string} The fixes URL. 562 */ 563codepops.BitsboxNavBar.prototype.fixHref = function(href) { 564 565 // If we're running on Cratejoy and the href begins with a forward slash, 566 // then make sure we send the user to a path on the main site. 567 if (this.isRunningOnCrateJoy() && href.substr(0, 1) == '/') { 568 return 'https://bitsbox.com' + href; 569 } 570 return href; 571}; 572 573 574/** 575 * Hides the shopping cart bar on Cratejoy site. Note that this relies on JQuery 576 * being loaded, which it always is on Cratejoy sites. 577 */ 578codepops.BitsboxNavBar.prototype.hideShoppingCart = function () { 579 $('.row-offcanvas').one('webkitTransitionEnd otransitionend oTransitionEnd ' + 580 'msTransitionEnd transitionend', function(e) { 581 if(!$('.row-offcanvas').hasClass('active')) { 582 $('.row-offcanvas').removeClass('active-position'); 583 } 584 }); 585 $('.row-offcanvas').removeClass('active'); 586 $(document).unbind('mouseup touchend'); 587}; 588 589 590/** 591 * Shows the shopping cart bar on Cratejoy site. Note that this relies on JQuery 592 * being loaded, which it always is on Cratejoy sites. 593 */ 594codepops.BitsboxNavBar.prototype.showShoppingCart = function () { 595 $('.row-offcanvas').addClass('active-position'); 596 $('.row-offcanvas').addClass('active'); 597 var boundHideCart = codepops.bind(this.hideShoppingCart, this); 598 599 $(document).bind('mouseup touchend', function (e) { 600 var $container = $('.sidebar-offcanvas'); 601 if (!$container.is(e.target) && $container.has(e.target).length === 0) { 602 boundHideCart(); 603 } 604 }); 605}; 606 607 608 609/** 610 * Toggles shopping cart bar on Cratejoy site. 611 */ 612codepops.BitsboxNavBar.prototype.toggleShoppingCart = function () { 613 614 // Hide the mobile popdown menu so it does not cover up the cart. 615 this.popdownPanel.className = 'bitsbox-popdown hidden'; 616 617 if (this.shoppingCartIsVisible()) { 618 this.hideShoppingCart(); 619 } else { 620 this.showShoppingCart(); 621 } 622}; 623 624 625/** 626 * Returns whether the Cratejoy shopping cart bar is currently visible. 627 * @return {boolean} Whether the shopping cart bar is visible. 628 */ 629codepops.BitsboxNavBar.prototype.shoppingCartIsVisible = function () { 630 if ($('.row-offcanvas') && 631 $('.row-offcanvas')[0] 632 && $('.row-offcanvas')[0].className.indexOf('active-position') > -1) { 633 return true; 634 } else { 635 return false; 636 } 637}; 638 639 640/** 641 * Returns whether the user is currently logged in to a Cratejoy account. 642 * @return {boolean} Whether they are logged in. 643 */ 644codepops.BitsboxNavBar.prototype.customerIsLoggedInToCratejoy = function () { 645 var crateJoyMenu = this.document_.getElementsByClassName('dropdown-menu')[0]; 646 if (crateJoyMenu && crateJoyMenu.innerHTML.indexOf('Store Sign Out') > -1) { 647 return true; 648 } else { 649 return false; 650 } 651}; 652 653 654/** 655 * Handy bind function. 656 * @param {Function} fn The function to be bound. 657 * @param {Object} selfObj The object to be bound as 'this'. 658 * @param {Array} var_args The arguments to be handed in to the bound function. 659 * @return {Function} The newly bound function. 660 */ 661codepops.bind = function(fn, selfObj, var_args) { 662 var boundArgs = fn.boundArgs_; 663 if (arguments.length > 2) { 664 var args = Array.prototype.slice.call(arguments, 2); 665 if (boundArgs)args.unshift.apply(args, boundArgs); 666 boundArgs = args; 667 } 668 selfObj = fn.boundSelf_ || selfObj; 669 fn = fn.boundFn_ || fn; 670 var newfn; 671 var context = selfObj || goog.global; 672 if (boundArgs)newfn = function() { 673 var args = Array.prototype.slice.call(arguments); 674 args.unshift.apply(args, boundArgs);
675 return fn.apply(context, args); 676 }; 677 else newfn = function() { 678 return fn.apply(context, arguments); 679 }; 680 newfn.boundArgs_ = boundArgs; 681 newfn.boundSelf_ = selfObj; 682 newfn.boundFn_ = fn; 683 return newfn; 684}; 685 686 687 688// If this file is being loaded from anywhere but the test harness, go ahead 689// and create an instance of our object. (In a test situation, we want to 690// be able to create our own instances of the object using mock documents.) 691if (window.location.href.indexOf('/tests/') == -1) { 692 693 /** 694 * Instance of our navigation bar. 695 * @type {BitsboxNavBar} 696 */ 697 codepops.bitsboxnavbar = new codepops.BitsboxNavBar(); 698 699}
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.