1/*! 2 * Patched Pojo Accessibility app (based on pojo-accessibility v2.1.0 legacy app). 3 * Changes: 4 * - Converts toolbar <a href="#"> controls to <button type="button"> before binding 5 * - Uses class selectors (not a.pojo-a11y-toolbar-link) so buttons stay wired 6 * - Hides decorative icon SVG titles so accessible names are not duplicated 7 * - Sets aria-expanded on the toolbar toggle 8 * - Skips forcing role="link" onto toolbar controls 9 */ 10(function () { 11 var isWebkit = navigator.userAgent.toLowerCase().indexOf('webkit') > -1; 12 var isOpera = navigator.userAgent.toLowerCase().indexOf('opera') > -1; 13 var isIe = navigator.userAgent.toLowerCase().indexOf('msie') > -1; 14 15 if ((isWebkit || isOpera || isIe) && document.getElementById && window.addEventListener) { 16 window.addEventListener('hashchange', function () { 17 var element, id = location.hash.substring(1); 18 if (/^[A-z0-9_-]+$/.test(id) && (element = document.getElementById(id))) { 19 if (!/^(?:a|select|input|button|textarea)$/i.test(element.tagName)) { 20 element.tabIndex = -1; 21 } 22 element.focus(); 23 } 24 }, false); 25 } 26})(); 27 28(function ($, window, document) { 29 'use strict'; 30 31 var App = { 32 cache: { 33 $document: $(document), 34 $window: $(window) 35 }, 36 37 settings: { 38 minFontSize: 120, 39 maxFontSize: 200, 40 buttonsClassPrefix: 'pojo-a11y-btn-', 41 bodyClassPrefix: 'pojo-a11y-', 42 bodyFontClassPrefix: 'pojo-a11y-resize-font-', 43 storageKey: 'pojo-a11y', 44 expires: (window.PojoA11yOptions && PojoA11yOptions.save_expiration) 45 ? 3600000 * PojoA11yOptions.save_expiration 46 : 43200000 47 }, 48 49 variables: { 50 currentFontSize: 120, 51 currentSchema: null 52 }, 53 54 activeActions: {}, 55 56 normalizeToolbarControls: function () { 57 var $toolbar = this.cache.$toolbar; 58 59 $toolbar.find('a.pojo-a11y-toolbar-link').each(function () { 60 var $link = $(this); 61 var attrs = {}; 62 var labelText; 63 var $button; 64 65 $.each(this.attributes, function () { 66 if (this.name === 'href' || this.name === 'role') { 67 return; 68 } 69 attrs[this.name] = this.value; 70 }); 71 72 $button = $('<button type="button"></button>') 73 .attr(attrs) 74 .html($link.html()); 75 76 // Decorative icon + SVG <title> duplicate the visible label. 77 $button.find('.pojo-a11y-toolbar-icon').attr('aria-hidden', 'true'); 78 $button.find('svg title').remove(); 79 80 if ($button.hasClass('pojo-a11y-toolbar-toggle-link')) { 81 labelText = $button.attr('title') || 'Accessibility Tools'; 82 $button.attr('aria-label', labelText); 83 $button.attr('aria-expanded', 'false'); 84 $button.find('.pojo-sr-only, .sr-only').remove(); 85 } 86 87 $link.replaceWith($button); 88 }); 89 }, 90 91 cacheElements: function () { 92 this.cache.$toolbar = $('#pojo-a11y-toolbar'); 93 this.normalizeToolbarControls(); 94 95 this.cache.$toolbarLinks = this.cache.$toolbar.find('.pojo-a11y-toolbar-link'); 96 this.cache.$toolbarToolsLinks = this.cache.$toolbar.find('.pojo-a11y-tools .pojo-a11y-toolbar-link'); 97 this.cache.$btnToolbarToggle = this.cache.$toolbar.find('div.pojo-a11y-toolbar-toggle > .pojo-a11y-toolbar-link'); 98 this.cache.$skipToContent = $('#pojo-a11y-skip-content'); 99 this.cache.$body = $('body'); 100 }, 101 102 buildElements: function () { 103 this.cache.$body.prepend(this.cache.$toolbar); 104 this.cache.$body.prepend(this.cache.$skipToContent); 105 }, 106 107 bindEvents: function () { 108 var self = this; 109 110 self.cache.$btnToolbarToggle.on('click', function (event) { 111 event.preventDefault(); 112 self.cache.$toolbar.toggleClass('pojo-a11y-toolbar-open'); 113 114 var isOpen = self.cache.$toolbar.hasClass('pojo-a11y-toolbar-open'); 115 self.cache.$btnToolbarToggle.attr('aria-expanded', isOpen ? 'true' : 'false'); 116 117 if (isOpen) { 118 self.cache.$toolbarLinks.attr('tabindex', '0'); 119 } else { 120 self.cache.$toolbarToolsLinks.attr('tabindex', '-1'); 121 self.cache.$btnToolbarToggle.attr('tabindex', '0'); 122 } 123 }); 124 125 $(document).on('keyup', function (event) { 126 if (event.which === 9 && self.cache.$btnToolbarToggle.is(':focus')) { 127 self.cache.$toolbar.addClass('pojo-a11y-toolbar-open'); 128 self.cache.$btnToolbarToggle.attr('aria-expanded', 'true'); 129 self.cache.$toolbarLinks.attr('tabindex', '0'); 130 } 131 }); 132 133 self.bindToolbarButtons(); 134 }, 135 136 bindToolbarButtons: function () { 137 var self = this; 138 139 self.cache.$toolbarToolsLinks.on('click', function (event) { 140 event.preventDefault(); 141 142 var $this = $(this); 143 var action = $this.data('action'); 144 var actionGroup = $this.data('action-group'); 145 var isActive = false; 146 147 if (action !== 'reset') { 148 if (['toggle', 'schema'].indexOf(actionGroup) !== -1) { 149 isActive = $this.hasClass('active'); 150 } 151 self.activateButton(action, isActive); 152 } else { 153 self.reset(); 154 } 155 }); 156 }, 157 158 activateButton: function (action, isDisable) { 159 var actionGroup = this.getButtonByAction(action).data('action-group'); 160 this.activeActions[action] = !isDisable; 161 this.actions[actionGroup].call(this, action, isDisable); 162 this.saveToLocalStorage(); 163 }, 164 165 getActiveButtons: function () { 166 return this.cache.$toolbarToolsLinks.filter('.active'); 167 }, 168 169 getButtonByAction: function (action) { 170 return this.cache.$toolbarToolsLinks.filter('.' + this.settings.buttonsClassPrefix + action); 171 }, 172 173 actions: { 174 toggle: function (action, isDisable) { 175 var $button = this.getButtonByAction(action); 176 var fn = isDisable ? 'removeClass' : 'addClass'; 177 178 if (isDisable) { 179 $button.removeClass('active'); 180 } else { 181 $button.addClass('active'); 182 } 183 184 this.cache.$body[fn](this.settings.bodyClassPrefix + action); 185 }, 186 187 resize: function (action, isDisable) { 188 var currentSize = this.variables.currentFontSize; 189 190 if (action === 'resize-plus' && this.settings.maxFontSize > currentSize) { 191 this.variables.currentFontSize += 10; 192 } 193 194 if (action === 'resize-minus' && this.settings.minFontSize < currentSize) { 195 this.variables.currentFontSize -= 10; 196 } 197 198 if (isDisable) { 199 this.variables.currentFontSize = this.settings.minFontSize; 200 } 201 202 this.cache.$body.removeClass(this.settings.bodyFontClassPrefix + currentSize); 203 204 var isPlusActive = this.variables.currentFontSize > 120; 205 var fn = isPlusActive ? 'addClass' : 'removeClass'; 206 207 this.getButtonByAction('resize-plus')[fn]('active'); 208 209 if (isPlusActive) { 210 this.cache.$body.addClass(this.settings.bodyFontClassPrefix + this.variables.currentFontSize); 211 } 212 213 this.activeActions['resize-minus'] = false; 214 this.activeActions['resize-plus'] = isPlusActive; 215 this.cache.$window.trigger('resize'); 216 }, 217 218 schema: function (action, isDisable) { 219 var currentSchema = this.variables.currentSchema; 220 221 if (currentSchema) { 222 this.cache.$body.removeClass(this.settings.bodyClassPrefix + currentSchema); 223 this.getButtonByAction(currentSchema).removeClass('active'); 224 this.activeActions[currentSchema] = false; 225 this.saveToLocalStorage(); 226 } 227 228 if (isDisable) { 229 this.variables.currentSchema = null; 230 } else { 231 currentSchema = this.variables.currentSchema = action; 232 this.cache.$body.addClass(this.settings.bodyClassPrefix + currentSchema); 233 this.getButtonByAction(currentSchema).addClass('active'); 234 } 235 } 236 }, 237 238 reset: function () { 239 for (var action in this.activeActions) { 240 if (this.activeActions.hasOwnProperty(action) && this.activeActions[action]) { 241 this.activateButton(action, true); 242 } 243 } 244 localStorage.removeItem(this.settings.storageKey); 245 }, 246 247 saveToLocalStorage: function () { 248 if (!window.PojoA11yOptions || PojoA11yOptions.enable_save !== '1') { 249 return; 250 } 251 252 if (!this.variables.expires) { 253 this.variables.expires = (new Date()).getTime() + this.settings.expires; 254 } 255 256 var data = { 257 actions: this.activeActions, 258 variables: { 259 currentFontSize: this.variables.currentFontSize, 260 expires: this.variables.expires 261 } 262 }; 263 264 localStorage.setItem(this.settings.storageKey, JSON.stringify(data)); 265 }, 266 267 setFromLocalStorage: function () { 268 if (!window.PojoA11yOptions || PojoA11yOptions.enable_save !== '1') { 269 return; 270 } 271 272 var stored = JSON.parse(localStorage.getItem(this.settings.storageKey)); 273 if (!stored) { 274 return; 275 } 276 277 var now = new Date(); 278 if (stored.variables.expires < now) { 279 localStorage.removeItem(this.settings.storageKey); 280 return; 281 } 282 283 var actions = stored.actions; 284 285 if (stored.variables.currentFontSize > 120) { 286 stored.variables.currentFontSize -= 10; 287 } 288 289 $.extend(this.variables, stored.variables); 290 291 for (var action in actions) { 292 if (actions.hasOwnProperty(action) && actions[action]) { 293 this.activateButton(action, false); 294 } 295 } 296 }, 297 298 handleGlobalOptions: function () { 299 if (!window.PojoA11yOptions) { 300 return; 301 } 302 303 if (PojoA11yOptions.focusable === '1') { 304 this.cache.$body.addClass('pojo-a11y-focusable'); 305 } 306 307 if (PojoA11yOptions.remove_link_target === '1') { 308 $('a[target="_blank"]').attr('target', ''); 309 } 310
311 // Do not force role="link" sitewide; it fights correct button semantics. 312 }, 313 314 init: function () { 315 if (!$('#pojo-a11y-toolbar').length) { 316 return; 317 } 318 this.cacheElements(); 319 this.buildElements(); 320 this.bindEvents(); 321 this.handleGlobalOptions(); 322 } 323 }; 324 325 $(document).ready(function () { 326 App.init(); 327 App.setFromLocalStorage(); 328 }); 329})(jQuery, window, document);
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.