1/* 2 * selectize-plugin-a11y 3 * https://github.com/SalmenBejaoui/selectize-plugin-a11y 4 * 5 * Copyright 2018-present Salmen Bejaoui 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in all 15 * copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 */ 25/* global Selectize */ 26Selectize.define("selectize-plugin-a11y", function (options) { 27 var self = this; 28 var KEY_RETURN = 13; 29 30 if (typeof self.accessibility === "undefined") { 31 self.accessibility = {}; 32 } 33 34 self.accessibility.helpers = { 35 randomId: function (len) { 36 var str = "", 37 strLength = len || 10, 38 base = "abcdefghijklmnopqrstuvwxyz0123456789", 39 baseLength = base.length; 40 41 for (var i = 0; i < strLength; i++) { 42 str += base[Math.floor(baseLength * Math.random())]; 43 } 44 45 return str; 46 } 47 }; 48 49 self.accessibility.liveRegion = { 50 $region: "", 51 speak: function (msg) { 52 var $container = $("<div></div>"); 53 $container.text(msg); 54 this.$region.html($container); 55 }, 56 domListener: function () { 57 var observer = new MutationObserver(function (mutations) { 58 mutations.forEach(function (mutation) { 59 var $target = $(mutation.target); 60 if ($target.hasClass("items")) { 61 if ($target.hasClass("dropdown-active")) { 62 // open 63 self.$control_input.attr("aria-expanded", "true"); 64 } else { 65 // close 66 self.$control_input.attr("aria-expanded", "false"); 67 self.$control_input.removeAttr("aria-activedescendant"); 68 } 69 } else { 70 // option change 71 if ($target.hasClass("active")) { 72 if (!!$target.attr("data-value")) { // eslint-disable-line no-extra-boolean-cast 73 self.$control_input.attr( 74 "aria-activedescendant", 75 $target.attr("id") 76 ); 77 self.accessibility.liveRegion.speak($target.text(), 500); 78 } 79 } 80 } 81 }); 82 }); 83 observer.observe(self.$dropdown[0], { 84 attributes: true, 85 attributeFilter: ["class"], 86 subtree: true, 87 attributeOldValue: true 88 }); 89 90 observer.observe(self.$control[0], { 91 attributes: true, 92 attributeFilter: ["class"] 93 }); 94 95 observer.observe(self.$control_input[0], { 96 attributes: true, 97 attributeFilter: ["value"] 98 }); 99 }, 100 setAttributes: function () { 101 this.$region.attr({ 102 "aria-live": "assertive", 103 role: "log", 104 "aria-relevant": "additions", 105 "aria-atomic": "true" 106 }); 107 }, 108 setStyles: function () { 109 this.$region.css({ 110 position: "absolute", 111 width: "1px", 112 height: "1px", 113 "margin-top": "-1px", 114 clip: "rect(1px, 1px, 1px, 1px)", 115 overflow: "hidden" 116 }); 117 }, 118 init: function () { 119 this.$region = $("<div>"); 120 this.setAttributes(); 121 this.setStyles(); 122 $("body").append(this.$region); 123 this.domListener(); 124 } 125 }; 126 127 this.setup = (function () { 128 var original = self.setup; 129 return function () { 130 original.apply(this, arguments); 131 var inputId = self.accessibility.helpers.randomId(), 132 listboxId = self.accessibility.helpers.randomId(); 133
134 self.$control.on("keydown", function (e) { 135 if (e.keyCode === KEY_RETURN) { 136 $(this).click(); 137 } 138 }); 139 140 self.$control_input.attr({ 141 role: "combobox", 142 "aria-expanded": "false", 143 haspopup: "listbox", 144 "aria-owns": listboxId, 145 "aria-label": self.$wrapper 146 .closest("[data-accessibility-selectize-label]") 147 .attr("data-accessibility-selectize-label") 148 }); 149 150 self.$dropdown_content.attr({ 151 role: "listbox", 152 id: listboxId 153 }); 154 self.accessibility.liveRegion.init(); 155 }; 156 })(); 157 158 this.destroy = (function () { 159 var original = self.destroy; 160 return function () { 161 self.accessibility.liveRegion.$region.remove(); 162 return original.apply(this, arguments); 163 }; 164 })(); 165});
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.