/*!
* Module Polyfills
*/
/**
* @namespace Polyfills
*/
const MODULE_NAME = 'Polyfills';
//###[ IMPORTS ]########################################################################################################
import {assert, hasValue, isFunction, orDefault} from './basic.js';
import {createFetchRequest} from './requests.js';
//###[ EXPORTS ]########################################################################################################
/**
* @namespace Polyfills:polyfillFetch
*/
/**
* Polyfills window.fetch with a simple XMLHttpRequest-based implementation adapted from "unfetch", to provide
* basic functionality with a compatible signature while keeping the source as small as possible.
*
* This polyfill should cover most basic use cases, but for complex cases you might need to polyfill something more
* complete (for example Github's implementation: https://github.com/github/fetch).
*
* @param {?Boolean} [force=false] - if true, replaces a possibly present native implementation with the polyfill as well
*
* @memberof Polyfills:polyfillFetch
* @alias polyfillFetch
* @see https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
* @see https://github.com/developit/unfetch
* @example
* polyfillFetch(true);
*/
export function polyfillFetch(force=false){
force = orDefault(force, false, 'bool');
if( force || !isFunction(window.fetch) ){
window.fetch = function(url, options=null){
return createFetchRequest(url, options).execute();
};
}
}
/**
* @namespace Polyfills:polyfillElementMatches
*/
/**
* Adds Element.matches support, if not already present in browser. Falls back to ms or mozilla implementations
* if necessary.
*
* @throws error if Element.matches is not supported
*
* @memberof Polyfills:polyfillElementMatches
* @alias polyfillElementMatches
* @see https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
* @example
* polyfillElementMatches()
* => makes Element.prototype.matches available, if not already present
*/
export function polyfillElementMatches(){
const __methodName__ = 'polyfillElementMatches';
if( !Element.prototype.matches ){
Element.prototype.matches = Element.prototype.msMatchesSelector
?? Element.prototype.webkitMatchesSelector
?? null
;
}
assert(hasValue(Element.prototype.matches), `${MODULE_NAME}:${__methodName__} | browser does not support Element.matches`);
}
/**
* @namespace Polyfills:polyfillCustomEvent
*/
/**
* Adds CustomEvent support, if not already present in browser. Falls back to manual implementation via
* document.createEvent and event.initCustomEvent, if necessary.
*
* @memberof Polyfills:polyfillCustomEvent
* @alias polyfillCustomEvent
* @see https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
* @example
* polyfillCustomEvent()
* => makes "window.CustomEvent" and "new CustomEvent()" available, if not already present
*/
export function polyfillCustomEvent(){
if( isFunction(window.CustomEvent) ) return false;
const CustomEvent = function(event, params){
params = params ?? {bubbles : false, cancelable : false, detail : undefined};
const e = document.createEvent('CustomEvent');
e.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
return e;
};
CustomEvent.prototype = window.Event.prototype;
window.CustomEvent = CustomEvent;
}
/**
* @namespace Polyfills:polyfillArrayAt
*/
/**
* Adds support for Array.prototype.at, which is a fairly recent feature, compared to most other basic array
* operations, resulting in even modern Chrome, Firefox and Safari versions not having implemented this.
* But adding this is quite forward, it just being general array index access with possible negative index.
*
* @memberof Polyfills:polyfillArrayAt
* @alias polyfillArrayAt
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at
* @example
* polyfillArrayAt()
* => adds Array.prototype.at if not already defined
*/
export function polyfillArrayAt(){
if( isFunction(Array.prototype.at) ) return false;
Object.defineProperty(Array.prototype, 'at', {
value : function(n){
n = Math.trunc(n) || 0;
if( n < 0 ) n += this.length;
if( (n < 0) || (n >= this.length) ) return undefined;
return this[n];
},
writable : true,
enumerable : false,
configurable : true
});
}