Skip to content

Instantly share code, notes, and snippets.

@jacopocolo
Created April 25, 2020 19:26
Show Gist options
  • Save jacopocolo/a4183b2ad781dc20d90d2d113ce4f846 to your computer and use it in GitHub Desktop.
Save jacopocolo/a4183b2ad781dc20d90d2d113ce4f846 to your computer and use it in GitHub Desktop.
Polyfill functions to make Bitsy 7.0 and below work on a Nintendo 3ds browser
<script type="text/javascript">
//assign polyfill
if (!Object.assign) {
Object.defineProperty(Object, 'assign', {
enumerable: false,
configurable: true,
writable: true,
value: function(target, firstSource) {
'use strict';
if (target === undefined || target === null) {
throw new TypeError('Cannot convert first argument to object');
}
var to = Object(target);
for (var i = 1; i < arguments.length; i++) {
var nextSource = arguments[i];
if (nextSource === undefined || nextSource === null) {
continue;
}
nextSource = Object(nextSource);
var keysArray = Object.keys(Object(nextSource));
for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
var nextKey = keysArray[nextIndex];
var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
if (desc !== undefined && desc.enumerable) {
to[nextKey] = nextSource[nextKey];
}
}
}
return to;
}
});
}
//includes polyfill
if (!Array.prototype.includes) {
Array.prototype.includes = function(searchElement /*, fromIndex*/) {
'use strict';
if (this == null) {
throw new TypeError('Array.prototype.includes called on null or undefined');
}
var O = Object(this);
var len = parseInt(O.length, 10) || 0;
if (len === 0) {
return false;
}
var n = parseInt(arguments[1], 10) || 0;
var k;
if (n >= 0) {
k = n;
} else {
k = len + n;
if (k < 0) {k = 0;}
}
var currentElement;
while (k < len) {
currentElement = O[k];
if (searchElement === currentElement ||
(searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN
return true;
}
k++;
}
return false;
};
}
//map polyfill
/**
* Copyright 2012 Eric Wendelin - MIT License
*
* es6-map-shim.js is a DESTRUCTIVE shim that follows the latest Map specification
* as closely as possible. It is destructive in the sense that it overrides native implementations.
*
* IMPORTANT: Currently, get(), set(), has() and delete() are all O(n) operations.
* Normally, they would be O(1). Therefore it is NOT recommended to use this with
* a large dataset or in any production environment.
*
* This library assumes ES5 functionality: Object.create, Object.defineProperty,
* Array.indexOf, Function.bind and others.
*/
(function(module) {
function Map(iterable) {
var _items = [];
var _keys = [];
var _values = [];
// Object.is polyfill, courtesy of @WebReflection
var is = Object.is || function(a, b) {
return a === b ?
a !== 0 || 1 / a == 1 / b :
a != a && b != b;
};
// More reliable indexOf, courtesy of @WebReflection
var betterIndexOf = function(value) {
if(value != value || value === 0) {
for(var i = this.length; i-- && !is(this[i], value););
} else {
i = [].indexOf.call(this, value);
}
return i;
};
/**
* MapIterator used for iterating over all entries in given map.
*
* @param map {Map} to iterate
* @param kind {String} identifying what to yield. Possible values
* are 'keys', 'values' and 'keys+values'
* @constructor
*/
var MapIterator = function MapIterator(map, kind) {
var _index = 0;
return Object.create({}, {
next: {
value: function() {
// check if index is within bounds
if (_index < map.items().length) {
switch(kind) {
case 'keys': return map.keys()[_index++];
case 'values': return map.values()[_index++];
case 'keys+values': return [].slice.call(map.items()[_index++]);
default: throw new TypeError('Invalid iterator type');
}
}
// TODO: make sure I'm interpreting the spec correctly here
throw new Error('Stop Iteration');
}
},
iterator: {
value: function() {
return this;
}
},
toString: {
value: function() {
return '[object Map Iterator]';
}
}
});
};
var _set = function(key, value) {
// check if key exists and overwrite
var index = betterIndexOf.call(_keys, key);
if (index > -1) {
_items[index][1] = value;
_values[index] = value;
} else {
_items.push([key, value]);
_keys.push(key);
_values.push(value);
}
};
var setItem = function(item) {
if (item.length !== 2) {
throw new TypeError('Invalid iterable passed to Map constructor');
}
_set(item[0], item[1]);
};
// FIXME: accommodate any class that defines an @@iterator method that returns
// an iterator object that produces two element array-like objects
if (Array.isArray(iterable)) {
iterable.forEach(setItem);
} else if (iterable !== undefined) {
throw new TypeError('Invalid Map');
}
return Object.create(MapPrototype, {
/**
* @return {Array} all entries in the Map, in order
*/
items:{
value:function() {
return [].slice.call(_items);
}
},
/**
* @return {Array} all keys in the Map, in order
*/
keys:{
value:function() {
return [].slice.call(_keys);
}
},
/**
* @return {Array} all values in the Map, in order
*/
values:{
value:function() {
return [].slice.call(_values);
}
},
/**
* Given a key, indicate whether that key exists in this Map.
*
* @param key {Object} expected key
* @return {Boolean} true if key in Map
*/
has:{
value:function(key) {
// TODO: double-check how spec reads about null values
var index = betterIndexOf.call(_keys, key);
return index > -1;
}
},
/**
* Given a key, retrieve the value associated with that key (or undefined).
*
* @param key {Object}
* @return {Object} value associated with key or undefined
*/
get:{
value:function(key) {
var index = betterIndexOf.call(_keys, key);
return index > -1 ? _values[index] : undefined;
}
},
/**
* Add or overwrite entry associating key with value. Always returns undefined.
*
* @param key {Object} anything
* @param value {Object} also anything
*/
set:{
value: _set
},
/**
* Return the number of entries in this Map.
*
* @return {Number} number of entries
*/
size:{
get:function() {
return _items.length;
}
},
/**
* Remove all entries in this Map. Returns undefined.
*/
clear:{
value:function() {
_keys.length = _values.length = _items.length = 0;
}
},
/**
* Delete entry with given key, if it exists.
*
* @param key {Object} any possible key
* @return {Boolean} true if an entry was deleted
*/
'delete':{
value:function(key) {
var index = betterIndexOf.call(_keys, key);
if (index > -1) {
_keys.splice(index, 1);
_values.splice(index, 1);
_items.splice(index, 1);
return true;
}
return false;
}
},
/**
* Given a callback function and optional context, invoke the callback on all
* entries in this Map.
*
* @param callbackFn {Function}
*/
forEach:{
value:function(callbackfn /*, thisArg*/) {
if (typeof callbackfn != 'function') {
throw new TypeError('Invalid callback function given to forEach');
}
function tryNext() {
try {
return iter.next();
} catch(e) {
return undefined;
}
}
var iter = this.iterator();
var current = tryNext();
var next = tryNext();
while(current !== undefined) {
callbackfn.apply(arguments[1], [current[1], current[0], this]);
current = next;
next = tryNext();
}
}
},
/**
* Return a MapIterator object for this map.
*/
iterator:{
value: function() {
return new MapIterator(this, 'keys+values');
}
},
toString:{
value: function() {
return '[Object Map]';
}
}
});
}
var notInNode = module == 'undefined';
var window = notInNode ? this : global;
var module = notInNode ? {} : exports;
var MapPrototype = Map.prototype;
Map.prototype = MapPrototype = Map();
window.Map = module.Map = window.Map || Map;
}.call(this, typeof exports));
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment