Source: polyfills.js

  1. /*!
  2. * Module Polyfills
  3. */
  4. /**
  5. * @namespace Polyfills
  6. */
  7. const MODULE_NAME = 'Polyfills';
  8. //###[ IMPORTS ]########################################################################################################
  9. import {assert, hasValue, isFunction, orDefault} from './basic.js';
  10. import {createFetchRequest} from './requests.js';
  11. //###[ EXPORTS ]########################################################################################################
  12. /**
  13. * @namespace Polyfills:polyfillFetch
  14. */
  15. /**
  16. * Polyfills window.fetch with a simple XMLHttpRequest-based implementation adapted from "unfetch", to provide
  17. * basic functionality with a compatible signature while keeping the source as small as possible.
  18. *
  19. * This polyfill should cover most basic use cases, but for complex cases you might need to polyfill something more
  20. * complete (for example Github's implementation: https://github.com/github/fetch).
  21. *
  22. * @param {?Boolean} [force=false] - if true, replaces a possibly present native implementation with the polyfill as well
  23. *
  24. * @memberof Polyfills:polyfillFetch
  25. * @alias polyfillFetch
  26. * @see https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
  27. * @see https://github.com/developit/unfetch
  28. * @example
  29. * polyfillFetch(true);
  30. */
  31. export function polyfillFetch(force=false){
  32. force = orDefault(force, false, 'bool');
  33. if( force || !isFunction(window.fetch) ){
  34. window.fetch = function(url, options=null){
  35. return createFetchRequest(url, options).execute();
  36. };
  37. }
  38. }
  39. /**
  40. * @namespace Polyfills:polyfillElementMatches
  41. */
  42. /**
  43. * Adds Element.matches support, if not already present in browser. Falls back to ms or mozilla implementations
  44. * if necessary.
  45. *
  46. * @throws error if Element.matches is not supported
  47. *
  48. * @memberof Polyfills:polyfillElementMatches
  49. * @alias polyfillElementMatches
  50. * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
  51. * @example
  52. * polyfillElementMatches()
  53. * => makes Element.prototype.matches available, if not already present
  54. */
  55. export function polyfillElementMatches(){
  56. const __methodName__ = 'polyfillElementMatches';
  57. if( !Element.prototype.matches ){
  58. Element.prototype.matches = Element.prototype.msMatchesSelector
  59. ?? Element.prototype.webkitMatchesSelector
  60. ?? null
  61. ;
  62. }
  63. assert(hasValue(Element.prototype.matches), `${MODULE_NAME}:${__methodName__} | browser does not support Element.matches`);
  64. }
  65. /**
  66. * @namespace Polyfills:polyfillCustomEvent
  67. */
  68. /**
  69. * Adds CustomEvent support, if not already present in browser. Falls back to manual implementation via
  70. * document.createEvent and event.initCustomEvent, if necessary.
  71. *
  72. * @memberof Polyfills:polyfillCustomEvent
  73. * @alias polyfillCustomEvent
  74. * @see https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
  75. * @example
  76. * polyfillCustomEvent()
  77. * => makes "window.CustomEvent" and "new CustomEvent()" available, if not already present
  78. */
  79. export function polyfillCustomEvent(){
  80. if( isFunction(window.CustomEvent) ) return false;
  81. const CustomEvent = function(event, params){
  82. params = params ?? {bubbles : false, cancelable : false, detail : undefined};
  83. const e = document.createEvent('CustomEvent');
  84. e.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
  85. return e;
  86. };
  87. CustomEvent.prototype = window.Event.prototype;
  88. window.CustomEvent = CustomEvent;
  89. }
  90. /**
  91. * @namespace Polyfills:polyfillArrayAt
  92. */
  93. /**
  94. * Adds support for Array.prototype.at, which is a fairly recent feature, compared to most other basic array
  95. * operations, resulting in even modern Chrome, Firefox and Safari versions not having implemented this.
  96. * But adding this is quite forward, it just being general array index access with possible negative index.
  97. *
  98. * @memberof Polyfills:polyfillArrayAt
  99. * @alias polyfillArrayAt
  100. * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at
  101. * @example
  102. * polyfillArrayAt()
  103. * => adds Array.prototype.at if not already defined
  104. */
  105. export function polyfillArrayAt(){
  106. if( isFunction(Array.prototype.at) ) return false;
  107. Object.defineProperty(Array.prototype, 'at', {
  108. value : function(n){
  109. n = Math.trunc(n) || 0;
  110. if( n < 0 ) n += this.length;
  111. if( (n < 0) || (n >= this.length) ) return undefined;
  112. return this[n];
  113. },
  114. writable : true,
  115. enumerable : false,
  116. configurable : true
  117. });
  118. }