PageSourceSearch

https://ama-csail.github.io/vendor/globalassets/scripts/assets.core.js

js ama-csail.github.io collected 2026-10-03 08:36:45 UTC 54,801 bytes, 1,358 lines download raw bytes

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.