1//adding comment to test connection between assets-web and global assets 2 3/******************************************************************************* 4 Minimum Dependencies: JQuery, JQueryUI JS/CSS, Bootstrap JS/CSS 5********************************************************************************/ 6var debugON = false; 7/******************************************************************************* 8 Required assistive technology text, can be abstracted for bi-lingual support 9********************************************************************************/ 10var exitText = '<span class="sr-only"> opens a new tab</span>', 11 //insert same span but with visible image on page 12 exitTextImage = '<span class="fa fa-external-link fa-spacing"><span class="adobeBlank" aria-hidden="true">New Window icon</span></span><span class="sr-only">This link opens a new window or tab</span>', 13 //policy text 14 policyText = '<a href="http://www.medicare.gov/sharedresources/shared/pages/external-link-disclaimer.aspx" class="fa fa-external-link non-gov-notice" title="Medicare\' External Link Policy" target="_blank"><span class="adobeBlank">New Window icon</span></a>', 15 //use hidden text to note where user is located 16 youAreHere = '<span class="hiddenText">You are here</span>', 17 //add ARIA attributes to mobile navigation and remove if screen size is adjusted above mobile screen size 18 mobileDropdownUl = $('#topNavList').find('.navbar-nav'), 19 //variable to find accordion header text 20 headerTitle; 21 22 23/************************************************************************* 24 Namespaced method to use in conjunction with jQuery extension methods. 25**************************************************************************/ 26var A11y = { 27 Core: function() { 28 //add sr only text for links that open in new window 29 this.externalWindow(); 30 31 //add external policy link 32 this.externalPolicy(); 33 34 //add proper headings 35 this.headings(); 36 37 //add proper font iconts 38 this.fontIcons(); 39 40 41 /******************************************* 42 find focusable item when page changes 43 *******************************************/ 44 var focusable = $('html').find().first(':focusable'); 45 46 /******************************************* 47 framebuster 48 ********************************************/ 49 //hide content on page load, can be any element 50 $(".container").hide(); 51 if (window.self === window.top) { 52 //show content if not in a frame 53 $(".container").show(); 54 } else { 55 //reloads the page to show without frame. 56 top.location = self.location; 57 } 58 59 /******************************************* 60 Live Regions 61 ********************************************/ 62 //add live region for anything to use for announcements to screen readers 63 if ($('#liveText').length === 0) { 64 $('body').prepend('<div id="liveText" class="sr-only" aria-live="assertive"></div>'); 65 $('body').prepend('<div id="liveText-polite" class="sr-only" aria-live="polite"></div>'); 66 } 67 68 /******************************************* 69 Mark up presentation tables 70 ********************************************/ 71 // Add attr to presentation tables; for accessibility 72 if (!$('.table-presentation').attr('role')) { 73 $('.table-presentation').attr('role', 'presentation'); 74 } 75 76 /******************************************* 77 Add global Language if not defined 78 ********************************************/ 79 var htmlAttr = $("html").attr('lang'); 80 81 // For some browsers, `attr` is undefined; 82 if (typeof htmlAttr === typeof undefined || htmlAttr === false) { 83 $('html').attr('lang', 'en-US'); 84 } 85 86 }, 87 accordionHelper: function() { 88 //toggle accordion header collapsed/expanded status 89 $('.ui-accordion-header').find('.sr-section-alert').text(function() { 90 return ($(this).parent().hasClass('ui-accordion-header-active')) ? $(this).text().replace('collapsed', 'expanded') : $(this).text().replace('exp
90anded', 'collapsed'); 91 }); 92 //toggle accordion header collapsed/expanded icon status 93 $('.ui-accordion-header').find('.arrow-icon').text(function() { 94 return ($(this).parent().hasClass('fa-caret-down')) ? $(this).text().replace('Collapsed', 'Expanded') : $(this).text().replace('Expanded', 'Collapsed'); 95 }); 96 97 }, 98 //accordion 508 99 accordion: function(el) { 100 101 el.on("accordioncreate", function() { 102 //change aria live to active header on selection --- added keyup for spacebar functionality 103 $('.ui-accordion-header').removeAttr("aria-live").next('div').removeAttr('aria-live').attr('aria-expanded', 'false'); 104 $('.ui-accordion-header').find('.ui-accordion-header-icon').attr({ 105 'role': 'presentation', 106 'aria-hidden': true 107 }); 108 $('.ui-accordion-header-active').next('div').attr('aria-live', 'polite'); 109 110 $('.ui-accordion-header').append('<span class="sr-only sr-section-alert"> section is collapsed</span>').children('.ui-accordion-header-icon'); 111 if ($('html').hasClass('ui-helper-nocustomfonts') && ($('html').hasClass('lt-ie9') || $('html').hasClass('ie9') || $('html').hasClass('ie10') || $('html').hasClass('ie11'))) { 112 $('.ui-accordion-header').append('<span class="sr-only sr-section-alert"> section is collapsed</span>').children('.ui-accordion-header-icon').html('<span class="adobeBlank arrow-icon" aria-hidden="true">Collapsed arrow icon</span>'); 113 } 114 A11y.accordionHelper(); 115 116 }); 117 el.on("accordionbeforeactivate", function(event) { 118 //make changes before new tab is opened so screen reader announces the changes 119 var activeHeader = $(event.target).attr('id'); 120 121 $('.ui-accordion-header').find('.sr-section-alert').text(function() { 122 return (activeHeader) ? $(this).text().replace('collapsed', 'expanded') : $(this).text().replace('expanded', 'collapsed'); 123 }); 124 125 126 }); 127 //change Expand collapse due to collapsible bug with aria expanded 128 el.on("accordionactivate", function() { 129 var activeContent = $(this).find('.ui-accordion-content-active'); 130 $(this).children().each(function() { 131 A11y.accordionHelper(); 132 }); 133 $('.ui-accordion').find('.ui-accordion-header-active').attr({ 134 'aria-expanded': true, 135 'aria-selected': true 136 }); 137 //activeContent.focus(); 138 }); 139 }, 140 141 //alert 508 142 alerts: function() { 143 //Close alert and return focus to last focused element 144 $("body").on("click", ".close", function() { 145 $(this).blur(); 146 $(this).closest(".alert").fadeOut("slow"); 147 $(this).parent().prev().focus(); 148 $(this).closest(".alert").delay(1500).remove(); 149 }); 150 }, 151 152 //autocomplete 508 153 autocomplete: function() { 154 //add a half second delay to when autocomplete suggestion shows for screen reader 155 $(".ui-autocomplete-input").attr("aria-controls", "list").attr("aria-haspopup", "true"); 156 157 /*$(".ui-autocomplete-input").on("click", function(){ 158 $('html,body').animate({ 159 scrollTop: $(this).offset().top 160 }, 1000); 161 });*/ 162 163 $(".ui-autocomplete-input").on("autocompleteselect", function(event, ui) { 164 $('#liveText').html(ui.item ? 'Selected: ' + ui.item.value : 'Nothing selected'); 165 }); 166 167 }, 168 bindSkipNav: function(e) { 169 e.preventDefault(); 170 var target = $(e.target).attr('href'); 171 $(target).focus(); 172 }, 173 174 //block UI 508 175 block: function(el, enable) { 176 //adding structure for jquery ui dialog 177 if ($(".blockUI")) { 178 if (enable) { 179 $('.wrapper').attr('aria-hidden', 'true'); 180 $('#liveText').html('Processing Started. Please wait'); 181 182 setTimeout(function() { 183 $(".blockUI").attr({ 184 tabindex: "-1", 185 width: "auto" 186 }); 187 }, 10); //set tabindex to -1 after title receives focus 188 } else { 189 $('.wrapper').attr('aria-hidden', 'false'); 190 $('#liveText').html('Processing Completed'); 191 } 192 193 } 194 195 }, 196 197 // Custom input 198 customInput: function() { 199 $('input[type=checkbox], input[type=radio]').each(function() { 200 var input = $(this); 201 202 // get the associated label using the input's id 203 var label = $('label[for=' + input.attr('id') + ']'); 204 205 206 // add disabled class for disabled inputs 207 if (input.attr('disabled')) label.addClass('disabled'); 208 }); 209 }, 210 211 carousel: function() { 212 //show-hide prev/next buttons and change focus for when each is hidden 213 $('#myCarousel').carousel({ 214 interval: false, 215 wrap: false 216 }).on('slid.bs.carousel', function() { 217 var pages = $(this).find("ul.item"); 218 var currentPage = pages.filter(".active"); 219 var currentIndex = pages.index(currentPage) + 1; 220 var lrUpdate = "Showing Carousel page " + currentIndex + " of " + pages.length; 221 $(".myCarousel-liveRegion").text(lrUpdate); 222 223 var $this = $(this); 224 $this.children('.carousel-control').show(); 225 if ($('.carousel-inner .item:first').hasClass('active')) { 226 $this.children('.left.carousel-control').hide(); 227 //focus on first li a of first ul in carousel when the prev navigation button is hidden 228 $('.carousel-inner .item:first').find('li:first>a').focus(); 229 230 } else if ($('.carousel-inner .item:last').hasClass('active')) { 231 $this.children('.right.carousel-control').hide(); 232 //focus on last li a of last ul in carousel when the next navigation button is hidden 233 $('.carousel-inner .item:last').find('li:last>a').focus(); 234 } 235 }); 236 $('.left.carousel-control').hide(); 237 $('.right.carousel-control').show(); 238 }, 239 240 //datatables 508 241 datatables: function() { 242 243 //for datatables, add first and second columns into sr only description of row edit/remove buttons 244 /*$('.rowActionBtn').each(function(index, element) { 245 var firstColumn = $(this).closest('tr').children(':first-child').text().trim(); 246 var lastColumn = $(this).closest('tr').children(':nth-child(2)').text().trim(); 247 $(this).children(".actionRowNum").html(firstColumn + ' ' + lastColumn); 248 $('.paginate_enabled_previous, .paginate_enabled_next').css('cursor', 'pointer'); 249 });*/ 250 $('.previous, .next').on('click', function() { 251 $('.rowActionBtn').each(function(index, element) { 252 var firstColumn = $(this).closest('tr').children(':first-child').text().trim(); 253 var lastColumn = $(this).closest('tr').children(':nth-child(2)').text().trim(); 254 $(this).children(".actionRowNum").html(firstColumn + ' ' + lastColumn); 255 }); 256 257 }); 258 //copy abbr from li and place on child anchor for screen reader 259 $(".dataTable th").each(function(index, element) { 260 $(this).attr('aria-label', $(this).attr('abbr')); 261 }); 262 //data tables remove action link in header and replace with P tag 263 if ($(".dataTable th").hasClass('sorting_disabled')) { 264 //data tables remove action link in header and replace with P tag 265 var alertItem = $('.sorting_disabled').children('a').text(); 266 $(".sorting_disabled").children("a").delay(100).replaceWith("<p class='fauxLinkHeader'>" + alertItem + "</p>"); 267 $(".fauxLinkHeader").css({ 268 'font-size': '1em', 269 'line-height': '1.125em', 270 'margin-bottom': '0', 271 'text-decoration': 'underline', 272 'cursor': 'context-menu' 273 }); 274 }
275 $(".fa-trash-o").attr("style", "font-family :'FontAwesome' !important").html("<span class='adobeBlank'>Delete icon </span>"); 276 //change text for save button also 277 $('.dataTable').on('click', '.rowActionBtn.save', function() { 278 $('#liveText').text('Changes Saved'); 279 setTimeout(function() { 280 $('#liveText').text(''); 281 }, 1000); 282 $(this).closest('tr').find('.edit').focus(); 283 }); 284 $('.dataTable').on('click', '.rowActionBtn.edit', function() { 285 var firstColumn = $(this).closest('tr').children(':first-child').find('input').val(); 286 var lastColumn = $(this).closest('tr').children(':nth-child(2)').find('input').val(); 287 if (debugON) console.log(firstColumn); 288 $(this).children(".actionRowNum").text(firstColumn + ' ' + lastColumn); 289 290 $('#liveText').text('Editing ' + firstColumn + ' ' + lastColumn); 291 setTimeout(function() { 292 $('#liveText').text(''); 293 }, 1000); 294 // wait 1 second to remove message to existing live region 295 }); 296 $('.dataTable').on('click', '.rowActionBtn.delete', function() { 297 var firstColumn = $(this).closest('tr').children(':first-child').find('input').val(); 298 var lastColumn = $(this).closest('tr').children(':nth-child(2)').find('input').val(); 299 if (debugON) console.log(firstColumn); 300 $(this).children(".actionRowNum").text(firstColumn + ' ' + lastColumn); 301 302 $('#liveText').text('Deleted row'); 303 setTimeout(function() { 304 $('#liveText').text(''); 305 }, 10000); 306 // wait 1 second to remove message to existing live region 307 }); 308 //remove links which are disabled from tab order 309 $('.dataTables_paginate a').each(function() { 310 if ($(this).hasClass('disabled')) { 311 $(this).attr('tabindex', '-1'); 312 } 313 }); 314 //change tab index on pagination links to remove disabled links from tab order 315 $(document).on('click keyup', 'a', function(e) { 316 if (e.type == 'click' || (e.type == 'keyup' && e.keyCode == 13)) { 317 var dts = $('.dataTables_paginate'); 318 if ($(dts).hasClass('dataTables_paginate')) { 319 setTimeout(function() { 320 $('.dataTables_paginate a').attr('tabindex', '0'); 321 $('.dataTables_paginate a.disabled').attr('tabindex', '-1'); 322 }, 100); 323 } 324 } 325 }); 326 327 }, 328 329 //datepicker 508 330 datepicker: function() { 331 //add fontawesome font family to datepicker calendars 332 $('.date-picker-control .fa.fa-calendar').attr("style", "font-family :'FontAwesome' !important"); 333 }, 334 335 //dialog 508 336 dialog: function(el) { 337 var dialog = $('.ui-dialog'), 338 contents = $('.dialog-contents'), 339 titleBar = $('.ui-dialog-titlebar'); 340 341 //adding structure for jquery ui dialog 342 if ($('div').hasClass('ui-dialog')) { 343 dialog.find('.ui-dialog-content').attr('aria-hidden', 'false'); 344 //wrap dialog inner elements 345 if (dialog.find(contents).length === 0) { 346 dialog.wrapInner("<div class='dialog-contents' role='document'></div>"); 347 } 348 //add attributes to close button 349 titleBar.find('.ui-button').attr({ 350 //'tabindex': "0", 351 "aria-label": 'Close' 352 }).addClass("fa fa-times-circle icon_circle_remove pull-right") 353 .removeClass("ui-dialog-titlebar-close ui-button-icon-only") 354 .find('.ui-button-text') 355 .addClass("adobeBlank") 356 .attr('aria-hidden', 'true') 357 .css('position', 'absolute'); 358 //make title element focusable and set up as H1 359 titleBar.find('.ui-dialog-title').attr({ 360 'tabindex': '-1', 361 'style': 'width: auto', 362 'role': 'heading',
363 'aria-level': '1' 364 }) 365 366 } 367 if ($("#progressDialog").is('.ui-dialog-content')) { 368 if ($('#progressbarText').length === 0) { 369 $('.ui-dialog-content').append('<div id="progressbarText" class="sr-only" role="status" aria-live="assertive"></div>'); 370 } 371 }; 372 }, 373 dialogOpen: function() { 374 var titleBar = $('.ui-dialog-titlebar'), 375 title = $('.ui-dialog-title'), 376 progressTrigger = $('.progressTriggerFocus'); 377 378 //make 'x' close button in header larger 379 titleBar.find('.ui-button').attr({ 380 "style": "font-family: 'FontAwesome' !important;font-size: 44px !important;" 381 }); 382 //change title to H1 383 title.replaceWith(function() { 384 var attrs = ''; 385 $($(this)[0].attributes).each(function(i, v) { 386 attrs += ' ' + this.nodeName + '="' + this.value + '"'; 387 }); 388 return '<h1 ' + attrs + '>' + $(this).text() + '</h1>'; 389 }); 390 391 392 393 if ($("#progressDialog").is('.ui-dialog-content')) { 394 //If displayed in a modal pop-up remove close button 395 setTimeout(function() { 396 $(".ui-dialog-titlebar>button").remove(); 397 }, 2); 398 $(document).on("progressbarcomplete", function(event, ui) { 399 setTimeout(function() { 400 $('#liveText-polite').text('Progress bar has closed'); 401 setTimeout(function() { 402 progressTrigger.attr('aria-hidden', 'false').focus(); 403 }, 2000); 404 }, 1); 405 $(".ui-dialog").remove(); 406 $('.ui-widget-overlay').remove(); 407 }); 408 409 } 410 }, 411 dialogFocus: function() { 412 var title = $('.ui-dialog-title'), 413 dialog = $('.ui-dialog'), 414 progressbar = $('[role="progressbar"]'); 415 //focus on h1 after 100th of a second 416 setTimeout(function() { 417 if (dialog.hasClass('progressBar')) { 418 progressbar.focus(); 419 } else { 420 title.focus(); 421 } 422 /*else if ($('html').is('.lt-ie9, .ie9, .ie10, .ie11')) { 423 //move focus to H1 tag in IE browsers for JAWS users 424 title.focus(); 425 }*/ 426 }, 1); 427 $('.ui-resizable-handle, .ui-progressbar-overlay').attr('aria-hidden', 'true'); 428 }, 429 expandCollapse: function(options) { 430 431 if (options['text'] === true) { 432 433 434 //change icon hc mode text to toggle on click 435 $('.collapsibleBoxActive').on('click', function() { 436 if ($(this).children('a').hasClass('collapsible-heading-collapsed')) { 437 $(this).find('.adobeBlank').text('Collapsed Icon'); 438 } else { 439 $(this).find('.adobeBlank').text('Expanded Icon'); 440 } 441 }); 442 443 //change icon hc mode text to toggle on click 444 $('.collapsible-heading').on('click', function() { 445 if ($(this).hasClass('collapsible-heading-collapsed')) { 446 $(this).find('.adobeBlank').text('Collapsed Icon'); 447 } else { 448 $(this).find('.adobeBlank').text('Expanded Icon'); 449 } 450 }); 451 452 } else { 453 454 455 if ($(".toggleIcon").hasClass("glyphicon-expand")) { 456 $(".toggleIcon").html("<span class='adobeBlank'>Collapsed icon</span>"); 457 } else if ($(".toggleIcon").hasClass("glyphicon-collapse-down")) { 458 $(".toggleIcon").html("<span class='adobeBlank'>Expanded icon</span>"); 459 } 460 461 $('.toggleIcon').keydown(function(event) { 462 if (event.keyCode === 32) { 463 //alert('spacebar'); 464 event.preventDefault(); 465 $(this).click(); 466 } 467 return true; 468 }); 469 470 if (options['expandDefault'] === true) { 471 472 $('.collapsible-heading-toggle-icon').attr('aria-expanded', 'true'); 473 if (!$('.collapsible-heading-toggle-icon').children().hasClass('expand-icon')) { 474 $('.collapsible-heading-toggle-icon').prepend("<em data-collapse-text='collapse' data-expand-text='expand' title='Expanded' class='expand-icon'></em>"); 475 } 476 this.expandIconButton(); 477 } else { 478 $('.collapsible-heading-toggle-icon').attr('aria-expanded', 'false'); 479 if (!$('.collapsible-heading-toggle-icon').children().hasClass('expand-icon')) { 480 $('.collapsible-heading-toggle-icon').prepend("<em data-collapse-text='collapse' data-expand-text='expand' title='Collapsed' class='collapse-icon'></em>"); 481 } 482 this.expandIconButton(); 483 } 484 485 //change icon hc mode text to toggle on click 486 $('.collapsible-heading-toggle-icon').on('click', function() { 487 var icon = $(this).children()[0]; 488 489 if (icon !== typeof undefined && icon !== '') { 490 if ($(icon).hasClass('collapse-icon')) { 491 $(icon).parent().attr('aria-expanded', 'true'); 492 $(icon).attr('title', 'Expanded').attr('class', 'expand-icon').empty(); 493 } else { 494 $(icon).parent().attr('aria-expanded', 'false'); 495 $(icon).attr('title', 'Collapsed').attr('class', 'collapse-icon').empty(); 496 } 497 } 498 499 }); 500 501 $('.collapsible-heading-toggle-icon').keydown(function(event) { 502 if (event.keyCode === 32) { 503 //alert('spacebar'); 504 event.preventDefault(); 505 $(this).click(); 506 } 507 return true; 508 }); 509 510 } 511 //removed button role from collapsible image links on expand/collapse 512 $(".collapsible-heading").removeAttr("role"); 513 }, 514
515 //create buttons from anchor tags to keep semantics and prevent 'visited link' announcements with screen readers 516 expandIconButton: function() { 517 //get anchor tag inside of heading tag with 'collapsibleIcon' class 518 var anchors = $('.collapsibleIcon > a'); 519 //if anchor tag exists change it to a button 520 if (anchors.length !== 0) { 521 var anchorClass = anchors.attr('class'), 522 anchorExpanded = anchors.attr('aria-expanded'); 523 anchors.find('em').attr("style", "font-family :'FontAwesome' !important"); 524 anchors.wrapInner('<button/>'); 525 anchors.children('button').attr({ 526 'class': anchorClass, 527 'aria-expanded': anchorExpanded 528 }).addClass('btn-link').attr('tabindex', '0'); 529 anchors.contents().unwrap(); 530 } 531 }, 532 533 externalWindow: function() { 534 //check if exit text is set otherwise append it. 535 $('a[target="_blank"]:not(.sr-set)').append(exitText).addClass('sr-set'); 536 }, 537 538 externalWindowImage: function() { 539 //check if exit text is set otherwise append it. 540 $('a[target="_blank"]:not(.sr-set)').append(exitTextImage).addClass('sr-set'); 541 }, 542 543 544 externalPolicy: function() { 545 //check if exit text is set otherwise append it. 546 if (!$('a.extlink').next().is('a')) { 547 $('a.extlink').after(policyText); 548 } 549 }, 550 551 //font based icons 508 552 fontIcons: function() { 553 $('.fa').attr("style", "font-family :'FontAwesome' !important"); 554 $('.glyphicon').delay(500).attr("style", "font-family :'Glyphicons Halflings' !important"); 555 $('button[data-validationtrigger]').on('click', function() { 556 $('.fa').attr("style", "font-family :'FontAwesome' !important"); 557 $('.glyphicon').delay(500).attr("style", "font-family :'Glyphicons Halflings' !important"); 558 }); 559 }, 560 561 //Set custom focus 562 focusMethod: function(options) { 563 //Options <delay> <boolean> required, <id> <string> of focuasable element, or <class> <string> of focusable element, or <element> <string> of element name. 564 if (options.length !== 0) { 565 if (options.delay) { 566 //Delay often used to set focus in legacy IE with strict render order 567 if (options.id !== undefined) { 568 setTimeout(function() { 569 $('#' + options.id).focus(); 570 }, 100); 571 } else if (options['class'] !== undefined) { 572 setTimeout(function() { 573 $('.' + options['class']).focus(); 574 }, 100); 575 } else if (options['element'] !== undefined) { 576 setTimeout(function() { 577 $(options['element']).focus(); 578 }, 100); 579 } 580 } else { 581 if (options.id !== undefined) { 582 $('#' + options.id).focus(); 583 } else if (options['class'] !== undefined) { 584 $('.' + options['class']).focus(); 585 } else if (options['element'] !== undefined) { 586 $(options['element']).focus(); 587 } 588 } 589 590 } 591 }, 592 593 //Set custom focus to heading 594 focustoHeading: function() { 595 596 var skipto = $("h1:first"); 597 598 $(document).scrollTop(skipto.offset().top); 599 skipto.attr("tabIndex", "-1"); 600 skipto.focus(); 601 skipto.focusout(function() { 602 $(this).removeAttr("tabindex"); 603 }); 604 }, 605 606 607 // Method to get focused element 608 getFocusedElement: function() { 609 var elem = document.activeElement; 610 return $(elem && (elem.type || elem.href) ? elem : []); 611 }, 612 613 // Method to get parameters from the querystring 614 getQueryStringVal: function(name) { 615 name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); 616 var regexS = "[\\?&]" + name + "=([^&#]*)"; 617 var regex = new RegExp(regexS); 618 var results = regex.exec(window.location.search); 619 if (results === null) 620 return ""; 621 else 622 return decodeURIComponent(results[1].replace(/\+/g, " "));
623 }, 624 625 //Method to pull entire querystring 626 getQueryString: function(name, uri) { 627 if (typeof(uri) != 'string') uri = window.location.href; 628 name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); 629 var regexS = "[\\#?&]" + name + "=([^&#]*)"; 630 var regex = new RegExp(regexS); 631 var results = regex.exec(uri); 632 try { 633 return results[1]; 634 } catch (e) { 635 return "undefined"; 636 } 637 }, 638 639 //Adding aria-level and role for all headings 640 headings: function() { 641 var headings = "h1, h2, h3, h4, h5, h6"; 642 643 $(headings).delay(1000).each(function() { 644 if (!$(this).attr('role')) { 645 var headingLevel = $(this)[0].nodeName.substring(1); 646 $(this).attr({ 647 'role': 'heading', 648 'aria-level': headingLevel 649 }); 650 } 651 }); 652 }, 653 ieDetect: function() { 654 //detect ie10/11 and add corresponding class on the HTML element 655 var html = $('html'), 656 ie10 = (navigator.userAgent.match(/MSIE 10/i)), 657 ie11 = !!navigator.userAgent.match(/Trident.*rv[ :]*11\./); 658 if (ie10 == "MSIE 10") html.addClass('ie10'); 659 if (ie11 == true) html.addClass('ie11'); 660 }, 661 //allow links that appear as buttons to fucntion with the spacebar 662 keyPressLinks: function() { 663 $('a[role=button]').off("keypress").on("keypress", function(e) { 664 if (e.keyCode === 32) { 665 $(this).trigger("click"); 666 e.preventDefault(); 667 } 668 }); 669 }, 670 671 menu: function(el) { 672 //Adding aria-selected for each selected li in menu 673 el.on("menufocus", function(event, ui) { 674 $(".ui-state-focus").attr('aria-selected', 'true'); 675 }); 676 677 el.on("menublur", function(event, ui) { 678 $('.ui-menu a').each(function(index, element) { 679 $(this).removeAttr('aria-selected'); 680 }); 681 }); 682 }, 683 684 progressbar: function() { 685 var progressTrigger = $('.progressTriggerFocus'), 686 titleBar = $('.ui-dialog-titlebar'); 687 688 $(document).on("progressbarcreate", ".ui-progressbar", function(event, ui) { 689 //titleBar.focus(); 690 $(".ui-progressbar").removeClass("ui-corner-all"); 691 progressTrigger.attr('aria-hidden', 'true'); 692 //remove corners class from title bar 693 $(".ui-progressbar-value").removeClass("ui-progressbar-value ui-widget-header ui-corner-left").addClass("ui-progressbar-overlay"); 694 695 //Change dialog container to use role='dialog' to read correctly with screen readers 696 $('.dialog-contents').attr('role', 'dialog'); 697 }); 698 }, 699 700 required: function() { 701 // Add aria-required="true" and aria-described by to form feilds only 702 if ($('span.requiredField').length > 0) { 703 var x = 0; 704 $('span.requiredField').parent().each(function(index, elem) { 705 //add ID to formatting span 706 $(this).siblings(".text-tip").attr('id', 'formatting' + x); 707 708 if ($(this).next().prop('type') === 'text' || $(this).next().prop('type') === 'select-one') { 709 $(this).next().attr('aria-required', 'true'); 710 $(this).next().attr('aria-describedby', 'formatting' + x); 711 } else if ($(this).next().next().prop('type') === 'text' || $(this).next().next().prop('type') === 'select-one') { 712 $(this).next().next().attr('aria-required', 'true'); 713 $(this).next().attr('aria-describedby', 'formatting' + x); 714 } 715 x++; 716 }); 717 } 718 719 }, 720 721 722 723 //tabs 508 724 tabs: function(el) { 725 //all changes in the extend for ui.tabs 726 }, 727 //get title of page on view change and add to live region 728 titlePageChange: function() { 729 var pageTitle = $(document).find("title").text(); 730 $('#liveText').text(pageTitle); 731 732 }, 733 //tooltip 508 734 tooltips: function() { 735 $(".selector").on("tooltipopen", function(event, ui) {}); 736 } 737 738 //end of A11y namespace function 739}; 740 741 742 743/******************************************* 744 Extension Methods for jQuery widgets 745*******************************************/ 746 747//extend jQuery Accordion widget 748$.widget('ui.accordion', $.ui.accordion, { 749 _create: function() { 750 if (debugON) console.log('Custom Accordion Widget'); 751 A11y.accordion(this.element); 752 return this._super(); 753 } 754}); 755 756 757//extend the autocomplete widget 758$.widget("ui.autocomplete", $.ui.autocomplete, { 759 _renderItem: function(ul, item) { 760 var term = this.element.val(), 761 html = item.label; 762 return $("<li></li>") 763 .append($("<a></a>").html(html)) 764 .appendTo(ul); 765 }, 766 //508 default instantioantion methods 767 delay: 600, 768 autoFocus: true, 769 mutliple: false, 770 _create: function(event, ui) { 771 //call 508 helper method 772 if (debugON) console.log('Custom Autocomplete Widget'); 773 A11y.autocomplete(); 774 return this._super(); 775 } 776}); 777 778 779//extend the jQuery button widget 780$.widget("A11y.button", $.ui.button, { 781 _create: function() { 782 if (debugON) console.log('Custom Button Widget'); 783 this.element.attr('aria-pressed', 'false') 784 .click(function(event) { 785 if (event.target !== undefined) { 786 if ($(event.target).is("span")) 787 //mark parent link or input if using span inside button 788 $(event.target).parent().attr('aria-pressed', 'true'); 789 else 790 $(event.target).attr('aria-pressed', 'true'); 791 } 792 }); 793 return this._super(); 794 } 795}); 796 797//extend the jQuery dialog widget 798$.widget("ui.dialog", $.ui.dialog, { 799 //default 508 options 800 autoOpen: false, 801 resizable: false, 802 draggable: false, 803 width: 'auto', 804 height: 'auto', 805 modal: true, 806 _title: function(title) { 807 A11y.dialog(); 808 return this._super(title) 809 }, 810 _createOverlay: function() { 811 //this loads when dialog is opened 812 var bodyTag = $('body > *'); 813 A11y.dialogOpen();
814 /* add focus to h1 tag after delay to allow complete dialog to set up and add aria hidden 815 to each direct descendent of the body tag to prevent screen reader from reading content 816 */ 817 this._delay(function() { 818 A11y.dialogFocus(); 819 bodyTag.attr('aria-hidden', 'true'); 820 this.uiDialog.removeAttr('aria-hidden'); 821 }); 822 return this._super(); 823 }, 824 _createWrapper: function() { 825 //remove aria-describedby from dialog 826 this._delay(function() { 827 var lowerButtonContainer = this.uiDialog.children('.ui-dialog-buttonpane'), 828 titleH1 = this.uiDialog.find('.ui-dialog-title').attr('id'), 829 dialogContents = this.uiDialog.find('.dialog-contents'), 830 innerContents = this.uiDialog.find('.ui-dialog-content'), 831 lowerButtonContainerButton = lowerButtonContainer.find('button'), 832 headingClosingButton = dialogContents.find('.ui-dialog-titlebar button'); 833 834 dialogContents.attr('id', titleH1 + '-contents'); 835 lowerButtonContainerButton.removeAttr('aria-pressed'); 836 headingClosingButton.removeAttr('aria-pressed aria-disabled title').find('.ui-icon-closethick').remove(); 837 var describedById = dialogContents.attr('id'); 838 //this.uiDialog.removeAttr('aria-describedby'); 839 //adding label and hiding aria-hidden to text for screen readers to ignore 840 $(lowerButtonContainerButton).each(function() { 841 var button = $(this), 842 lowerButtonContainerButtonLabel = button.children('.ui-button-text').text().toLowerCase(); 843 button.removeAttr('aria-pressed').attr('aria-label', lowerButtonContainerButtonLabel).find('.ui-button-text').attr('aria-hidden', 'true'); 844 845 }); 846 this.uiDialog.attr('aria-describedby', describedById); 847 if (lowerButtonContainer.length) { 848 lowerButtonContainer.find('button').removeAttr('aria-disabled'); 849 lowerButtonContainer.detach().appendTo('div[role="document"]'); 850 dialogContents.prepend("<p class='sr-only ui-dialog-hint'>Start of Dialog</p>").append("<p class='sr-only ui-dialog-hint'>End of Dialog</p>"); 851 } 852 853 }); 854 855 return this._super(); 856 }, 857 858 _destroyOverlay: function() { 859 //unhide page content for screen readers and hide dialog when closed 860 var bodyTag = $('body > *'); 861 bodyTag.removeAttr('aria-hidden'); 862 this.uiDialog.attr('aria-hidden', 'true'); 863 864 return this._super(); 865 } 866}); 867 868 869//extend the jQuery menu widget 870$.widget("ui.menu", $.ui.menu, { 871 _create: function() { 872 if (debugON) console.log('Custom Menu Widget'); 873 A11y.menu(this.element); 874 return this._super(); 875 } 876}); 877 878//extend the jQuery progressbar widget 879$.widget("ui.progressbar", $.ui.progressbar, { 880 _create: function() { 881 if (debugON) console.log('Custom Progressbar Widget'); 882 A11y.progressbar(); 883 return this._super(); 884 }, 885 _refreshValue: function(value) { 886 //adding live region update for safari only 887 var is_chrome = navigator.userAgent.indexOf('Chrome') > -1, 888 is_safari = navigator.userAgent.indexOf("Safari") > -1, 889 progressbarCurValue = $('.ProgressBarContainer').attr('aria-valuenow'), 890 progressbarLiveRegion = $('#progressbarText'); 891 if ((is_chrome) && (is_safari)) { 892 is_safari = false; 893 } 894 if (is_safari) { 895 progressbarLiveRegion.text(progressbarCurValue + "%"); 896 }; 897 if (value === this.options.max) { 898 this._trigger("Progress bar has closed"); 899 } 900 return this._super(); 901 } 902}); 903 904//extend the button function 905$.widget("ui.slider", $.ui.slider, { 906 _refreshValue: function() { 907 var val = this.element.slider("value"), 908 handle = this.element.children('.ui-slider-handle'), 909 option = this.options, 910 currentSliderValue = option.value, 911 minSliderValue = option.min, 912 maxSliderValue = option.max, 913 ariaSliderLabel = option.ariaLabel, 914 ariaSliderValueText = (option.slideTextValue) ? val + option.slideTextValue : val, 915 ariaOrientationValue = (option.ariaOrientation) ? option.ariaOrientation : ""; 916 handle.attr({ 917 'aria-valuenow': val, 918 'aria-valuetext': ariaSliderValueText, 919 'role': 'slider', 920 'aria-orientation': ariaOrientationValue, 921 'aria-valuemin': minSliderValue, 922 'aria-valuemax': maxSliderValue, 923 'aria-label': ariaSliderLabel 924 }); 925 return this._super(); 926 } 927}); 928 929//extend the spinner function 930$.widget("ui.spinner", $.ui.spinner, { 931 _create: function() { 932 if (debugON) console.log('Custom Spinner Widget'); 933 //By default the spinner widget is already compliant use this method if it needs future implementatations 934 return this._super(); 935 } 936}); 937 938//extend the tabs function ++33 939$.widget("ui.tabs", $.ui.tabs, { 940 _create: function(event, ui) { 941 if (debugON) console.log('Custom Tabs Widget'); 942 //applying the live regiions for page load because the A11y.Core function is not called at time of execution of the tabs widget 943 $('body').prepend('<div id="liveText" class="sr-only" aria-l
943ive="assertive"></div>'); 944 $('body').prepend('<div id="liveText-polite" class="sr-only" aria-live="polite"></div>'); 945 return this._super(); 946 }, 947 _refresh: function() { 948 949 //remove specific classes on tabs widget on page load 950 var tabContainer = this.element; 951 tabContainer.removeClass('ui-widget ui-widget-content ui-corner-all'); 952 //get the text of the tab that is active on page load 953 if (this.active.length) { 954 var newTabText = $.trim(this.active[0].textContent); 955 //alert sr via polite live region of tab change 956 $('#liveText-polite').text(newTabText + ' tab is selected'); 957 setTimeout(function() { 958 $('#liveText-polite').text('') 959 }, 1000) 960 } else {} 961 return this._super(); 962 }, 963 // handles show/hide for selecting tabs 964 _toggle: function(event, eventData) { 965 //get text of activated tab 966 var newTabText = $.trim(eventData.newTab[0].textContent); 967 //alert sr via polite live region of tab change 968 $('#liveText-polite').text(newTabText + ' tab is selected'); 969 setTimeout(function() { 970 $('#liveText-polite').text('') 971 }, 1000) 972 return this._super(event, eventData); 973 } 974}); 975 976//extend jQuery Tooltip widget to separate JQuery UI tooltip from Bootstrap's tooltip 977$.widget('A11y.tooltip', $.ui.tooltip, { 978 _create: function() { 979 return this._super(); 980 } 981}); 982 983 984//extends fillament Group expand widget 985$.fn.A11ycollapsible = function(options) { 986 //dependency on lang attribute being set on html tag 987 if (options === null || options === undefined) { 988 //default 508 options 989 options = { 990 'text': true, 991 'icon': false, 992 'closeAll': false 993 }; 994 } 995 996 //check if collapsible dependency is loaded. 997 if (typeof $.fn.collapsible === 'function') { 998 if (debugON) console.log('Custom collapsible Widget'); 999 $.fn.collapsible.call(this, options); 1000 A11y.expandCollapse(options); 1001 } else { 1002 if (debugON) console.log('Missing jQuery Collapsible library'); 1003 } 1004}; 1005 1006$.fn.A11ycustomInput = function() { 1007 if (typeof $.fn.carousel === 'function') { 1008 $.fn.customInput.call(this); 1009 A11y.customInput(); 1010 } 1011 1012}; 1013 1014 1015 1016//extends whatsock acciesability controls date widget 1017$.fn.A11yblockUI = function() { 1018 //check if calendar dependency is loaded. 1019 if (typeof $.fn.block === 'function') { 1020 if (debugON) console.log('Custom Block UI Start'); 1021 $.blockUI(); 1022 A11y.block($(this), true); 1023 1024 } else { 1025 if (debugON) console.log('Missing Jquery Block UI'); 1026 } 1027}; 1028 1029 1030//extends whatsock acciesability controls date widget 1031$.fn.A11yUnblockUI = function() { 1032 //check if calendar dependency is loaded. 1033 if (typeof $.fn.unblock === 'function') { 1034 if (debugON) console.log('Custom Block UI Complete'); 1035 $.unblockUI(); 1036 A11y.block($(this), false); 1037 1038 } else { 1039 if (debugON) console.log('Missing Jquery Block UI'); 1040 } 1041}; 1042 1043/* jquery ui datepicker extends */ 1044$.datepicker._showDatepicker = function(input) { 1045 input = input.target || input; 1046 if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger 1047 input = $("input", input.parentNode)[0]; 1048 } 1049 1050 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here 1051 return; 1052 } 1053 1054 var inst, beforeShow, beforeShowSettings, isFixed, 1055 offset, showAnim, duration; 1056 1057 inst = $.datepicker._getInst(input); 1058 if ($.datepicker._curInst && $.datepicker._curInst !== inst) { 1059 $.datepicker._curInst.dpDiv.stop(true, true); 1060 if (inst && $.datepicker._datepickerShowing) { 1061 $.datepicker._hideDatepicker($.datepicker._curInst.input[0]); 1062 } 1063 } 1064 1065 beforeShow = $.datepicker._get(inst, "beforeShow"); 1066 beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {}; 1067 if (beforeShowSettings === false) { 1068 return; 1069 } 1070 extendRemove(inst.settings, beforeShowSettings); 1071 1072 inst.lastVal = null; 1073 $.datepicker._lastInput = input; 1074 $.datepicker._setDateFromField(inst); 1075 1076 if ($.datepicker._inDialog) { // hide cursor 1077 input.value = ""; 1078 } 1079 if (!$.datepicker._pos) { // position below input 1080 $.datepicker._pos = $.datepicker._findPos(input); 1081 $.datepicker._pos[1] += input.offsetHeight; // add the height 1082 } 1083 1084 isFixed = false; 1085 $(input).parents().each(function() { 1086 isFixed |= $(this).css("position") === "fixed"; 1087 return !isFixed; 1088 });
1089 1090 offset = { 1091 left: $.datepicker._pos[0], 1092 top: $.datepicker._pos[1] 1093 }; 1094 $.datepicker._pos = null; 1095 //to avoid flashes on Firefox 1096 inst.dpDiv.empty(); 1097 // determine sizing offscreen 1098 inst.dpDiv.css({ 1099 position: "absolute", 1100 display: "block", 1101 top: "-1000px" 1102 }); 1103 $.datepicker._updateDatepicker(inst); 1104 // fix width for dynamic number of date pickers 1105 // and adjust position before showing 1106 offset = $.datepicker._checkOffset(inst, offset, isFixed); 1107 inst.dpDiv.css({ 1108 position: ($.datepicker._inDialog && $.blockUI ? 1109 "static" : (isFixed ? "fixed" : "absolute")), 1110 display: "none", 1111 left: offset.left + "px", 1112 top: offset.top + "px" 1113 }).attr("tabindex", "-1"); 1114 1115 if (!inst.inline) { 1116 showAnim = $.datepicker._get(inst, "showAnim"); 1117 duration = $.datepicker._get(inst, "duration"); 1118 inst.dpDiv.zIndex($(input).zIndex() + 1); 1119 $.datepicker._datepickerShowing = true; 1120 1121 if ($.effects && $.effects.effect[showAnim]) { 1122 inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration); 1123 } else { 1124 inst.dpDiv[showAnim || "show"](showAnim ? duration : null); 1125 } 1126 1127 $('#liveText-polite').text('Datepicker has opened'); 1128 1129 inst.dpDiv.focus().off('keydown').on('keydown', function(event) { 1130 $.datepicker._doKeyDown(event, input); 1131 }); 1132 1133 if ($.datepicker._shouldFocusInput(inst)) { 1134 //inst.input.focus(); 1135 } 1136 1137 $.datepicker._curInst = inst; 1138 } 1139} 1140 1141$.datepicker._doKeyDown = function(event, input) { 1142 var onSelect, dateStr, sel, 1143 inst = (input !== undefined) ? $.datepicker._getInst(input) : $.datepicker._getInst(event.target), 1144 handled = true, 1145 isRTL = inst.dpDiv.is(".ui-datepicker-rtl"); 1146 1147 inst._keyEvent = true; 1148 1149 if ($.datepicker._datepickerShowing) { 1150 switch (event.keyCode) { 1151 case 9: 1152 handled = true; 1153 break; // hide on tab out 1154 case 13: 1155 sel = $("td." + $.datepicker._dayOverClass + ":not(." + 1156 $.datepicker._currentClass + ")", inst.dpDiv); 1157 if (sel[0]) { 1158 $.datepicker._selectDay(inst.input[0], inst.selectedMonth, inst.selectedYear, sel[0]); 1159 } 1160 1161 onSelect = $.datepicker._get(inst, "onSelect"); 1162 if (onSelect) { 1163 dateStr = $.datepicker._formatDate(inst); 1164 1165 // trigger custom callback 1166 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); 1167 } else { 1168 $.datepicker._hideDatepicker(); 1169 inst.input.focus(); 1170 } 1171 1172 return false; // don't submit the form 1173 case 27: 1174 $.datepicker._hideDatepicker(); 1175 inst.input.focus(); 1176 break; // hide on escape 1177 case 33: 1178 $.datepicker._adjustDate(inst.input[0], (event.altKey ? 1179 -$.datepicker._get(inst, "stepBigMonths") : 1180 -$.datepicker._get(inst, "stepMonths")), "M"); 1181 break; // previous month/year on page up/+ alt 1182 case 34: 1183 $.datepicker._adjustDate(inst.input[0], (event.altKey ? 1184 +$.datepicker._get(inst, "stepBigMonths") : 1185 +$.datepicker._get(inst, "stepMonths")), "M"); 1186 break; // next month/year on page down/+ alt 1187 case 35: 1188 $.datepicker._adjustDate(inst.input[0], (isRTL ? -($.datepicker._getDaysInMonth(inst.selectedYear, inst.selectedMonth) - inst.selectedDay) : +($.datepicker._getDaysInMonth(inst.selectedYear, inst.selectedMonth) - inst.selectedDay)), "D"); 1189 handled = event.ctrlKey || event.metaKey; 1190 break; // clear on alt or command +end 1191 case 36: 1192 $.datepicker._adjustDate(inst.input[0], (isRTL ? +(inst.selectedDay - 1) : -(inst.selectedDay - 1)), "D"); 1193 handled = event.ctrlKey || event.metaKey; 1194 break; // current on alt or command +home 1195 case 37: 1196 $.datepicker._adjustDate(inst.input[0], (isRTL ? +1 : -1), "D"); 1197 handled = event.ctrlKey || event.metaKey; 1198 // -1 day on ctrl or command +left 1199 break; 1200 case 38: 1201 $.datepicker._adjustDate(inst.input[0], -7, "D"); 1202 handled = true; 1203 break; // -1 week on ctrl or command +up 1204 case 39: 1205 $.datepicker._adjustDate(inst.input[0], (isRTL ? -1 : +1), "D"); 1206 handled = event.ctrlKey || event.metaKey; 1207 // +1 day on ctrl or command +right 1208 break; 1209 case 40: 1210 $.datepicker._adjustDate(inst.input[0], +7, "D"); 1211 handled = true; 1212 break; // +1 week on ctrl or command +down 1213 default: 1214 handled = false; 1215 } 1216 } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home 1217 $.datepicker._showDatepicker(this); 1218 } else { 1219 handled = false; 1220 } 1221 1222 if (handled) { 1223 event.preventDefault(); 1224 event.stopPropagation(); 1225 } 1226} 1227 1228$.datepicker._shouldFocusInput = function(inst) { 1229 return false; 1230} 1231 1232$.datepicker._hideDatepicker = function(input) { 1233 var showAnim, duration, postProcess, onClose, 1234 inst = this._curInst; 1235 1236 if (!inst || (input && inst !== $.data(input, PROP_NAME))) { 1237 return; 1238 } 1239 1240 if (this._datepickerShowing) { 1241 showAnim = this._get(inst, "showAnim"); 1242 duration = this._get(inst, "duration"); 1243 postProcess = function() { 1244 $.datepicker._tidyDialog(inst); 1245 }; 1246 1247 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed 1248 if ($.effects && ($.effects.effect[showAnim] || $.effects[showAnim])) { 1249 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess); 1250 } else { 1251 inst.dpDiv[(showAnim === "slideDown" ? "slideUp" : 1252 (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess); 1253 } 1254 1255 if (!showAnim) { 1256 postProcess(); 1257 } 1258 this._datepickerShowing = false; 1259 1260 onClose = this._get(inst, "onClose"); 1261 if (onClose) { 1262 onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]); 1263 } 1264 1265 inst.trigger.focus(); 1266 1267 this._lastInput = null; 1268 if (this._inDialog) { 1269 this._dialogInput.css({ 1270 position: "absolute",
1271 left: "0", 1272 top: "-100px" 1273 }); 1274 if ($.blockUI) { 1275 $.unblockUI(); 1276 $("body").append(this.dpDiv); 1277 } 1278 } 1279 this._inDialog = false; 1280 } 1281} 1282 1283$.datepicker._attachments = function(input, inst) { 1284 var showOn, buttonText, buttonImage, buttonClass, 1285 appendText = this._get(inst, "appendText"), 1286 isRTL = this._get(inst, "isRTL"); 1287 1288 if (inst.append) { 1289 inst.append.remove(); 1290 } 1291 if (appendText) { 1292 inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>"); 1293 input[isRTL ? "before" : "after"](inst.append); 1294 } 1295 1296 input.unbind("focus", this._showDatepicker); 1297 1298 if (inst.trigger) { 1299 inst.trigger.remove(); 1300 } 1301 1302 showOn = this._get(inst, "showOn"); 1303 if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field 1304 input.focus(this._showDatepicker); 1305 } 1306 if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked 1307 buttonText = this._get(inst, "buttonText"); 1308 buttonImage = this._get(inst, "buttonImage"); 1309 buttonClass = this._get(inst, "buttonClass"); 1310 inst.trigger = $(this._get(inst, "buttonImageOnly") ? 1311 $("<img/>").addClass(this._triggerClass).attr({ 1312 src: buttonImage, 1313 alt: buttonText, 1314 title: buttonText 1315 }) : 1316 $('<span class="input-group-btn"></span>').html( 1317 $('<button type="button" class="btn btn-default"></button>').addClass(this._triggerClass).html(function() { 1318 if (!buttonImage && !buttonClass) { 1319 return buttonText; 1320 } else if (!buttonClass) { 1321 return $("<img/>").attr({ 1322 src: buttonImage, 1323 alt: buttonText, 1324 title: buttonText 1325 }); 1326 } else { 1327 return $("<span/>").html('<span class="' + buttonClass + '"><span class="adobeBlank">Calendar icon</span></span><span class="sr-only">' + buttonText + '</span>'); 1328 } 1329 }) 1330 )); 1331 1332 input[isRTL ? "before" : "after"](inst.trigger); 1333 inst.trigger.click(function() { 1334 if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) { 1335 $.datepicker._hideDatepicker(); 1336 input.focus(); 1337 } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) { 1338 $.datepicker._hideDatepicker(); 1339 $.datepicker._showDatepicker(input[0]); 1340 } else { 1341 $.datepicker._showDatepicker(input[0]); 1342 } 1343 return false; 1344 }); 1345 } 1346} 1347 1348/* jQuery extend now ignores nulls! */ 1349function extendRemove(target, props) { 1350 $.extend(target, props); 1351 for (var name in props) { 1352 if (props[name] == null) { 1353 target[name] = props[name]; 1354 } 1355 } 1356 return target; 1357 } 1358 /* end of jquery ui datepicker extends */
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.