Last active
July 25, 2019 16:04
-
-
Save brettz9/4212217 to your computer and use it in GitHub Desktop.
selectedOptions shim (multiple select) with IE8 support
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Polyfill for "fixing" IE's lack of support (IE < 9) for applying slice | |
* on host objects like NamedNodeMap, NodeList, and HTMLCollection | |
* (technically, since host objects are implementation-dependent, | |
* IE doesn't need to work this way). Also works on strings, | |
* fixes IE to allow an explicit undefined for the 2nd argument | |
* (as in Firefox), and prevents errors when called on other | |
* DOM objects. | |
* @license MIT, GPL, do whatever you want | |
-* @see https://gist.github.com/brettz9/6093105 | |
*/ | |
(function () { | |
'use strict'; | |
var _slice = Array.prototype.slice; | |
try { | |
_slice.call(document.documentElement); // Can't be used with DOM elements in IE < 9 | |
} | |
catch (e) { // Fails in IE < 9 | |
Array.prototype.slice = function (begin, end, testa) { | |
var i, arrl = this.length, a = []; | |
if (this.charAt) { // Although IE < 9 does not fail when applying Array.prototype.slice | |
// to strings, here we do have to duck-type to avoid failing | |
// with IE < 9's lack of support for string indexes | |
for (i = 0; i < arrl; i++) { | |
a.push(this.charAt(i)); | |
} | |
} | |
else { // This will work for genuine arrays, array-like objects, NamedNodeMap (attributes, entities, notations), NodeList (e.g., getElementsByTagName), HTMLCollection (e.g., childNodes), and will not fail on other DOM objects (as do DOM elements in IE < 9) | |
for (i = 0; i < this.length; i++) { // IE < 9 (at least IE < 9 mode in IE 10) does not work with node.attributes (NamedNodeMap) without a dynamically checked length here | |
a.push(this[i]); | |
} | |
} | |
return _slice.call(a, begin, end || a.length); // IE < 9 gives errors here if end is allowed as undefined (as opposed to just missing) so we default ourselves | |
}; | |
} | |
}()); | |
/** | |
* @license MIT, GPL, do whatever you want | |
* @requires Array.prototype.slice fix {@link https://gist.github.com/brettz9/6093105} | |
*/ | |
if (!Array.from) { | |
Array.from = function (object) { | |
'use strict'; | |
return [].slice.call(object); | |
}; | |
} | |
/* | |
* Xccessors Standard: Cross-browser ECMAScript 5 accessors | |
* http://purl.eligrey.com/github/Xccessors | |
* | |
* 2010-06-21 | |
* | |
* By Eli Grey, http://eligrey.com | |
* | |
* A shim that partially implements Object.defineProperty, | |
* Object.getOwnPropertyDescriptor, and Object.defineProperties in browsers that have | |
* legacy __(define|lookup)[GS]etter__ support. | |
* | |
* Licensed under the X11/MIT License | |
* See LICENSE.md | |
*/ | |
/*jslint white: true, undef: true, plusplus: true, | |
bitwise: true, regexp: true, newcap: true, maxlen: 90 */ | |
/*! @source http://purl.eligrey.com/github/Xccessors/blob/master/xccessors-standard.js*/ | |
(function () { | |
"use strict"; | |
var ObjectProto = Object.prototype, | |
defineGetter = ObjectProto.__defineGetter__, | |
defineSetter = ObjectProto.__defineSetter__, | |
lookupGetter = ObjectProto.__lookupGetter__, | |
lookupSetter = ObjectProto.__lookupSetter__, | |
hasOwnProp = ObjectProto.hasOwnProperty; | |
if (defineGetter && defineSetter && lookupGetter && lookupSetter) { | |
if (!Object.defineProperty) { | |
Object.defineProperty = function (obj, prop, descriptor) { | |
if (arguments.length < 3) { // all arguments required | |
throw new TypeError("Arguments not optional"); | |
} | |
prop += ""; // convert prop to string | |
if (hasOwnProp.call(descriptor, "value")) { | |
if (!lookupGetter.call(obj, prop) && !lookupSetter.call(obj, prop)) { | |
// data property defined and no pre-existing accessors | |
obj[prop] = descriptor.value; | |
} | |
if ((hasOwnProp.call(descriptor, "get") || | |
hasOwnProp.call(descriptor, "set"))) | |
{ | |
// descriptor has a value prop but accessor already exists | |
throw new TypeError("Cannot specify an accessor and a value"); | |
} | |
} | |
// can't switch off these features in ECMAScript 3 | |
// so throw a TypeError if any are false | |
if (!(descriptor.writable && | |
descriptor.enumerable && descriptor.configurable)) | |
{ | |
throw new TypeError( | |
"This implementation of Object.defineProperty does not support" + | |
" false for configurable, enumerable, or writable." | |
); | |
} | |
if (descriptor.get) { | |
defineGetter.call(obj, prop, descriptor.get); | |
} | |
if (descriptor.set) { | |
defineSetter.call(obj, prop, descriptor.set); | |
} | |
return obj; | |
}; | |
} | |
if (!Object.getOwnPropertyDescriptor) { | |
Object.getOwnPropertyDescriptor = function (obj, prop) { | |
if (arguments.length < 2) { // all arguments required | |
throw new TypeError("Arguments not optional."); | |
} | |
prop += ""; // convert prop to string | |
var descriptor = { | |
configurable: true, | |
enumerable : true, | |
writable : true | |
}, | |
getter = lookupGetter.call(obj, prop), | |
setter = lookupSetter.call(obj, prop); | |
if (!hasOwnProp.call(obj, prop)) { | |
// property doesn't exist or is inherited | |
return descriptor; | |
} | |
if (!getter && !setter) { // not an accessor so return prop | |
descriptor.value = obj[prop]; | |
return descriptor; | |
} | |
// there is an accessor, remove descriptor.writable; | |
// populate descriptor.get and descriptor.set (IE's behavior) | |
delete descriptor.writable; | |
descriptor.get = descriptor.set = undefined; | |
if (getter) { | |
descriptor.get = getter; | |
} | |
if (setter) { | |
descriptor.set = setter; | |
} | |
return descriptor; | |
}; | |
} | |
if (!Object.defineProperties) { | |
Object.defineProperties = function (obj, props) { | |
var prop; | |
for (prop in props) { | |
if (hasOwnProp.call(props, prop)) { | |
Object.defineProperty(obj, prop, props[prop]); | |
} | |
} | |
}; | |
} | |
} | |
}()); | |
if (!Array.prototype.filter) { | |
Array.prototype.filter = function(fun /*, thisp*/) { | |
'use strict'; | |
if (this == null) { | |
throw new TypeError(); | |
} | |
var t = Object(this), | |
len = t.length >>> 0, | |
res, thisp, i, val; | |
if (typeof fun !== 'function') { | |
throw new TypeError(); | |
} | |
res = []; | |
thisp = arguments[1]; | |
for (i = 0; i < len; i++) { | |
if (i in t) { | |
val = t[i]; // in case fun mutates this | |
if (fun.call(thisp, val, i, t)) { | |
res.push(val); | |
} | |
} | |
} | |
return res; | |
}; | |
} | |
/*globals HTMLSelectElement*/ | |
/** | |
* @requires polyfill: Array.from {@link https://gist.github.com/4212262} | |
* @requires polyfill: Array.prototype.filter {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter} | |
* @requires polyfill: Object.defineProperty {@link https://github.com/eligrey/Xccessors} | |
* @license MIT, GPL, do whatever you want | |
*/ | |
(function () { | |
'use strict'; | |
// Inspired by http://stackoverflow.com/a/7754729/271577 | |
function PseudoHTMLCollection(arr) { | |
var i, arrl; | |
for (i = 0, arrl = arr.length; i < arrl; i++) { | |
this[i] = arr[i]; | |
} | |
try { | |
Object.defineProperty(this, 'length', { | |
get: function () { | |
return arr.length; | |
} | |
}); | |
} | |
catch (e) { // IE does not support accessors on non-DOM objects, so we can't handle dynamic (array-like index) addition to the collection | |
this.length = arr.length; | |
} | |
if (Object.freeze) { // Not present in IE, so don't rely on security aspects | |
Object.freeze(this); | |
} | |
} | |
PseudoHTMLCollection.prototype = { | |
constructor: PseudoHTMLCollection, | |
item: function (i) { | |
return this[i] !== undefined && this[i] !== null ? this[i] : null; | |
}, | |
namedItem: function (name) { | |
var i, thisl; | |
for (i = 0, thisl = this.length; i < thisl; i++) { | |
if (this[i].id === name || this[i].name === name) { | |
return this[i]; | |
} | |
} | |
return null; | |
} | |
}; | |
Object.defineProperty(HTMLSelectElement.prototype, 'selectedOptions', {get: function () { | |
return new PseudoHTMLCollection(Array.from(this.options).filter(function (option) { | |
return option.selected; | |
})); | |
}}); | |
}()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<select id="myItems" multiple="multiple"> | |
<optgroup><option>zzz</option></optgroup> | |
<option>abc</option> | |
<option>def</option> | |
<option>xyz</option> | |
</select> | |
<button onclick="run()">click</button> | |
<script src="HTMLSelectElement.prototype.selectedOptions.js"></script> | |
<script> | |
function run () { | |
var p = document.getElementById('myItems'); | |
alert(p.selectedOptions[0].value); | |
} | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment