255 lines
8.5 KiB
JavaScript
255 lines
8.5 KiB
JavaScript
"use strict";
|
|
|
|
exports.__esModule = true;
|
|
exports["default"] = makeAsyncScript;
|
|
|
|
var _react = require("react");
|
|
|
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
|
|
var _hoistNonReactStatics = _interopRequireDefault(require("hoist-non-react-statics"));
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
|
|
|
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
|
|
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
|
|
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
|
|
|
|
var SCRIPT_MAP = {}; // A counter used to generate a unique id for each component that uses the function
|
|
|
|
var idCount = 0;
|
|
|
|
function makeAsyncScript(getScriptURL, options) {
|
|
options = options || {};
|
|
return function wrapWithAsyncScript(WrappedComponent) {
|
|
var wrappedComponentName = WrappedComponent.displayName || WrappedComponent.name || "Component";
|
|
|
|
var AsyncScriptLoader =
|
|
/*#__PURE__*/
|
|
function (_Component) {
|
|
_inheritsLoose(AsyncScriptLoader, _Component);
|
|
|
|
function AsyncScriptLoader(props, context) {
|
|
var _this;
|
|
|
|
_this = _Component.call(this, props, context) || this;
|
|
_this.state = {};
|
|
_this.__scriptURL = "";
|
|
return _this;
|
|
}
|
|
|
|
var _proto = AsyncScriptLoader.prototype;
|
|
|
|
_proto.asyncScriptLoaderGetScriptLoaderID = function asyncScriptLoaderGetScriptLoaderID() {
|
|
if (!this.__scriptLoaderID) {
|
|
this.__scriptLoaderID = "async-script-loader-" + idCount++;
|
|
}
|
|
|
|
return this.__scriptLoaderID;
|
|
};
|
|
|
|
_proto.setupScriptURL = function setupScriptURL() {
|
|
this.__scriptURL = typeof getScriptURL === "function" ? getScriptURL() : getScriptURL;
|
|
return this.__scriptURL;
|
|
};
|
|
|
|
_proto.asyncScriptLoaderHandleLoad = function asyncScriptLoaderHandleLoad(state) {
|
|
var _this2 = this;
|
|
|
|
// use reacts setState callback to fire props.asyncScriptOnLoad with new state/entry
|
|
this.setState(state, function () {
|
|
return _this2.props.asyncScriptOnLoad && _this2.props.asyncScriptOnLoad(_this2.state);
|
|
});
|
|
};
|
|
|
|
_proto.asyncScriptLoaderTriggerOnScriptLoaded = function asyncScriptLoaderTriggerOnScriptLoaded() {
|
|
var mapEntry = SCRIPT_MAP[this.__scriptURL];
|
|
|
|
if (!mapEntry || !mapEntry.loaded) {
|
|
throw new Error("Script is not loaded.");
|
|
}
|
|
|
|
for (var obsKey in mapEntry.observers) {
|
|
mapEntry.observers[obsKey](mapEntry);
|
|
}
|
|
|
|
delete window[options.callbackName];
|
|
};
|
|
|
|
_proto.componentDidMount = function componentDidMount() {
|
|
var _this3 = this;
|
|
|
|
var scriptURL = this.setupScriptURL();
|
|
var key = this.asyncScriptLoaderGetScriptLoaderID();
|
|
var _options = options,
|
|
globalName = _options.globalName,
|
|
callbackName = _options.callbackName,
|
|
scriptId = _options.scriptId; // check if global object already attached to window
|
|
|
|
if (globalName && typeof window[globalName] !== "undefined") {
|
|
SCRIPT_MAP[scriptURL] = {
|
|
loaded: true,
|
|
observers: {}
|
|
};
|
|
} // check if script loading already
|
|
|
|
|
|
if (SCRIPT_MAP[scriptURL]) {
|
|
var entry = SCRIPT_MAP[scriptURL]; // if loaded or errored then "finish"
|
|
|
|
if (entry && (entry.loaded || entry.errored)) {
|
|
this.asyncScriptLoaderHandleLoad(entry);
|
|
return;
|
|
} // if still loading then callback to observer queue
|
|
|
|
|
|
entry.observers[key] = function (entry) {
|
|
return _this3.asyncScriptLoaderHandleLoad(entry);
|
|
};
|
|
|
|
return;
|
|
}
|
|
/*
|
|
* hasn't started loading
|
|
* start the "magic"
|
|
* setup script to load and observers
|
|
*/
|
|
|
|
|
|
var observers = {};
|
|
|
|
observers[key] = function (entry) {
|
|
return _this3.asyncScriptLoaderHandleLoad(entry);
|
|
};
|
|
|
|
SCRIPT_MAP[scriptURL] = {
|
|
loaded: false,
|
|
observers: observers
|
|
};
|
|
var script = document.createElement("script");
|
|
script.src = scriptURL;
|
|
script.async = true;
|
|
|
|
for (var attribute in options.attributes) {
|
|
script.setAttribute(attribute, options.attributes[attribute]);
|
|
}
|
|
|
|
if (scriptId) {
|
|
script.id = scriptId;
|
|
}
|
|
|
|
var callObserverFuncAndRemoveObserver = function callObserverFuncAndRemoveObserver(func) {
|
|
if (SCRIPT_MAP[scriptURL]) {
|
|
var mapEntry = SCRIPT_MAP[scriptURL];
|
|
var observersMap = mapEntry.observers;
|
|
|
|
for (var obsKey in observersMap) {
|
|
if (func(observersMap[obsKey])) {
|
|
delete observersMap[obsKey];
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
if (callbackName && typeof window !== "undefined") {
|
|
window[callbackName] = function () {
|
|
return _this3.asyncScriptLoaderTriggerOnScriptLoaded();
|
|
};
|
|
}
|
|
|
|
script.onload = function () {
|
|
var mapEntry = SCRIPT_MAP[scriptURL];
|
|
|
|
if (mapEntry) {
|
|
mapEntry.loaded = true;
|
|
callObserverFuncAndRemoveObserver(function (observer) {
|
|
if (callbackName) {
|
|
return false;
|
|
}
|
|
|
|
observer(mapEntry);
|
|
return true;
|
|
});
|
|
}
|
|
};
|
|
|
|
script.onerror = function () {
|
|
var mapEntry = SCRIPT_MAP[scriptURL];
|
|
|
|
if (mapEntry) {
|
|
mapEntry.errored = true;
|
|
callObserverFuncAndRemoveObserver(function (observer) {
|
|
observer(mapEntry);
|
|
return true;
|
|
});
|
|
}
|
|
};
|
|
|
|
document.body.appendChild(script);
|
|
};
|
|
|
|
_proto.componentWillUnmount = function componentWillUnmount() {
|
|
// Remove tag script
|
|
var scriptURL = this.__scriptURL;
|
|
|
|
if (options.removeOnUnmount === true) {
|
|
var allScripts = document.getElementsByTagName("script");
|
|
|
|
for (var i = 0; i < allScripts.length; i += 1) {
|
|
if (allScripts[i].src.indexOf(scriptURL) > -1) {
|
|
if (allScripts[i].parentNode) {
|
|
allScripts[i].parentNode.removeChild(allScripts[i]);
|
|
}
|
|
}
|
|
}
|
|
} // Clean the observer entry
|
|
|
|
|
|
var mapEntry = SCRIPT_MAP[scriptURL];
|
|
|
|
if (mapEntry) {
|
|
delete mapEntry.observers[this.asyncScriptLoaderGetScriptLoaderID()];
|
|
|
|
if (options.removeOnUnmount === true) {
|
|
delete SCRIPT_MAP[scriptURL];
|
|
}
|
|
}
|
|
};
|
|
|
|
_proto.render = function render() {
|
|
var globalName = options.globalName; // remove asyncScriptOnLoad from childProps
|
|
|
|
var _this$props = this.props,
|
|
asyncScriptOnLoad = _this$props.asyncScriptOnLoad,
|
|
forwardedRef = _this$props.forwardedRef,
|
|
childProps = _objectWithoutPropertiesLoose(_this$props, ["asyncScriptOnLoad", "forwardedRef"]); // eslint-disable-line no-unused-vars
|
|
|
|
|
|
if (globalName && typeof window !== "undefined") {
|
|
childProps[globalName] = typeof window[globalName] !== "undefined" ? window[globalName] : undefined;
|
|
}
|
|
|
|
childProps.ref = forwardedRef;
|
|
return (0, _react.createElement)(WrappedComponent, childProps);
|
|
};
|
|
|
|
return AsyncScriptLoader;
|
|
}(_react.Component); // Note the second param "ref" provided by React.forwardRef.
|
|
// We can pass it along to AsyncScriptLoader as a regular prop, e.g. "forwardedRef"
|
|
// And it can then be attached to the Component.
|
|
|
|
|
|
var ForwardedComponent = (0, _react.forwardRef)(function (props, ref) {
|
|
return (0, _react.createElement)(AsyncScriptLoader, _extends({}, props, {
|
|
forwardedRef: ref
|
|
}));
|
|
});
|
|
ForwardedComponent.displayName = "AsyncScriptLoader(" + wrappedComponentName + ")";
|
|
ForwardedComponent.propTypes = {
|
|
asyncScriptOnLoad: _propTypes["default"].func
|
|
};
|
|
return (0, _hoistNonReactStatics["default"])(ForwardedComponent, WrappedComponent);
|
|
};
|
|
} |