1/* 2 TermTemplate:"<strong> <%this.term%> </strong>", 3 this.options.relatedHeader 4 5 termTemplate 6 autoSearchObj.options.provider.termTemplate 7*/ 8 9/* jshint onevar: false */ 10( function( $ ) { 11 "use strict"; 12 $.widget( "ui.autosearch", $.ui.autocomplete, { 13 _renderMenu: function( ul, items ) { 14 var that = this; 15 var related = $.grep( items, function( obj ) {//, item) { 16 return obj.related !== "false"; 17 } ); 18 var unrelated = $.grep( items, function( obj ) {//, item) { 19 return obj.related === "false"; 20 } ); 21 $.each( unrelated, function( i, item ) { 22 that._renderItemData( ul, item ); 23 } ); 24 25 if ( this.options.showRelated && related.length ) { 26 if ( this.options.relatedHeader ) { 27 that._renderHeader( ul, this.options.relatedHeader ); 28 } 29 $.each( related, function( i, item ) { 30 that._renderItemData( ul, item ); 31 } ); 32 } 33 }, 34 _renderItemData: function( ul, item ) { 35 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item ); 36 }, 37 _renderItem: function( ul, item ) { 38 var text = item.label; 39 40 return $( "<li></li>" ).data( "item.autocomplete", item ).append( text ).appendTo( ul ); 41 }, 42 _renderHeader: function( ul, text ) { 43 return $( "<li></li>" ).append( "<a href=''>" + text + "</a>" ).appendTo( ul ); 44 } 45 } ); 46} )( jQuery ); 47 48/** Intended usage is 49* $.spine({ 50* "option":"value" 51* }); 52**/ 53/*jshint -W054 */ 54;( function( $, window, document, undefined ) { 55 /** 56 * Strip one or more classes from a class attribute matching a given prefix. 57 * 58 * @param {string} partialMatch The class partial to match against, like `btn-` to match `btn-danger btn-active`, but not `btn`. 59 * @param {string} endOrBegin Omit to match the beginning. Provide a truthy value to only find classes ending with a match. 60 * @returns {jQuery} 61 */ 62 $.fn.stripClass = function( partialMatch, endOrBegin ) { 63 var x; 64 x = new RegExp( ( !endOrBegin ? "\\b" : "\\S+" ) + partialMatch + "\\S*", "g" ); 65 66 // http://stackoverflow.com/a/2644364/1037948 67 this.attr( "class", function( i, c ) { 68 if ( !c ) { 69 return; // Protect against no class 70 } 71 return c.replace( x, "" ); 72 } ); 73 return this; 74 }; 75 76 /** 77 * Refresh a snapshot of stored jQuery selector data. 78 * 79 * Not all stored object properties would normally be reflected when 80 * the original selector is modified. This ensures we capture the 81 * latest version. 82 * 83 * @returns {*} 84 */ 85 $.fn.refresh = function() { 86 var elems; 87 elems = $( this.selector ); 88 this.splice( 0, this.length ); 89 90 try { 91 this.push.apply( this, elems ); 92 } 93 catch ( err ) { 94 if ( $( this.selector ).html() !== "" ) { 95 return $( this.selector ); 96 }else { 97 return $( "<div>" ); 98 } 99 } 100 return this; 101 }; 102 103 /** 104 * A small templating engine for processing HTML with given data. 105 * 106 * @see TemplateEngine via MIT Licensed https://github.com/krasimir/absurd/ 107 * 108 * @param {string} html 109 * @param {Object} options 110 * @returns {*} 111 */ 112 $.runTemplate = function( html, options ) { 113 var re, add, match, cursor, code, reExp, result; 114 115 re = /<%(.+?)%>/g; 116 reExp = /(^( )?(var|if|for|else|switch|case|break|{|}|;))(.*)?/g; 117 code = "var r=[];\n"; 118 cursor = 0; 119 120 add = function( line, js ) { 121 if ( js ) { 122 code += line.match( reExp ) ? line + "\n" : "r.push(" + line + ");\n"; 123 }else { 124 code += line !== "" ? "r.push('" + line.replace( /'/g, "\"" ) + "');\n" : ""; 125 } 126 return add; 127 }; 128 129 while ( ( match = re.exec( html ) ) ) { 130 add( html.slice( cursor, match.index ) )( match[ 1 ], true ); 131 cursor = match.index + match[ 0 ].length; 132 } 133 134 add( html.substr( cursor, html.length - cursor ) ); 135 code = ( code + "return r.join('');" ).replace( /[\r\t\n]/g, "" ); 136 result = new Function( code ).apply( options ); 137 138 return result; 139 }; 140 141 /** 142 * Unused in Spine. 143 * 144 * @todo Consider deprecating. 145 * 146 * @returns {*} 147 */ 148 $.whenAll = function() { 149 return $.when.apply( $, arguments ); 150 }; 151 152 /** 153 * Determine if the current view is an iOS device. 154 * 155 * @returns {boolean} 156 */ 157 $.is_iOS = function() { 158 return ( window.navigator.userAgent.match( /(iPad|iPhone|iPod)/ig ) ? true : false ); 159 }; 160 161 /** 162 * Determine if the current view is an Android device. 163 * 164 * @returns {boolean} 165 */ 166 $.is_Android = function() { 167 return ( window.navigator.userAgent.match( /(Android)/ig ) ? true : false ); 168 }; 169 170 /** 171 * Detect browser support for SVG images. 172 * 173 * @returns {boolean} 174 */ 175 $.svg_enabled = function() { 176 return document.implementation.hasFeature( "http://www.w3.org/TR/SVG11/feature#Image", "1.1" ); 177 }; 178 179 /** 180 * Use MutationObserver to watch for any changes to a specific DOM element and trigger 181 * the passed callback when a change is made. 182 * 183 * This is currently only used within the Spine to watch `#glue` for changes such as 184 * menu expansion, etc... 185 * 186 * @param obj 187 * @param callback 188 */ 189 $.observeDOM = function( obj, callback ) { 190 var config, mutationObserver; 191 192 if ( window.MutationObserver ) { 193 config = { 194 childList: true, 195 attributes: true, 196 subtree: true, 197 attributeOldValue: true, 198 attributeFilter: [ "class", "style" ] 199 }; 200 201 mutationObserver = new MutationObserver( function( mutationRecords ) { 202 var fire_callback = false; // Assume no callback is needed. 203 204 $.each( mutationRecords, function( index, mutationRecord ) { 205 if ( mutationRecord.type === "childList" ) { 206 if ( mutationRecord.addedNodes.length > 0 ) { 207 fire_callback = true; 208 } else if ( mutationRecord.removedNodes.length > 0 ) { 209 fire_callback = true; 210 } 211 } else if ( mutationRecord.type === "attributes" ) { 212 if ( mutationRecord.attributeName === "class" ) { 213 fire_callback = true; 214 } 215 } 216 } ); 217 218 // If one of our matched mutations has been observed, fire the callback. 219 if ( fire_callback ) { 220 callback(); 221 } 222 } ); 223 mutationObserver.observe( obj[ 0 ], config ); 224 } else { 225 226 // Set a fallback function to fire every 200ms and watch for DOM changes. 227 window.setTimeout( function() { 228 var current_obj = obj.refresh(); 229 230 if ( typeof window.obj_watch === "undefined" ) { 231 window.obj_watch = current_obj[ 0 ]; 232 } 233 234 /** 235 * If the current object does not match the object we're watching, assume 236 * a DOM mutation has occurred and fire the callback. 237 */ 238 if ( window.obj_watch !== current_obj[ 0 ] ) { 239 callback(); 240 } 241 242 window.obj_watch = current_obj[ 0 ]; 243 244 // Reset observation on the current object. 245 $.observeDOM( current_obj, callback ); 246 }, 200 ); 247 } 248 }; 249 250 /** 251 * Setup the plugin's prototype. 252 * 253 * @param {string} name 254 * @param {object} prototype 255 */ 256 $.s = function( name, prototype ) { 257 var namespace; 258 259 namespace = name.split( "." )[ 0 ]; 260 name = name.split( "." )[ 1 ]; 261 262 $[ namespace ] = $[ namespace ] || {}; 263 264 $[ namespace ][ name ] = function( options, element ) { 265 if ( arguments.length ) { 266 this._setup( options, element ); 267 } 268 }; 269 270 $[ namespace ][ name ].prototype = $.extend( { 271 namespace: namespace, 272 pluginName: name 273 }, prototype ); 274 275 $.fn[ name ] = function( context ) { 276 var isMethodCall, context_options, args, returnValue; 277 278 context_options = {}; 279 280 if ( arguments[ 1 ] ) { 281 context_options = arguments[ 1 ]; 282 } 283 284 context = context || {}; 285 286 this.options = $.extend( {}, context ); 287 288 isMethodCall = ( typeof context === "string" ); 289 args = Array.prototype.slice.call( arguments, 1 ); 290 returnValue = this; 291 292 if ( isMethodCall && context.substring( 0, 1 ) === "_" ) { 293 return returnValue; 294 } 295 296 this.each( function() { 297 var instance; 298 299 instance = $.data( this, name ); 300 301 if ( !instance ) { 302 instance = $.data( this, name, new $[ namespace ][ name ]( context, this ) ); 303 } 304 305 if ( instance[ context + "_init" ] !== undefined ) { 306 if ( instance[ context + "_init" ] ) { 307 instance[ context + "_init" ]( context_options ); 308 } 309 } 310 311 if ( isMethodCall && instance[ context ] !== undefined ) { 312 returnValue = instance[ context ].apply( instance, args ); 313 } 314 } ); 315 return returnValue; 316 }; 317 }; 318 319 /** 320 * Configure and create the jQuery.ui.spine plugin. 321 * 322 * Based on a fork of MIT Licensed jquery-ui-map 323 * See: https://code.google.com/p/jquery-ui-map/source/browse/trunk/ui/jquery.ui.map.js 324 */ 325 $.s( "ui.spine", { 326 327 globals: { 328 version: "0.1.0", 329 current_url:window.location.href 330 }, 331 332 options: {}, 333 334 /** 335 * Setup plugin basics. 336 * 337 * @param {object} options 338 * @param {HTMLElement} element 339 */ 340 _setup: function( options, element ) { 341 this.el = element; 342 options = options || {}; 343 $.extend( this.options, options, {} ); 344 this._create(); 345 }, 346 347 /** 348 * Instantiate the object 349 */ 350 _create: function() { 351 var self; 352 353 self = this; 354 this.instance = { 355 spine: self.options, 356 framework: [], 357 search: [], 358 social: [] 359 }; 360 361 self._call( self.options.callback, self.instance.spine ); 362 }, 363 364 /** 365 * Add objects to the global spine object. 366 * 367 * Note: Context is not yet implemented. 368 * 369 * @param {object} obj e.g. {'foo':'bar'} 370 * @param {string} context e.g. 'search', 'social', 'framework' 371 */ 372 _set_globals: function( obj, context ) { 373 context = null; // Avoiding jshint error temporarily. 374 375 if ( typeof( obj ) !== "object" ) { 376 return; 377 } 378 $.extend( this.globals, obj ); 379 }, 380 381 /** 382 * Retrieve a context's objects from the global spine object. 383 * 384 * @param {string} context e.g. 'search', 'social', 'framework' 385 * @returns {*} 386 * @private 387 */ 388 _get_globals: function( context ) { 389 return this.globals[ context ]; 390 }, 391 392 /** 393 * Clears an object of a context. 394 * 395 * @param {string} context e.g. 'search', 'social', 'framework' 396 */ 397 clear: function( context ) { 398 this._c( this.get( context ) ); 399 this.set( context, [] ); 400 401 return this; 402 }, 403 404 /** 405 * Clears an object of its properties. 406 * 407 * @param {object} obj 408 */ 409 _c: function( obj ) { 410 for ( var property in obj ) { 411 if ( obj.hasOwnProperty( property ) ) { 412 obj[ property ] = null; 413 } 414 } 415 }, 416 417 /** 418 * Returns objects with a specific context. 419 * 420 * @param {string} context In what context, e.g. 'search', 'social', 'framework' 421 * @param {object} options Contains string property, string value, string operator (AND/OR). 422 * @param callback:function(search:jObj, isFound:boolean) 423 */ 424 find: function( context, options, callback ) { 425 var obj, isFound, property, value; 426 obj = this.get( context ); 427 options.value = $.isArray( options.value ) ? options.value : [ options.value ]; 428 for ( property in obj ) { 429 if ( obj.hasOwnProperty( property ) ) { 430 isFound = false;
431 for ( value in options.value ) { 432 if ( $.inArray( options.value[ value ], obj[ property ][ options.property ] ) > -1 ) { 433 isFound = true; 434 } else { 435 if ( options.operator && options.operator === "AND" ) { 436 isFound = false; 437 break; 438 } 439 } 440 } 441 callback( obj[ property ], isFound ); 442 } 443 } 444 return this; 445 }, 446 447 /** 448 * Returns an instance property by key. Has the ability to set an object if the property does not exist 449 * @param key:string 450 * @param value:object(optional) 451 */ 452 get: function( key, value ) { 453 var instance, e, i; 454 instance = this.instance; 455 if ( !instance[ key ] ) { 456 if ( key.indexOf( ">" ) > -1 ) { 457 e = key.replace( / /g, "" ).split( ">" ); 458 for ( i = 0; i < e.length; i++ ) { 459 if ( !instance[ e[ i ] ] ) { 460 if ( value ) { 461 instance[ e[ i ] ] = ( ( i + 1 ) < e.length ) ? [] : value; 462 } else { 463 return null; 464 } 465 } 466 instance = instance[ e[ i ] ]; 467 } 468 return instance; 469 } else if ( value && !instance[ key ] ) { 470 this.set( key, value ); 471 } 472 } 473 return instance[ key ]; 474 }, 475 476 /** 477 * Sets an instance property 478 * @param key:string 479 * @param value:object 480 */ 481 set: function( key, value ) { 482 this.instance[ key ] = value; 483 return this; 484 }, 485 486 /** 487 * Helper method for unwrapping jQuery/DOM/string elements 488 * @param obj:string/node/jQuery 489 */ 490 _unwrap: function( obj ) { 491 return ( !obj ) ? null : ( ( obj instanceof jQuery ) ? obj[ 0 ] : ( ( obj instanceof Object ) ? obj : $( "#" + obj )[ 0 ] ) ); 492 }, 493 494 /** 495 * Helper method for calling a function 496 * @param callback 497 */ 498 _call: function( callback ) { 499 if ( callback && $.isFunction( callback ) ) { 500 callback.apply( this, Array.prototype.slice.call( arguments, 1 ) ); 501 } 502 }, 503 504 /** 505 * Destroys spine elements and options. 506 */ 507 clear_spine: function() { 508 this.clear( "search" ).clear( "framework" ).clear( "social" ); 509 }, 510 511 /** 512 * Destroys the plugin. 513 */ 514 destroy: function( callback ) { 515 this.clear( "search" ).clear( "framework" ).clear( "social" )._c( this.instance ); 516 $.removeData( this.el, this.name ); 517 this._call( callback, this ); 518 } 519 } ); 520 521 /** 522 * The primary Spine method used to start things up.
523 * 524 * @param {object} options 525 * @returns {*} 526 */ 527 $.spine = function( options ) { 528 var targ; 529 530 targ = this.jquery === undefined ? $( "body" ) : this; 531 532 return $.each( targ, function() { 533 var targ; 534 targ = $( this ); 535 536 // Initialize the Spine plugin. 537 targ.spine( {} ); 538 539 options = $.extend( { "framework":{}, "search":{}, "social":{} }, options ); 540 541 // Setup each of the extensions. 542 $.each( options, function( i, v ) { 543 targ.spine( i, v ); 544 } ); 545 } ); 546 }; 547 548} )( jQuery, window, document ); 549 550 /*! 551 * 552 * Depends: 553 * jquery.ui.v.js 554 */ 555/*jshint multistr: true */ 556( function( $ ) { 557 $.extend( $.ui.spine.prototype, { 558 /** 559 * Initialize the Spine framework. Fired automatically in `$.s`, found 560 * in ui.spine.js. 561 * 562 * @param {object} options 563 */ 564 framework_init: function( options ) { 565 $.extend( this.framework_options, options ); 566 this._set_globals( this.framework_globals ); 567 this.framework_create(); 568 }, 569 570 /** 571 * Global framework options for the Spine framework. 572 */ 573 framework_options: { 574 viewport_offset: 0, 575 equalizer_filter: ".skip*", 576 contact_template: "<address itemscope itemtype='http://schema.org/Organization' class='hcard'>" + 577 "<% if (typeof(this.department) != 'undefined') { %><div class='organization-unit fn org'>" + 578 "<% if (typeof(this.url) != 'undefined') { %><a href='<%this.url%>' class='url'><% } %>" + 579 "<%this.department%>" + 580 "<% if (typeof(this.url) != 'undefined') { %></a><% } %>" + 581 "</div><% } %> " + 582 "<% if (typeof(this.name) != 'undefined') { %><div class='organization-name'><%this.name%></div><% } %>" + 583 "<div class='address'>" + 584 "<% if (typeof(this.streetAddress) != 'undefined') { %><div class='street-address'><%this.streetAddress%></div><% } %>" + 585 "<% if (typeof(this.addressLocality) != 'undefined' || typeof(this.postalCode) != 'undefined') { %><div class='locality'>" + 586 "<% if (typeof(this.addressLocality) != 'undefined' ) { %><%this.addressLocality%><% } %>" + 587 "<% if (typeof(this.addressRegion) != 'undefined' ) { %>, <%this.addressRegion%><% } %>" + 588 "<% if (typeof(this.postalCode) != 'undefined' ) { %> <span class='postalcode'><%this.postalCode%></span><% } %>" + 589 "</div><% } %>" + 590 "</div>" + 591 "<% if (typeof(this.telephone) != 'undefined' ) { %><div class='tel'><%this.telephone%></div><% } %>" + 592 "<% if (typeof(this.email) != 'undefined' ) { %><div class='email' rel='email'><a href='mailto:<%this.email%>'>Email us</a></div><% } %>" + 593 "<% if (typeof(this.ContactPoint) != 'undefined' && typeof(this.ContactPointTitle) != 'undefined') { %>" + 594 "<div class='more'><a href='<%this.ContactPoint%>'><%this.ContactPointTitle%></a></div>" + 595 "<% } %>" + 596 "</address>" 597 }, 598 599 /** 600 * Global objects that are part of the Spine framework. 601 */ 602 framework_globals: { 603 spine: $( "#spine" ), 604 glue: $( "#glue" ), 605 main: $( "main" ), 606 wsu_actions: $( "#wsu-actions" ) 607 }, 608 609 /** 610 * Data on the current state of navigation for use when calculating 611 * sizes and placement of other elements. 612 */ 613 nav_state:{ 614 viewport_ht: 0, 615 scroll_dif: 0, 616 positionLock: 0, 617 scroll_top: 0, 618 spine_ht: 0, 619 glue_ht: 0, 620 height_dif: 0 621 }, 622 623 /** 624 * Setup a scroll container for use with iOS. 625 */ 626 setup_nav_scroll: function() { 627 $( "#glue" ).wrapInner( "<div id='scroll'>" ); 628 $( "#spine header" ).insertBefore( $( "#glue" ) ); 629 }, 630 631 /** 632 * Determine if the page view is in a mobile state, defined as less than 990px; 633 */ 634 is_mobile_view: function() { 635 if ( window.matchMedia ) { 636 return window.matchMedia( "(max-width: 989px)" ).matches; 637 } else if ( window.styleMedia ) { 638 639 // Fallback for IE 9. IE 8 and below do not support media queries anyway. 640 return window.styleMedia.matchMedium( "(max-width: 989px)" ); 641 } 642 643 return false; 644 }, 645 646 /** 647 * Set the Spine to a given state, mobile or full. 648 * 649 * @param {string} state The state of the Spine to set. 650 */ 651 set_spine_state: function( state ) { 652 if ( "mobile" === state ) { 653 $( "html" ).removeClass( "spine-full" ).addClass( "ios spine-mobile" ); 654 this.setup_nav_scroll(); 655 } else { 656 $( "html" ).removeClass( "ios spine-mobile spine-mobile-open" ).addClass( "spine-full" ); 657 if ( $( "#scroll" ).length ) { 658 $( "#wsu-actions" ).unwrap(); 659 $( "#spine header" ).prependTo( "#glue" ); 660 } 661 } 662 }, 663 664 /** 665 * Determine if the Spine is already in a mobile state. 666 * 667 * @returns {boolean} 668 */ 669 has_mobile_state: function() { 670 if ( $( "html" ).hasClass( "spine-mobile" ) ) { 671 return true; 672 } 673 674 return false;
675 }, 676 677 /** 678 * On a resize event, adjust pieces of the Spine framework accordingly. 679 */ 680 framework_adjust_on_resize: function() { 681 var self, spread, verso, page, para, recto, recto_margin, verso_width, 682 viewport_ht, spine, glue, main; 683 684 self = this; 685 686 // Refresh data for global elements. 687 spine = self._get_globals( "spine" ).refresh(); 688 glue = self._get_globals( "glue" ).refresh(); 689 main = self._get_globals( "main" ).refresh(); 690 691 if ( self.is_mobile_view() && !self.has_mobile_state() ) { 692 self.set_spine_state( "mobile" ); 693 } else if ( !self.is_mobile_view() && self.has_mobile_state() ) { 694 self.set_spine_state( "full" ); 695 } 696 697 self.sizing(); 698 self.equalizing(); 699 700 if ( self.is_mobile_view() ) { 701 self.mainheight(); 702 } 703 704 // Only run function if an unbound element exists 705 if ( $( ".unbound, #binder.broken" ).length ) { 706 spread = $( window ).width(); 707 verso = self._get_globals( "main" ).offset().left; 708 page = self._get_globals( "main" ).width(); 709 recto = spread - self._get_globals( "main" ).offset().left; 710 recto_margin = ""; 711 712 if ( recto >= page ) { 713 recto_margin = recto - page; 714 } else { 715 recto_margin = 0; 716 } 717 718 /* Broken Binding */ 719 if ( $( "#binder" ).is( ".broken" ) ) { 720 self._get_globals( "main" ).css( "width", recto ); 721 } 722 723 verso_width = verso + self._get_globals( "main" ).width(); 724 725 $( ".unbound:not(.element).recto" ).css( "width", recto ).css( "margin-right", -( recto_margin ) ); 726 $( ".unbound.element.recto" ).each( function() { 727 para = $( this ).width(); 728 $( this ).css( "width", para + recto_margin ).css( "margin-right", -( recto_margin ) ); 729 } ); 730 $( ".unbound.verso" ).css( "width", verso_width ).css( "margin-left", -( verso ) ); 731 $( ".unbound.verso.recto" ).css( "width", spread ); 732 } 733 734 viewport_ht = $( window ).height() - this.framework_options.viewport_offset; 735 736 if ( !self.is_mobile_view() ) { 737 glue.css( "min-height", viewport_ht ); 738 spine.css( "min-height", viewport_ht ); 739 740 $( document ).trigger( "scroll" ); 741 } else { 742 glue.css( "min-height", "" ); 743 spine.css( "min-height", "" ); 744 } 745 }, 746 747 /** 748 * Create the Spine framework and setup basic events based on information present in the DOM. 749 */ 750 framework_create: function() { 751 var self, contactHtml, propmap = {}, svg_imgs; 752 753 self = this; // Preserve scope. 754 755 // Generate the contact section. 756 if ( !$( "#wsu-contact" ).length ) { 757 contactHtml = "<section id='wsu-contact' class='spine-contact spine-action closed'>"; 758 propmap = {}; 759 760 $.each( $( "[itemtype='http://schema.org/Organization']" ), function() { 761 var tar = this; 762 $.each( $( tar ).find( "[itemprop]" ), function( i, v ) { 763 var tmp = {}; 764 tmp[ $( v ).attr( "itemprop" ) ] = $( v ).attr( "content" ); 765 $.extend( propmap, tmp ); 766 } ); 767 contactHtml += $.runTemplate( self.framework_options.contact_template, propmap ); 768 } ); 769 contactHtml += "</section>"; 770 self.setup_tabs( "contact", contactHtml ); 771 } 772 773 self.setup_nav(); 774 775 // Set the initial state of the Spine on page load. Mobile is defined as less than 990px. 776 if ( self.is_mobile_view() ) { 777 self.set_spine_state( "mobile" ); 778 } else { 779 $( "html" ).addClass( "spine-full" ); 780 } 781 782 // If SVG is not supported, add a class and replace Spine SVG files with PNG equivalents. 783 if ( !$.svg_enabled() ) { 784 $( "html" ).addClass( "nosvg" ); 785 svg_imgs = $( "img[src$='.svg']" ); 786 787 if ( svg_imgs.length ) { 788 $.each( svg_imgs, function() { 789 $( this ).attr( "src", $( this ).attr( "src" ).replace( ".svg", ".png" ) ); 790 } ); 791 } 792 } 793 794 self.setup_spine(); 795 self.setup_printing(); 796 797 $( window ).on( "resize orientationchange", function() { self.framework_adjust_on_resize(); } ).trigger( "resize" ); 798 799 if ( !self.is_mobile_view() ) { 800 $( document ).trigger( "scroll" ); 801 } 802 }, 803 804 /** 805 * Label `#jacket` with the current window size. 806 * 807 * @param {HTMLelement} jacket 808 */ 809 sizing: function( jacket ) { 810 var current_width, jacket_classes, px_width, size_intermediate, size_medium, size_large; 811 812 jacket = jacket || $( "#jacket" ); 813 814 current_width = $( window ).width(); 815 816 size_intermediate = "size-intermediate size-smallish size-lt-medium size-lt-large size-lt-xlarge size-gt-small"; 817 size_medium = "size-medium size-lt-xlarge size-lt-large size-gt-intermediate size-gt-smallish size-gt-small"; 818 size_large = "size-large size-lt-xlarge size-gt-small size-gt-intermediate size-gt-smallish size-gt-medium"; 819 820 px_width = ""; 821 822 if ( current_width >= 1188 ) { 823 jacket_classes = "size-xlarge size-gt-small size-gt-intermediate size-gt-smallish size-gt-medium size-gt-large"; 824 } else if ( current_width >= 990 ) { 825 jacket_classes = size_large; 826 } else if ( ( current_width < 990 ) && current_width >= 792 ) { 827 px_width = "size-lt-990"; 828 jacket_classes = $( "#binder" ).is( ".fluid" ) ? size_large : size_medium; 829 } else if ( current_width < 792 && current_width >= 694 ) { 830 px_width = "size-lt-792"; 831 jacket_classes = $( "#binder" ).is( ".fixed" ) ? size_intermediate : size_medium; 832 } else if ( current_width < 694 && current_width >= 396 ) { 833 jacket_classes = "size-small size-lt-intermediate size-lt-smallish size-lt-medium size-lt-large size-lt-xlarge"; 834 } else { 835 jacket_classes = "size-small size-lt-small size-lt-intermediate size-lt-smallish size-lt-medium size-lt-large size-lt-xlarge"; 836 } 837 838 jacket.stripClass( "size-" ).addClass( jacket_classes + " " + px_width ); 839 }, 840 841 /** 842 * Equalize columns in a layout. 843 */ 844 equalizing: function() { 845 var obj; 846
847 if ( $( ".equalize" ).length ) { 848 obj = $( ".equalize" ); 849 obj.find( ".column" ).css( "min-height", "" ); 850 851 $.each( obj, function() { 852 var tallestBox = 0; 853 $.each( $( ".column", this ), function() { 854 tallestBox = ( $( this ).outerHeight() > tallestBox ) ? $( this ).outerHeight() : tallestBox; 855 } ); 856 857 if ( ( $( window ).width() <= 792 && !obj.is( ".equalize-medium" ) ) || ( $( window ).width() <= 694 && !obj.is( ".equalize-small" ) ) ) { 858 $( ".column", this ).not( ".unequaled" ).css( "min-height", "1" ); 859 } else { 860 $( ".column", this ).not( ".unequaled" ).css( "min-height", tallestBox ); 861 } 862 $( "section.equalize .column", this ).css( "min-height", "auto" ); 863 } ); 864 } 865 }, 866 867 /** 868 * Apply a minimum height to the `main` element. 869 */ 870 mainheight: function() { 871 var main, window_height, main_height; 872 873 main = this._get_globals( "main" ).refresh(); 874 875 if ( main.offset() ) { 876 window_height = $( window ).height(); 877 main_height = window_height; 878 if ( $( "#binder" ).is( ".size-lt-large" ) ) { 879 main_height -= 50; 880 } 881 $( "main:not(.height-auto)" ).css( "min-height", main_height ); 882 } 883 }, 884 885 /** 886 * Sets up framework html and other DOM attributes 887 */ 888 setup_jacket: function() {}, 889 890 /** 891 * Sets up framework html and other DOM attributes 892 */ 893 setup_binder: function() {}, 894 895 /** 896 * Sets up framework html and other DOM attributes 897 */ 898 setup_content: function() {}, 899 900 /** 901 * Toggle the display and removal of the mobile navigation. 902 * 903 * @param e 904 */ 905 toggle_mobile_nav: function( e ) { 906 var html, body, shelve, spine, glue, transitionEnd; 907 908 if ( typeof e !== "undefined" ) { 909 e.preventDefault(); 910 } 911 912 html = $( "html" ); 913 body = $( "body" ); 914 shelve = $( "#shelve" ); 915 spine = $.ui.spine.prototype._get_globals( "spine" ).refresh(); 916 glue = $.ui.spine.prototype._get_globals( "glue" ).refresh(); 917 918 /* Cross browser support for CSS "transition end" event */ 919 transitionEnd = "transitionend webkitTransitionEnd otransitionend MSTransitionEnd"; 920 921 // Whether opening or closing, the Spine will be animating from this point forward. 922 body.addClass( "spine-animating" ); 923 924 // Tell the browser and stylesheet what direction the Spine is animating. 925 if ( html.hasClass( "spine-mobile-open" ) ) { 926 body.addClass( "spine-move-left" ); 927 shelve.attr( "aria-expanded", "false" ); 928 } else { 929 body.addClass( "spine-move-right" ); 930 shelve.attr( "aria-expanded", "true" ); 931 } 932 933 glue.on( transitionEnd, function() { 934 body.removeClass( "spine-animating spine-move-left spine-move-right" ); 935 936 if ( html.hasClass( "spine-mobile-open" ) ) { 937 html.removeClass( "spine-mobile-open" ); 938 939 $( "#scroll" ).off( "touchstart" ); 940 $( document ).off( "touchmove touchend touchstart" ); 941 } else { 942 html.addClass( "spine-mobile-open" ); 943 944 var scroll_element = document.querySelector( "#scroll" ); 945 946 scroll_element.addEventListener( "touchstart", function() { 947 var top = scroll_element.scrollTop, totalScroll = scroll_element.scrollHeight, currentScroll = top + scroll_element.offsetHeight; 948 949 if ( top === 0 ) { 950 scroll_element.scrollTop = 1; 951 } else if ( currentScroll === totalScroll ) { 952 scroll_element.scrollTop = top - 1; 953 } 954 } ); 955 956 // Prevent scrolling on mobile outside of `#scroll` while the mobile menu is open. 957 $( document ).on( "touchmove touchend touchstart", function( evt ) { 958 if ( $( evt.target ).parents( "#scroll" ).length > 0 || $( evt.target ).is( "#scroll" ) ) { 959 return true; 960 } 961 962 evt.stopPropagation(); 963 evt.preventDefault(); 964 } ); 965 } 966 glue.off( transitionEnd ); 967 } ); 968 }, 969 970 /** 971 * Sets up the spine area 972 */ 973 setup_spine: function() { 974 var self, spine, glue, main, viewport_ht, spine_ht, height_dif, positionLock; 975 976 $( "#spine .spine-header" ).prepend( "<button id='shelve' type='button' aria-label='Site Navigation' aria-haspopup='true' aria-controls='glue' aria-expanded='false' />" ); 977 978 self = this; 979 980 spine = self._get_globals( "spine" ).refresh(); 981 glue = self._get_globals( "glue" ).refresh(); 982 main = self._get_globals( "main" ).refresh(); 983 984 self.nav_state.scroll_top = 0; 985 self.nav_state.scroll_dif = 0; 986 self.nav_state.positionLock = 0; 987 988 // The menu button should always trigger a toggle of the mobile navigation. 989 $( ".spine-header" ).on( "click touchend", "#shelve", self.toggle_mobile_nav ); 990 991 // Tapping anything outside of the Spine should trigger a toggle if the menu is open. 992 main.on( "click", function( e ) { 993 if ( $( "html" ).hasClass( "spine-mobile-open" ) ) { 994 self.toggle_mobile_nav( e ); 995 } 996 } ); 997 998 if ( !self.is_mobile_view() ) { 999 1000 // Watch for DOM changes and resize the Spine to match. 1001 $.observeDOM( glue, function() { 1002 self.apply_nav_func( self ); 1003 } ); 1004 1005 // Fixed/Sticky Horizontal Header 1006 $( document ).on( "scroll", function() { 1007 self.apply_nav_func( self ); 1008 } ); 1009 1010 $( document ).keydown( function( e ) {
1011 if ( e.which === 35 || e.which === 36 ) { 1012 viewport_ht = $( window ).height(); 1013 spine_ht = spine[ 0 ].scrollHeight; 1014 height_dif = viewport_ht - spine_ht; 1015 1016 if ( e.which === 35 ) { 1017 positionLock = height_dif; 1018 } else if ( e.which === 36 ) { 1019 positionLock = 0; 1020 } 1021 1022 spine.css( { "position": "fixed", "top": positionLock + "px" } ); 1023 self.nav_state.positionLock = positionLock; 1024 } 1025 } ); 1026 1027 // Apply the `.skimmed` class to the Spine on non mobile views after 148px. 1028 $( document ).scroll( function() { 1029 var top; 1030 top = $( document ).scrollTop(); 1031 if ( top > 148 ) { 1032 $( "#spine" ).addClass( "skimmed" ); 1033 } else { 1034 $( "#spine" ).removeClass( "skimmed" ); 1035 } 1036 } ); 1037 } 1038 1039 /** 1040 * When the navigation area is shorter than the available window, add a margin to the 1041 * Spine footer so that the scroll container becomes active. This avoids issues on 1042 * mobile devices when overflow is not applied. 1043 */ 1044 if ( self.is_mobile_view() ) { 1045 var nav_height = $( ".spine-header" ).height() + $( "#wsu-actions" ).height() + $( "#spine-navigation" ).height(); 1046 var spine_footer = $( ".spine-footer" ); 1047 var footer_height = spine_footer.height(); 1048 if ( window.innerHeight - nav_height >= footer_height ) { 1049 var margin = window.innerHeight - nav_height - footer_height; 1050 spine_footer.css( "margin-top", margin ); 1051 } 1052 } 1053 }, 1054 1055 /** 1056 * Ensure Spine navigation is properly positioned and sized to snap to the top 1057 * and bottom of the document. 1058 * 1059 * @param self 1060 */ 1061 apply_nav_func: function( self ) { 1062 var spine, glue, main, top, scroll_top, positionLock, scroll_dif, glue_ht; 1063 1064 spine = self._get_globals( "spine" ).refresh(); 1065 glue = self._get_globals( "glue" ).refresh(); 1066 main = self._get_globals( "main" ).refresh(); 1067 1068 scroll_top = self.nav_state.scroll_top; 1069 positionLock = self.nav_state.positionLock; 1070 1071 top = $( document ).scrollTop(); 1072 scroll_dif = scroll_top - top; 1073 scroll_top = top; 1074 glue_ht = glue.height(); 1075 1076 self.nav_state.scroll_top = scroll_top; 1077 1078 // Main should always be at least as high as `#glue`. 1079 main.css( { "min-height": glue_ht } ); 1080 1081 /** 1082 * When the content in `main` is larger than the content in `#glue`, maintain a 1083 * fixed top position on `#spine` for smooth and predictable navigation scrolling. 1084 */ 1085 if ( main.outerHeight( true ) > glue_ht ) { 1086 var upper_bound = glue_ht - window.innerHeight; 1087 1088 /** 1089 * Assume fluid movement by default. As long as we are within the upper bounds 1090 * we can calculate the position based on scroll location whether the scroll 1091 * goes up or down. 1092 */ 1093 positionLock = positionLock + scroll_dif; 1094 1095 /** 1096 * If the position is ever greater than 0, we've scrolled too far up and can 1097 * reset the position to 0. 1098 */ 1099 if ( positionLock > 0 ) { 1100 positionLock = 0; 1101 } 1102 1103 /** 1104 * If we ever scroll to a place where the new position would be calculated 1105 * outside of the upper bound, then reset it to the upper bound. This prevents 1106 * from scrolling too far down. 1107 */ 1108 if ( positionLock < ( -1 * upper_bound ) ) { 1109 positionLock = ( -1 * upper_bound ) - this.framework_options.viewport_offset; 1110 } 1111 1112 spine.css( { "position": "fixed", "top": positionLock + "px" } ); 1113 self.nav_state.positionLock = positionLock; 1114 } else if ( spine.is( "#spine[style]" ) ) { 1115 spine.removeAttr( "style" ); 1116 } 1117 }, 1118 1119 /** 1120 * Toggle a Spine action item and the data associated with it between an 1121 * open and closed state on touch. 1122 * 1123 * @param evt 1124 * @private 1125 */ 1126 _toggle_spine_action_item: function( evt ) { 1127 var tab, action_ht; 1128 1129 evt.preventDefault(); 1130 1131 tab = $( evt.target ).parent( "li" ).attr( "id" ).split( "-" )[ 1 ]; 1132 1133 $( "#wsu-actions" ).find( "*.opened, #wsu-" + tab + ", #wsu-" + tab + "-tab" ).toggleClass( "opened closed" ); 1134 1135 if ( $( evt.target ).parent( "li" ).hasClass( "opened" ) ) { 1136 $( "#spine-navigation, .spine-footer" ).css( "visibility", "hidden" ); 1137 } else { 1138 $( "#spine-navigation, .spine-footer" ).css( "visibility", "initial" ); 1139 } 1140 1141 action_ht = window.innerHeight - $( ".spine-header" ).outerHeight() - $( "#wsu-actions-tabs" ).outerHeight(); 1142 1143 $( ".spine-action.opened" ).css( "min-height", action_ht ); 1144 $( evt.target ).off( "mouseup touchend", $.ui.spine.prototype._toggle_spine_action_item ); 1145 }, 1146 1147 /** 1148 * Process a WSU action tab (mail, sharing, etc...) and setup the 1149 * structure accordingly. 1150 */ 1151 setup_tabs: function( tab, html ) { 1152 var self, wsu_actions, action_ht; 1153 1154 html = html || ""; 1155 self = this; 1156 1157 wsu_actions = self._get_globals( "wsu_actions" ).refresh(); 1158 1159 $( "#wsu-" + tab + "-tab" ).append( html ); 1160 1161 if ( self.is_mobile_view() ) { 1162 $( "#wsu-" + tab + "-tab > button" ).on( "mousedown touchstart", function( e ) { 1163 $( e.target ).on( "mouseup touchend", $.ui.spine.prototype._toggle_spine_action_item ); 1164 $( e.target ).on( "mousemove touchmove", function( e ) { 1165 $( e.target ).off( "mouseup touchend", $.ui.spine.prototype._toggle_spine_action_item ); 1166 } ); 1167 } ); 1168 } else { 1169 $( "#wsu-" + tab + "-tab > button" ).on( "click", function( e ) { 1170 e.preventDefault();
1171 wsu_actions.find( "*.opened,#wsu-" + tab + ",#wsu-" + tab + "-tab" ).toggleClass( "opened closed" ); 1172 1173 // Hide the Spine navigation from screen readers when action tabs are in focus. 1174 if ( $( "#wsu-" + tab + "-tab" ).hasClass( "opened" ) ) { 1175 $( "#spine-navigation, .spine-footer" ).css( "visibility", "hidden" ); 1176 } else { 1177 $( "#spine-navigation, .spine-footer" ).css( "visibility", "initial" ); 1178 } 1179 1180 action_ht = window.innerHeight - $( ".spine-header" ).outerHeight() - $( "#wsu-actions-tabs" ).outerHeight(); 1181 1182 $( ".spine-action.opened" ).css( "min-height", action_ht ); 1183 } ); 1184 } 1185 }, 1186 1187 /** 1188 * Toggle a parent list item and its children between an open 1189 * and closed state on touch. 1190 * 1191 * @param evt 1192 * @private 1193 */ 1194 _toggle_spine_nav_list: function( evt ) { 1195 var target = $( evt.target ); 1196 1197 evt.preventDefault(); 1198 target.closest( "li" ).toggleClass( "opened" ); 1199 1200 // Remove the toggle event, as it will be added again on the next touchstart. 1201 target.off( "mouseup touchend", $.ui.spine.prototype._toggle_spine_nav_list ); 1202 }, 1203 1204 /** 1205 * Sets up navigation system 1206 */ 1207 setup_nav: function() { 1208 var self = this; 1209 1210 // Apply the `parent` class to each parent list item of an unordered list in the navigation. 1211 $( "#spine nav ul, #spine ul" ).parents( "li" ).addClass( "parent" ); 1212 1213 var couplets = $( "#spine nav li.parent > a" ); 1214 1215 // Assign active elements a class of dogeared unless those elements contain other active elements. 1216 $( "#spine .active:not(:has(.active))" ).addClass( "dogeared" ); 1217 1218 /** 1219 * Walk through each of the anchor elements in the navigation to establish when "Overview" 1220 * items should be added and what the text should read. 1221 */ 1222 couplets.each( function() { 1223 var tar, title, url; 1224 tar = $( this ); 1225 url = tar.attr( "href" ); 1226 1227 // "Overview" anchors are only added for parents with URLs. 1228 if ( "#" === url ) { 1229 return; 1230 } 1231 1232 var classes = "overview"; 1233 1234 // If a generated overview's parent is marked as dogeared, do the same with the overview. 1235 if ( tar.closest( ".parent" ).is( ".dogeared" ) ) { 1236 classes += " dogeared"; 1237 } 1238 1239 title = ( tar.is( "[title]" ) ) ? tar.attr( "title" ) : "Overview"; 1240 title = ( tar.is( "[data-overview]" ) ) ? tar.data( "overview" ) : title; 1241 title = title.length > 0 ? title : "Overview"; // This is just triple checking that a value made it here. 1242 1243 tar.parent( "li" ).children( "ul" ).prepend( "<li class='" + classes + "'></li>" ); 1244 tar.clone( true, true ).appendTo( tar.parent( "li" ).find( "ul .overview:first" ) ); 1245 tar.parent( "li" ).find( "ul .overview:first a" ).html( title ); 1246 1247 // When the overview page is active, that area of the navigation should be opened. 1248 if ( tar.parent( "li" ).hasClass( "active" ) ) { 1249 tar.parents( "li" ).removeClass( "active" ).addClass( "opened dogeared" ); 1250 } 1251 } ); 1252 1253 /** 1254 * Account for historical markup in the WSU ecosystem and add the `active` and `dogeared` classes 1255 * to any list items that already have classes similar to `current` or `active`. Also apply the 1256 * `opened` and `dogeared` classes to any parent list items of these active elements. 1257 * 1258 * `active` and `dogeared` are both used for the styling of active menu items in the navigation. 1259 */ 1260 $( "#spine nav li[class*=current], #spine nav li[class*=active]" ).addClass( "active dogeared" ).parents( "li" ).addClass( "opened dogeared" ); 1261 1262 /** 1263 * Also look for any anchor elements using a similar method and apply `active` and `dogeared` classes to 1264 * all parent list items. 1265 */ 1266 $( "#spine nav li a[class*=current], #spine nav li a[class*=active]" ).parents( "li" ).addClass( "active dogeared" ); 1267 1268 /** 1269 * Setup navigation events depending on what the screen size is when the document first 1270 * loads. If mobile, we use touch events for navigation. If not mobile, we rely on 1271 * standard click events. 1272 * 1273 * Some additional handling is necessary on mobile to properly handle the sequence of 1274 * touchstart, touchmove, and touchend without confusion. 1275 */ 1276 if ( self.is_mobile_view() ) { 1277 couplets.on( "mousedown touchstart", function( e ) { 1278 $( e.target ).on( "mouseup touchend", $.ui.spine.prototype._toggle_spine_nav_list ); 1279 $( e.target ).on( "mousemove touchmove", function( e ) { 1280 $( e.target ).off( "mouseup touchend", $.ui.spine.prototype._toggle_spine_nav_list ); 1281 } ); 1282 } ); 1283 } else { 1284 1285 // Disclosure 1286 couplets.on( "click", function( e ) { 1287 e.preventDefault(); 1288 $( e.target ).closest( "li" ).toggleClass( "opened" ); 1289 } ); 1290 1291 // Trigger a scroll action when an anchor link is used. 1292 $( "main a[href*='#']:not([href*='://'])" ).on( "mouseup", function() { 1293 $( document ).trigger( "scroll" ); 1294 } ); 1295 } 1296 1297 // Mark external URLs in the nav menu. 1298 $( ".spine-navigation a[href^='http']:not([href*='://" + window.location.hostname + "'])" ).addClass( "external" ); 1299 }, 1300 1301 /** 1302 * Handle printing action when selected in the Spine. 1303 */ 1304 setup_printing: function() { 1305 var self, spine, wsu_actions, print_controls; 1306 1307 self = this; 1308 spine = self._get_globals( "spine" ).refresh(); 1309 wsu_actions = self._get_globals( "wsu_actions" ).refresh(); 1310 1311 // Print & Print View
1312 print_controls = "<span class='print-controls'><button id='print-invoke'>Print</button><button id='print-cancel'>Cancel</button></span>"; 1313 1314 function printPage() { 1315 window.print(); 1316 } 1317 1318 function print_cancel() { 1319 $( "html" ).toggleClass( "print" ); 1320 $( ".print-controls" ).remove(); 1321 } 1322 1323 function print( e ) { 1324 if ( undefined !== e ) { 1325 e.preventDefault(); 1326 } 1327 wsu_actions.find( ".opened" ).toggleClass( "opened closed" ); 1328 $( "html" ).toggleClass( "print" ); 1329 spine.find( "header" ).prepend( print_controls ); 1330 $( ".unshelved" ).removeClass( "unshelved" ).addClass( "shelved" ); 1331 $( "#print-invoke" ).on( "click", function() { window.print(); } ); 1332 $( "#print-cancel" ).on( "click", print_cancel ); 1333 window.setTimeout( function() { printPage(); }, 400 ); 1334 } 1335 $( "#wsu-print-tab button" ).click( print ); 1336 1337 // Shut a tool section 1338 $( "button.shut" ).on( "click touchend", function( e ) { 1339 e.preventDefault(); 1340 wsu_actions.find( ".opened" ).toggleClass( "opened closed" ); 1341 } ); 1342 } 1343 } ); 1344}( jQuery ) ); 1345 1346 /*! 1347 * 1348 * Depends: 1349 * jquery.ui.v.js 1350 */ 1351/*jshint multistr: true */ 1352( function( $ ) { 1353 "use strict"; 1354 $.extend( $.ui.spine.prototype, { 1355 search_init: function( options ) { 1356 var self; 1357 self = this;//Hold to preserve scop 1358 $.extend( options, self.search_options, options ); 1359 this._set_globals( this.search_globals ); 1360 this.create_search(); 1361 }, 1362 1363 search_options:{ 1364 data:[], 1365 providers:{ 1366 nav:{ 1367 name:"From Navigation", 1368 nodes: ".spine-navigation", 1369 dataType: "html", 1370 maxRows: 12, 1371 urlSpaces:"%20" 1372 }, 1373 atoz:{ 1374 name:"WSU A to Z index", 1375 url: "https://search.wsu.edu/2013service/searchservice/search.asmx/AZSearch", 1376 urlSpaces:"+", 1377 dataType: "jsonp", 1378 featureClass: "P", 1379 style: "full", 1380 maxRows: 12, 1381 termTemplate:"<strong><%this.term%></strong>", 1382 resultTemplate:"" 1383 } 1384 }, 1385 search:{ 1386 minLength: 2, 1387 maxRows: 12, 1388 getRelated:true, 1389 urlSpaces:"+", 1390 tabTemplate: "<section id='wsu-search' class='spine-search spine-action closed'>" + 1391 "<form id='default-search'>" + 1392 "<input name='term' type='text' value='' placeholder='search' title='Type search term here'>" + 1393 "<button type='submit'>Submit</button>" + 1394 "</form>" + 1395 "<div id='spine-shortcuts' class='spine-shortcuts'></div>" + 1396 "</section>" 1397 }, 1398 result:{ 1399 appendTo: "#spine-shortcuts", 1400 showRelated:true, 1401 target:"_blank", 1402 relatedHeader:"<b class='related_sep'>Related</b><hr/>", 1403 providerHeader:"<b class='provider_header'><%this.provider_name%></b><hr/>", 1404 termTemplate:"<b><%this.term%></b>", 1405 template:"<li><%this.searchitem%></li>" 1406 } 1407 }, 1408 search_globals: { 1409 wsu_search: $( "#wsu-search" ), 1410 search_input:$( "#wsu-search input[type=text]" ) 1411 }, 1412 create_search: function() { 1413 var self, wsu_search, tabhtml; 1414 self = this;//Hold to preserve scop 1415 wsu_search = self._get_globals( "wsu_search" ).refresh(); 1416 if ( !wsu_search.length ) { 1417 tabhtml = $.runTemplate( self.search_options.search.tabTemplate, {} ); 1418 }else { 1419 tabhtml = "<section id='wsu-search' class='spine-search spine-action closed'>" + wsu_search.html() + "</section>"; 1420 wsu_search.remove(); 1421 } 1422 this.setup_tabs( "search", tabhtml ); 1423 1424 if ( $( "#spine-shortcuts" ).length <= 0 ) { 1425 $( "#wsu-search" ).append( "<div id='spine-shortcuts' class='spine-shortcuts'></div>" ); 1426 } 1427 1428 $( "#wsu-search-tab button" ).on( "click touchend", function() { 1429 self._get_globals( "search_input" ).refresh().focus(); 1430 } ); 1431 this.setup_search(); 1432 }, 1433 1434 start_search:function( request, callback ) { 1435 var self, term, queries = []; 1436 self = this;//Hold to preserve scop 1437 1438 term = $.trim( request.term ); 1439 self.search_options.data = []; 1440 $.each( self.search_options.providers, function( i, provider ) { 1441 $.ui.autocomplete.prototype.options.termTemplate = ( typeof( provider.termTemplate ) !== undefined && provider.termTemplate !== "" ) ? provider.termTemplate : undefined; 1442 queries.push( self.run_query( term, provider ) ); 1443 } ); 1444 1445 $.when.apply( $, queries ).done( 1446 function() { 1447 $.each( arguments, function( i, v ) { 1448 var data, proData; 1449 if ( v !== undefined ) { 1450 data = v[ 0 ]; 1451 if ( data !== undefined && data.length > 0 ) { 1452 proData = self.setup_result_obj( term, data ); 1453 $.merge( self.search_options.data, proData ); 1454 } 1455 } 1456 } ); 1457 self._call( callback, self.search_options.data ); 1458 } ); 1459 }, 1460 1461 run_query:function( term, provider ) { 1462 var self, result = [], tmpObj = [], nodes; 1463 self = this;//Hold to preserve scop 1464 result = []; 1465 1466 if ( typeof( provider ) !== undefined && typeof( provider.url ) !== undefined && provider.nodes === undefined ) { 1467 return $.ajax( { 1468 url: provider.url, 1469 dataType: provider.dataType, 1470 data: { 1471 featureClass: provider.featureClass, 1472 style: provider.style, 1473 maxRows: provider.maxRows, 1474 name_startsWith: term, 1475 related:self.search_options.search.getRelated 1476 } 1477 } ); 1478 }else if ( typeof( provider ) !== undefined && typeof( provider.nodes ) !== undefined ) { 1479 nodes = $( provider.nodes ).find( "a" ); 1480 $.each( nodes, function( i, v ) { 1481 var obj, text, localtmpObj; 1482 obj = $( v ); 1483 text = obj.text(); 1484 if ( text.toLowerCase().indexOf( term.toLowerCase() ) > -1 && obj.attr( "href" ) !== "#" ) { 1485 localtmpObj = { 1486 label:text, 1487 value:obj.attr( "href" ), 1488 related:"false", 1489 searchKeywords:"" 1490 }; 1491 tmpObj.push( localtmpObj ); 1492 } 1493 } ); 1494 return [ tmpObj ]; 1495 } 1496 }, 1497 1498 format_result_text:function( term, text, value ) { 1499 var self, termTemplate, regex; 1500 self = this;//Hold to preserve scope 1501 1502 termTemplate = "<strong>$1</strong>"; //Typeof($.ui.autocomplete.prototype.options.termTemplate)!==undefined ? $.ui.autocomplete.prototype.options.termTemplate : "<strong>$1</strong>"; 1503 1504 regex = "(?![^&;]+;)(?!<[^<>]*)(" + $.ui.autocomplete.escapeRegex( term ) + ")(?![^<>]*>)(?![^&;]+;)"; 1505 text = "<a href='" + value + "' target='" + self.search_options.result.target + "'>" + text.replace( new RegExp( regex, "gi" ), termTemplate ) + "</a>"; 1506 1507 return text; 1508 }, 1509 1510 setup_result_obj:function( term, data ) { 1511 var self, matcher; 1512 self = this;//Hold to preserve scop 1513 matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" ); 1514 return $.map( data, function( item ) { 1515 var text, value, resultObj; 1516 text = item.label; 1517 value = item.value; 1518 if ( ( item.value && ( !term || matcher.test( text ) ) || item.related === "true" ) ) { 1519 text = self.format_result_text( term, text, value ); 1520 resultObj = { 1521 label: text, 1522 value: item.value, 1523 searchKeywords: item.searchKeywords !== undefined ? item.searchKeywords : "false", 1524 related: item.related !== undefined ? item.related : "false" 1525 }; 1526 return resultObj; 1527 } 1528 } ); 1529 }, 1530 1531 setup_search: function() { 1532 var self, wsu_search, search_input, focuseitem = {}; 1533 1534 self = this;//Hold to preserve scop 1535 wsu_search = self._get_globals( "wsu_search" ).refresh(); 1536 search_input = self._get_globals( "search_input" ).refresh(); 1537 focuseitem = {}; 1538 1539 search_input.autosearch( { 1540 1541 appendTo: self.search_options.result.appendTo, 1542 showRelated: self.search_options.result.showRelated, 1543 relatedHeader: self.search_options.result.relatedHeader, 1544 minLength: self.search_options.search.minLength, 1545 1546 source: function( request, response ) { 1547 self.start_search( request, function( data ) { 1548 response( data ); 1549 } ); 1550 }, 1551 search: function( ) { 1552 focuseitem = {}; 1553 }, 1554 select: function( e, ui ) { 1555 var id, term; 1556 id = ui.item.searchKeywords; 1557 term = $( ui.item.label ).text(); 1558 search_input.val( term ); 1559 search_input.autosearch( "close" ); 1560 return false;
1561 }, 1562 focus: function( e, ui ) { 1563 search_input.val( $( ui.item.label ).text() ); 1564 focuseitem = { 1565 label:ui.item.label 1566 }; 1567 e.preventDefault(); 1568 }, 1569 open: function( ) {}, 1570 close: function( e ) { 1571 e.preventDefault(); 1572 return false; 1573 } 1574 } ).data( "autosearch" ); 1575 1576 $( "#wsu-search form" ).submit( function() { 1577 var scope, site, cx, cof, search_term, search_url; 1578 scope = wsu_search.attr( "data-default" ); 1579 site = " site:" + window.location.hostname; 1580 if ( scope === "wsu.edu" ) { 1581 site = ""; 1582 } 1583 cx = "cx=004677039204386950923:xvo7gapmrrg"; 1584 cof = "cof=FORID%3A11"; 1585 search_term = search_input.val(); 1586 search_url = "https://search.wsu.edu/default.aspx?" + cx + "&" + cof + "&q=" + search_term + site; 1587 window.location.href = search_url; 1588 return false; 1589 } ); 1590 } 1591 } ); 1592}( jQuery ) ); 1593 1594/*! 1595* 1596* Depends: 1597* jquery.ui.spine.js 1598*/ 1599/*jshint multistr: true */ 1600( function( $ ) { 1601 $.extend( $.ui.spine.prototype, { 1602 social_init: function( options ) { 1603 $.extend( this.social_options, options ); 1604 1605 this._set_globals( this.social_globals ); 1606 this.social_create(); 1607 }, 1608 /** 1609 * These default options can be overridden with an object before 1610 * the Spine framework is started and with `$('body').spine( spineoptions )`. 1611 * 1612 * NOTE: The structure of these social options **will** change and could be 1613 * deprecated in a future release. Please communicate via the WSU Spine repository 1614 * when using these so that we can reach out before a transition in the future. 1615 * 1616 * https://github.com/washingtonstateuniversity/WSU-spine/issues/230 1617 */ 1618 social_options:{ 1619 share_text:"You should know ...", 1620 twitter_text:"You should know...", 1621 twitter_handle:"wsupullman", 1622 linkedin_source:"wsu.edu" 1623 }, 1624 social_globals: { 1625 share_block: $( "#wsu-share" ) 1626 }, 1627 social_create: function() { 1628 var self, share_block, share_text, current_url, wsu_actions, sharehtml, twitter_text, twitter_handle, linkedin_source; 1629 self = this;//Hold to preserve scope 1630 share_block = self._get_globals( "share_block" ).refresh(); 1631 if ( !share_block.length ) { 1632 share_text = encodeURIComponent( this.social_options.share_text ); 1633 twitter_text = encodeURIComponent( this.social_options.twitter_text ); 1634 twitter_handle = encodeURIComponent( this.social_options.twitter_handle ); 1635 current_url = self._get_globals( "current_url" ); 1636 wsu_actions = self._get_globals( "wsu_actions" ).refresh(); 1637 1638 sharehtml = "<section id='wsu-share' class='spine-share spine-action closed'>"; 1639 sharehtml += "<ul>"; 1640 sharehtml += "<li class='by-facebook'><a href='https://www.facebook.com/sharer/sharer.php?u=" + current_url + "'><span class='screen-reader-text'>Share this URL on </span>Facebook</a></li>"; 1641 1642 sharehtml += "<li class='by-twitter'><a href='https://twitter.com/intent/tweet?text=" + twitter_text + "&url=" + current_url; 1643 sharehtml += "&via=" + twitter_handle + "' target='_blank'><span class='screen-reader-text'>Share this URL on </span>Twitter</a></li>"; 1644 1645 sharehtml += "<li class='by-googleplus'><a href='https://plus.google.com/share?url=" + current_url + "'><span class='screen-reader-text'>Share this URL on </span>Google+</a></li>"; 1646 1647 sharehtml += "<li class='by-linkedin'><a href='https://www.linkedin.com/shareArticle?mini=true&url=" + current_url + "&summary=";
1648 sharehtml += share_text + "&source=" + linkedin_source + "' target='_blank'><span class='screen-reader-text'>Share this URL on </span>Linkedin</a></li>"; 1649 1650 sharehtml += "<li class='by-email'><a href='mailto:?subject=" + share_text + "&body=" + current_url + "'><span class='screen-reader-text'>Share this URL with </span>Email</a></li>"; 1651 sharehtml += "</ul>"; 1652 sharehtml += "</section>"; 1653 1654 self.setup_tabs( "share", sharehtml ); 1655 } // End Share Generation 1656 } 1657 } ); 1658}( jQuery ) ); 1659 1660( function( $ ) { 1661 "use strict"; 1662 $( document ).ready( function() { 1663 $( "html" ).removeClass( "no-js" ).addClass( "js" ); 1664 var spineoptions = window.spineoptions || {}; 1665 $.spine( spineoptions ); 1666 } ); 1667} )( 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.