diff --git a/.gitignore b/.gitignore index c3f2fe7..2562ef2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ es/ node_modules/ -# lib/ +lib/ dist/ coverage/ npm-debug.log diff --git a/docs/api/ReactGPT.md b/docs/api/ReactGPT.md index 85229be..96b1123 100644 --- a/docs/api/ReactGPT.md +++ b/docs/api/ReactGPT.md @@ -29,6 +29,7 @@ A React component which renders [GPT](https://support.google.com/dfp_sb/answer/1 - `onSlotOnload`(optional) - An optional event handler function for `googletag.events.SlotOnloadEvent`. - `renderWhenViewable`(optional) - An optional flag to indicate whether an ad should only render when it's fully in the viewport area. - `viewableThreshold`(optional) - An optional number to indicate how much percentage of an ad area needs to be in a viewable area before rendering. Acceptable range is between `0` and `1`. +- `viewableTriggerTop`(optional) - An optional percentage figure to trigger render when the ad is x% below the fold. - `onScriptLoaded`(optional) - An optional call back function to notify when the script is loaded. - `onMediaQueryChange`(optional) - An optional call back function to notify when the media queries change on the break point specified in the `sizeMapping`. - `style`(optional) - An optional object to be applied as `style` props to the container div. **This prop is only applied once in initial render.** If you want to apply style to the ad and change it frequently, apply style to the container. diff --git a/lib/Bling.js b/lib/Bling.js deleted file mode 100644 index 514da8c..0000000 --- a/lib/Bling.js +++ /dev/null @@ -1,915 +0,0 @@ -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _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; }; - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _class, _temp2; /* eslint-disable react/sort-comp */ - - -var _react = require("react"); - -var _react2 = _interopRequireDefault(_react); - -var _propTypes = require("prop-types"); - -var _propTypes2 = _interopRequireDefault(_propTypes); - -var _reactDom = require("react-dom"); - -var _reactDom2 = _interopRequireDefault(_reactDom); - -var _invariant = require("invariant"); - -var _invariant2 = _interopRequireDefault(_invariant); - -var _deepEqual = require("deep-equal"); - -var _deepEqual2 = _interopRequireDefault(_deepEqual); - -var _hoistNonReactStatics = require("hoist-non-react-statics"); - -var _hoistNonReactStatics2 = _interopRequireDefault(_hoistNonReactStatics); - -var _Events = require("./Events"); - -var _Events2 = _interopRequireDefault(_Events); - -var _filterProps = require("./utils/filterProps"); - -var _filterProps2 = _interopRequireDefault(_filterProps); - -var _createManager = require("./createManager"); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -/** - * An Ad Component using Google Publisher Tags. - * This component should work standalone w/o context. - * https://developers.google.com/doubleclick-gpt/ - * - * @module Bling - * @class Bling - * @fires Bling#Events.READY - * @fires Bling#Events.SLOT_RENDER_ENDED - * @fires Bling#Events.IMPRESSION_VIEWABLE - * @fires Bling#Events.SLOT_VISIBILITY_CHANGED - * @fires Bling#Events.SLOT_LOADED - */ -var Bling = (_temp2 = _class = function (_Component) { - _inherits(Bling, _Component); - - function Bling() { - var _ref; - - var _temp, _this, _ret; - - _classCallCheck(this, Bling); - - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Bling.__proto__ || Object.getPrototypeOf(Bling)).call.apply(_ref, [this].concat(args))), _this), _this.state = { - scriptLoaded: false, - inViewport: false - }, _temp), _possibleConstructorReturn(_this, _ret); - } - - /** - * An array of prop names which can reflect to the ad by calling `refresh`. - * - * @property refreshableProps - * @static - */ - - /** - * An array of prop names which requires to create a new ad slot and render as a new ad. - * - * @property reRenderProps - * @static - */ - - /** - * An instance of ad manager. - * - * @property _adManager - * @private - * @static - */ - - /** - * - * @property - * @private - * @static - */ - - - _createClass(Bling, [{ - key: "componentDidMount", - value: function componentDidMount() { - Bling._adManager.addInstance(this); - Bling._adManager.load(Bling._config.seedFileUrl).then(this.onScriptLoaded.bind(this)).catch(this.onScriptError.bind(this)); - } - }, { - key: "componentWillReceiveProps", - value: function componentWillReceiveProps(nextProps) { - var propsEqual = Bling._config.propsEqual; - var sizeMapping = this.props.sizeMapping; - - - if ((nextProps.sizeMapping || sizeMapping) && !propsEqual(nextProps.sizeMapping, sizeMapping)) { - Bling._adManager.removeMQListener(this, nextProps); - } - } - }, { - key: "shouldComponentUpdate", - value: function shouldComponentUpdate(nextProps, nextState) { - // if adUnitPath changes, need to create a new slot, re-render - // otherwise, just refresh - var scriptLoaded = nextState.scriptLoaded, - inViewport = nextState.inViewport; - - var notInViewport = this.notInViewport(nextProps, nextState); - var inViewportChanged = this.state.inViewport !== inViewport; - var isScriptLoaded = this.state.scriptLoaded !== scriptLoaded; - - // Exit early for visibility change, before executing deep equality check. - if (notInViewport) { - return false; - } else if (inViewportChanged) { - return true; - } - - var _Bling$_config = Bling._config, - filterProps = _Bling$_config.filterProps, - propsEqual = _Bling$_config.propsEqual; - - var refreshableProps = filterProps(Bling.refreshableProps, this.props, nextProps); - var reRenderProps = filterProps(Bling.reRenderProps, this.props, nextProps); - var shouldRender = !propsEqual(reRenderProps.props, reRenderProps.nextProps); - var shouldRefresh = !shouldRender && !propsEqual(refreshableProps.props, refreshableProps.nextProps); - - if (shouldRefresh) { - this.configureSlot(this._adSlot, nextProps); - } - - if (Bling._adManager._syncCorrelator) { - if (shouldRefresh) { - Bling._adManager.refresh(); - } else if (shouldRender || isScriptLoaded) { - Bling._adManager.renderAll(); - } - } else { - if (shouldRefresh) { - this.refresh(); - return false; - } - if (shouldRender || isScriptLoaded) { - return true; - } - } - - return false; - } - }, { - key: "componentDidUpdate", - value: function componentDidUpdate() { - if (this.notInViewport(this.props, this.state)) { - return; - } - if (this._divId) { - // initial render will enable pubads service before any ad renders - // so taken care of by the manager - if (Bling._adManager._initialRender) { - Bling._adManager.render(); - } else { - this.renderAd(); - } - } - } - }, { - key: "componentWillUnmount", - value: function componentWillUnmount() { - Bling._adManager.removeInstance(this); - if (this._adSlot) { - Bling._adManager.googletag.destroySlots([this._adSlot]); - this._adSlot = null; - } - } - }, { - key: "onScriptLoaded", - value: function onScriptLoaded() { - var onScriptLoaded = this.props.onScriptLoaded; - - - if (this.getRenderWhenViewable()) { - this.foldCheck(); - } - this.setState({ scriptLoaded: true }, onScriptLoaded); // eslint-disable-line react/no-did-mount-set-state - } - }, { - key: "onScriptError", - value: function onScriptError(err) { - console.warn("Ad: Failed to load gpt for " + Bling._config.seedFileUrl, err); - } - }, { - key: "getRenderWhenViewable", - value: function getRenderWhenViewable() { - var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.props; - - return props.renderWhenViewable !== undefined ? props.renderWhenViewable : Bling._config.renderWhenViewable; - } - }, { - key: "foldCheck", - value: function foldCheck() { - if (this.state.inViewport) { - return; - } - - var slotSize = this.getSlotSize(); - if (Array.isArray(slotSize) && Array.isArray(slotSize[0])) { - slotSize = slotSize[0]; - } - if (slotSize === "fluid" || Array.isArray(slotSize) && slotSize[0] === "fluid") { - slotSize = [0, 0]; - } - - var inViewport = Bling._adManager.isInViewport(_reactDom2.default.findDOMNode(this), slotSize, this.viewableThreshold); - if (inViewport) { - this.setState({ inViewport: true }); - } - } - }, { - key: "defineSizeMapping", - value: function defineSizeMapping(adSlot, sizeMapping) { - if (sizeMapping) { - Bling._adManager.addMQListener(this, this.props); - var sizeMappingArray = sizeMapping.reduce(function (mapping, size) { - return mapping.addSize(size.viewport, size.slot); - }, Bling._adManager.googletag.sizeMapping()).build(); - adSlot.defineSizeMapping(sizeMappingArray); - } - } - }, { - key: "setAttributes", - value: function setAttributes(adSlot, attributes) { - // no clear method, attempting to clear existing attributes before setting new ones. - var attributeKeys = adSlot.getAttributeKeys(); - attributeKeys.forEach(function (key) { - adSlot.set(key, null); - }); - if (attributes) { - Object.keys(attributes).forEach(function (key) { - adSlot.set(key, attributes[key]); - }); - } - } - }, { - key: "setTargeting", - value: function setTargeting(adSlot, targeting) { - adSlot.clearTargeting(); - if (targeting) { - Object.keys(targeting).forEach(function (key) { - adSlot.setTargeting(key, targeting[key]); - }); - } - } - }, { - key: "addCompanionAdService", - value: function addCompanionAdService(serviceConfig, adSlot) { - var companionAdsService = Bling._adManager.googletag.companionAds(); - adSlot.addService(companionAdsService); - if ((typeof serviceConfig === "undefined" ? "undefined" : _typeof(serviceConfig)) === "object") { - if (serviceConfig.hasOwnProperty("enableSyncLoading")) { - companionAdsService.enableSyncLoading(); - } - if (serviceConfig.hasOwnProperty("refreshUnfilledSlots")) { - companionAdsService.setRefreshUnfilledSlots(serviceConfig.refreshUnfilledSlots); - } - } - } - }, { - key: "getSlotSize", - value: function getSlotSize() { - var _props = this.props, - origSlotSize = _props.slotSize, - origSizeMapping = _props.sizeMapping; - - var slotSize = void 0; - if (origSlotSize) { - slotSize = origSlotSize; - } else if (origSizeMapping) { - var sizeMapping = origSizeMapping; - slotSize = sizeMapping[0] && sizeMapping[0].slot; - } - - return slotSize; - } - }, { - key: "renderAd", - value: function renderAd() { - this.defineSlot(); - this.display(); - } - }, { - key: "notInViewport", - value: function notInViewport() { - var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.props; - var state = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.state; - var inViewport = state.inViewport; - - return this.getRenderWhenViewable(props) && !inViewport; - } - }, { - key: "defineSlot", - value: function defineSlot() { - var _props2 = this.props, - adUnitPath = _props2.adUnitPath, - outOfPage = _props2.outOfPage, - npa = _props2.npa; - - var divId = this._divId; - var slotSize = this.getSlotSize(); - - this.handleSetNpaFlag(npa); - - if (!this._adSlot) { - if (outOfPage) { - this._adSlot = Bling._adManager.googletag.defineOutOfPageSlot(adUnitPath, divId); - } else { - this._adSlot = Bling._adManager.googletag.defineSlot(adUnitPath, slotSize || [], divId); - } - } - - this._adSlot && this.configureSlot(this._adSlot); - } - }, { - key: "configureSlot", - value: function configureSlot(adSlot) { - var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.props; - var sizeMapping = props.sizeMapping, - attributes = props.attributes, - targeting = props.targeting, - companionAdService = props.companionAdService, - categoryExclusion = props.categoryExclusion, - collapseEmptyDiv = props.collapseEmptyDiv, - safeFrameConfig = props.safeFrameConfig, - content = props.content, - clickUrl = props.clickUrl, - forceSafeFrame = props.forceSafeFrame; - - - this.defineSizeMapping(adSlot, sizeMapping); - - if (collapseEmptyDiv !== undefined) { - if (Array.isArray(collapseEmptyDiv)) { - var _adSlot$setCollapseEm; - - (_adSlot$setCollapseEm = adSlot.setCollapseEmptyDiv).call.apply(_adSlot$setCollapseEm, [adSlot].concat(_toConsumableArray(collapseEmptyDiv))); - } else { - adSlot.setCollapseEmptyDiv(collapseEmptyDiv); - } - } - - // Overrides click url - if (clickUrl) { - adSlot.setClickUrl(clickUrl); - } - - // Sets category exclusion - if (categoryExclusion) { - var exclusion = categoryExclusion; - if (typeof exclusion === "string") { - exclusion = [exclusion]; - } - adSlot.clearCategoryExclusions(); - exclusion.forEach(function (item) { - adSlot.setCategoryExclusion(item); - }); - } - - // Sets AdSense attributes - this.setAttributes(adSlot, attributes); - - // Sets custom targeting parameters - this.setTargeting(adSlot, targeting); - - if (safeFrameConfig) { - adSlot.setSafeFrameConfig(safeFrameConfig); - } - - if (forceSafeFrame) { - adSlot.setForceSafeFrame(forceSafeFrame); - } - - // Enables companion ad service - if (companionAdService) { - this.addCompanionAdService(companionAdService, adSlot); - } - - // GPT checks if the same service is already added. - if (content) { - adSlot.addService(Bling._adManager.googletag.content()); - } else { - adSlot.addService(Bling._adManager.googletag.pubads()); - } - } - }, { - key: "display", - value: function display() { - var _props3 = this.props, - content = _props3.content, - displayCallback = _props3.displayCallback, - adUnitPath = _props3.adUnitPath; - - var divId = this._divId; - var adSlot = this._adSlot; - var slotSize = this.getSlotSize(); - - if (content) { - Bling._adManager.googletag.content().setContent(adSlot, content); - } else { - if (!Bling._adManager._disableInitialLoad && !Bling._adManager._syncCorrelator) { - Bling._adManager.updateCorrelator(); - } - - if (typeof displayCallback === "function") { - displayCallback({ - display: function display() { - return Bling._adManager.googletag.display(divId); - }, - adSlotData: { - adUnitPath: adUnitPath, - size: slotSize, - adSlotId: divId - } - }); - } else { - Bling._adManager.googletag.display(divId); - } - - if (Bling._adManager._disableInitialLoad && !Bling._adManager._initialRender) { - this.refresh(); - } - } - } - }, { - key: "clear", - value: function clear() { - var adSlot = this._adSlot; - if (adSlot && adSlot.hasOwnProperty("getServices")) { - // googletag.ContentService doesn't clear content - var services = adSlot.getServices(); - if (this._divId && services.some(function (s) { - return !!s.setContent; - })) { - document.getElementById(this._divId).innerHTML = ""; - return; - } - Bling._adManager.clear([adSlot]); - } - } - }, { - key: "refresh", - value: function refresh(options) { - var adSlot = this._adSlot; - if (adSlot) { - this.clear(); - Bling._adManager.refresh([adSlot], options); - } - } - }, { - key: "render", - value: function render() { - var scriptLoaded = this.state.scriptLoaded; - var _props4 = this.props, - id = _props4.id, - outOfPage = _props4.outOfPage, - style = _props4.style; - - var shouldNotRender = this.notInViewport(this.props, this.state); - - if (!scriptLoaded || shouldNotRender) { - var slotSize = this.getSlotSize(); - - if (!outOfPage) { - (0, _invariant2.default)(slotSize, "Either 'slotSize' or 'sizeMapping' prop needs to be set."); - } - - if (Array.isArray(slotSize) && Array.isArray(slotSize[0])) { - slotSize = slotSize[0]; - } - // https://developers.google.com/doubleclick-gpt/reference?hl=en#googletag.NamedSize - if (slotSize === "fluid" || Array.isArray(slotSize) && slotSize[0] === "fluid") { - slotSize = ["auto", "auto"]; - } - var emptyStyle = slotSize && { - width: slotSize[0], - height: slotSize[1] - }; - // render node element instead of script element so that `inViewport` check works. - return _react2.default.createElement("div", { style: emptyStyle }); - } - - // clear the current ad if exists - this.clear(); - if (this._adSlot) { - Bling._adManager.googletag.destroySlots([this._adSlot]); - this._adSlot = null; - } - this._divId = id || Bling._adManager.generateDivId(); - - return _react2.default.createElement("div", { id: this._divId, style: style }); - } - - /** - * Call pubads and set the non-personalized Ads flag, if it is not undefined. - * - * @param {boolean} npa - */ - - }, { - key: "handleSetNpaFlag", - value: function handleSetNpaFlag(npa) { - if (npa === undefined) { - return; - } - - Bling._adManager.pubadsProxy({ - method: "setRequestNonPersonalizedAds", - args: [npa ? 1 : 0], - resolve: null, - reject: null - }); - } - }, { - key: "adSlot", - get: function get() { - return this._adSlot; - } - }, { - key: "viewableThreshold", - get: function get() { - return this.props.viewableThreshold >= 0 ? this.props.viewableThreshold : Bling._config.viewableThreshold; - } - }], [{ - key: "on", - value: function on(eventType, cb) { - Bling._on("on", eventType, cb); - } - }, { - key: "once", - value: function once(eventType, cb) { - Bling._on("once", eventType, cb); - } - }, { - key: "removeListener", - value: function removeListener() { - var _Bling$_adManager; - - (_Bling$_adManager = Bling._adManager).removeListener.apply(_Bling$_adManager, arguments); - } - }, { - key: "removeAllListeners", - value: function removeAllListeners() { - var _Bling$_adManager2; - - (_Bling$_adManager2 = Bling._adManager).removeAllListeners.apply(_Bling$_adManager2, arguments); - } - }, { - key: "_on", - value: function _on(fn, eventType, cb) { - if (typeof cb !== "function") { - return; - } - if (eventType === _Events2.default.READY && Bling._adManager.isReady) { - cb.call(Bling._adManager, Bling._adManager.googletag); - } else { - Bling._adManager[fn](eventType, cb); - } - } - }, { - key: "configure", - value: function configure() { - var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - - Bling._config = _extends({}, Bling._config, config); - } - /** - * Returns the GPT version. - * - * @method getGPTVersion - * @returns {Number|boolean} a version or false if GPT is not yet ready. - * @static - */ - - }, { - key: "getGPTVersion", - value: function getGPTVersion() { - return Bling._adManager.getGPTVersion(); - } - /** - * Returns the Pubads Service version. - * - * @method getPubadsVersion - * @returns {Number|boolean} a version or false if Pubads Service is not yet ready. - * @static - */ - - }, { - key: "getPubadsVersion", - value: function getPubadsVersion() { - return Bling._adManager.getPubadsVersion(); - } - /** - * Sets a flag to indicate whether the correlator value should always be same across the ads in the page or not. - * - * @method syncCorrelator - * @param {boolean} value - * @static - */ - - }, { - key: "syncCorrelator", - value: function syncCorrelator(value) { - Bling._adManager.syncCorrelator(value); - } - /** - * Trigger re-rendering of all the ads. - * - * @method render - * @static - */ - - }, { - key: "render", - value: function render() { - Bling._adManager.renderAll(); - } - /** - * Refreshes all the ads in the page with a new correlator value. - * - * @param {Array} slots An array of ad slots. - * @param {Object} options You can pass `changeCorrelator` flag. - * @static - */ - - }, { - key: "refresh", - value: function refresh(slots, options) { - Bling._adManager.refresh(slots, options); - } - /** - * Clears the ads for the specified ad slots, if no slots are provided, all the ads will be cleared. - * - * @method clear - * @param {Array} slots An optional array of slots to clear. - * @static - */ - - }, { - key: "clear", - value: function clear(slots) { - Bling._adManager.clear(slots); - } - /** - * Updates the correlator value for the next ad request. - * - * @method updateCorrelator - * @static - */ - - }, { - key: "updateCorrelator", - value: function updateCorrelator() { - Bling._adManager.updateCorrelator(); - } - }, { - key: "testManager", - set: function set(testManager) { - (0, _invariant2.default)(testManager, "Pass in createManagerTest to mock GPT"); - Bling._adManager = testManager; - } - }]); - - return Bling; -}(_react.Component), _class.propTypes = { - /** - * An optional string to be used as container div id. - * - * @property id - */ - id: _propTypes2.default.string, - /** - * An optional string indicating ad unit path which will be used - * to create an ad slot. - * - * @property adUnitPath - */ - adUnitPath: _propTypes2.default.string.isRequired, - /** - * An optional object which includes ad targeting key-value pairs. - * - * @property targeting - */ - targeting: _propTypes2.default.object, - /** - * An optional prop to specify the ad slot size which accepts [googletag.GeneralSize](https://developers.google.com/doubleclick-gpt/reference#googletag.GeneralSize) as a type. - * This will be preceded by the sizeMapping if specified. - * - * @property slotSize - */ - slotSize: _propTypes2.default.oneOfType([_propTypes2.default.array, _propTypes2.default.string]), - /** - * An optional array of object which contains an array of viewport size and slot size. - * This needs to be set if the ad needs to serve different ad sizes per different viewport sizes (responsive ad). - * Setting the `slot` to any dimension that's not configured in DFP results in rendering an empty ad. - * The ad slot size which is provided for the viewport size of [0, 0] will be used as default ad size if none of viewport size matches. - * - * https://support.google.com/dfp_premium/answer/3423562?hl=en - * - * e.g. - * - * sizeMapping={[ - * {viewport: [0, 0], slot: [320, 50]}, - * {viewport: [768, 0], slot: [728, 90]} - * ]} - * - * @property sizeMapping - */ - sizeMapping: _propTypes2.default.arrayOf(_propTypes2.default.shape({ - viewport: _propTypes2.default.array, - slot: _propTypes2.default.array - })), - /** - * An optional flag to indicate whether an ad slot should be out-of-page slot. - * - * @property outOfPage - */ - outOfPage: _propTypes2.default.bool, - /** - * An optional flag to indicate whether companion ad service should be enabled for the ad. - * If an object is passed, it takes as a configuration expecting `enableSyncLoading` or `refreshUnfilledSlots`. - * - * @property companionAdService - */ - companionAdService: _propTypes2.default.oneOfType([_propTypes2.default.bool, _propTypes2.default.object]), - /** - * An optional HTML content for the slot. If specified, the ad will render with the HTML content using content service. - * - * @property content - */ - content: _propTypes2.default.string, - /** - * An optional click through URL. If specified, any landing page URL associated with the creative that is served is overridden. - * - * @property clickUrl - */ - clickUrl: _propTypes2.default.string, - /** - * An optional string or an array of string which specifies a page-level ad category exclusion for the given label name. - * - * @property categoryExclusion - */ - categoryExclusion: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.array]), - /** - * An optional map of key-value pairs for an AdSense attribute on a particular ad slot. - * see the list of supported key value: https://developers.google.com/doubleclick-gpt/adsense_attributes#adsense_parameters.googletag.Slot - * - * @property attributes - */ - attributes: _propTypes2.default.object, - /** - * An optional flag to indicate whether an empty ad should be collapsed or not. - * - * @property collapseEmptyDiv - */ - collapseEmptyDiv: _propTypes2.default.oneOfType([_propTypes2.default.bool, _propTypes2.default.array]), - displayCallback: _propTypes2.default.func, - /** - * An optional flag to indicate whether ads in this slot should be forced to be rendered using a SafeFrame container. - * - * @property forceSafeFrame - */ - forceSafeFrame: _propTypes2.default.bool, - /** - * An optional object to set the slot-level preferences for SafeFrame configuration. - * - * @property safeFrameConfig - */ - safeFrameConfig: _propTypes2.default.object, - /** - * An optional event handler function for `googletag.events.SlotRenderEndedEvent`. - * - * @property onSlotRenderEnded - */ - onSlotRenderEnded: _propTypes2.default.func, - /** - * An optional event handler function for `googletag.events.ImpressionViewableEvent`. - * - * @property onImpressionViewable - */ - onImpressionViewable: _propTypes2.default.func, - /** - * An optional event handler function for `googletag.events.slotVisibilityChangedEvent`. - * - * @property onSlotVisibilityChanged - */ - onSlotVisibilityChanged: _propTypes2.default.func, - /** - * An optional event handler function for `googletag.events.SlotOnloadEvent`. - * - * @property onSlotOnload - */ - onSlotOnload: _propTypes2.default.func, - /** - * An optional flag to indicate whether an ad should only render when it's fully in the viewport area. - * - * @property renderWhenViewable - */ - renderWhenViewable: _propTypes2.default.bool, - /** - * An optional number to indicate how much percentage of an ad area needs to be in a viewable area before rendering. - * Acceptable range is between 0 and 1. - * - * @property viewableThreshold - */ - viewableThreshold: _propTypes2.default.number, - /** - * An optional call back function to notify when the script is loaded. - * - * @property onScriptLoaded - */ - onScriptLoaded: _propTypes2.default.func, - /** - * An optional call back function to notify when the media queries on the document change. - * - * @property onMediaQueryChange - */ - onMediaQueryChange: _propTypes2.default.func, - /** - * An optional object to be applied as `style` props to the container div. - * - * @property style - */ - style: _propTypes2.default.object, - /** - * An optional property to control non-personalized Ads. - * https://support.google.com/admanager/answer/7678538 - * - * Set to `true` to mark the ad request as NPA, and to `false` for ad requests that are eligible for personalized ads - * It is `false` by default, according to Google's definition. - * - * @property npa - */ - npa: _propTypes2.default.bool -}, _class.refreshableProps = ["targeting", "sizeMapping", "clickUrl", "categoryExclusion", "attributes", "collapseEmptyDiv", "companionAdService", "forceSafeFrame", "safeFrameConfig"], _class.reRenderProps = ["adUnitPath", "slotSize", "outOfPage", "content", "npa"], _class._adManager = (0, _createManager.createManager)(), _class._config = { - /** - * An optional string for GPT seed file url to override. - */ - seedFileUrl: "//www.googletagservices.com/tag/js/gpt.js", - /** - * An optional flag to indicate whether an ad should only render when it's fully in the viewport area. Default is `true`. - */ - renderWhenViewable: true, - /** - * An optional number to indicate how much percentage of an ad area needs to be in a viewable area before rendering. Default value is 0.5. - * Acceptable range is between 0 and 1. - */ - viewableThreshold: 0.5, - /** - * An optional function to create an object with filtered current props and next props for a given keys to perform equality check. - */ - filterProps: _filterProps2.default, - /** - * An optional function for the filtered props and the next props to perform equality check. - */ - propsEqual: _deepEqual2.default -}, _temp2); - -// proxy pubads API through Bling - -exports.default = (0, _hoistNonReactStatics2.default)(Bling, _createManager.pubadsAPI.reduce(function (api, method) { - api[method] = function () { - for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - args[_key2] = arguments[_key2]; - } - - return Bling._adManager.pubadsProxy({ method: method, args: args }); - }; - return api; -}, {})); \ No newline at end of file diff --git a/lib/Events.js b/lib/Events.js deleted file mode 100644 index bc0f0a2..0000000 --- a/lib/Events.js +++ /dev/null @@ -1,13 +0,0 @@ -Object.defineProperty(exports, "__esModule", { - value: true -}); -var Events = { - READY: "ready", - RENDER: "render", - SLOT_RENDER_ENDED: "slotRenderEnded", - IMPRESSION_VIEWABLE: "impressionViewable", - SLOT_VISIBILITY_CHANGED: "slotVisibilityChanged", - SLOT_LOADED: "slotOnload" -}; - -exports.default = Events; \ No newline at end of file diff --git a/lib/createManager.js b/lib/createManager.js deleted file mode 100644 index dbcd6b8..0000000 --- a/lib/createManager.js +++ /dev/null @@ -1,585 +0,0 @@ -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.AdManager = exports.APIToCallBeforeServiceEnabled = exports.pubadsAPI = undefined; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -exports.createManager = createManager; - -var _eventemitter = require("eventemitter3"); - -var _eventemitter2 = _interopRequireDefault(_eventemitter); - -var _throttleDebounce = require("throttle-debounce"); - -var _invariant = require("invariant"); - -var _invariant2 = _interopRequireDefault(_invariant); - -var _exenv = require("exenv"); - -var _Events = require("./Events"); - -var _Events2 = _interopRequireDefault(_Events); - -var _isInViewport2 = require("./utils/isInViewport"); - -var _isInViewport3 = _interopRequireDefault(_isInViewport2); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -// based on https://developers.google.com/doubleclick-gpt/reference?hl=en -var pubadsAPI = exports.pubadsAPI = ["enableAsyncRendering", "enableSingleRequest", "enableSyncRendering", "disableInitialLoad", "collapseEmptyDivs", "enableVideoAds", "set", "get", "getAttributeKeys", "setTargeting", "clearTargeting", "setCategoryExclusion", "clearCategoryExclusions", "setCentering", "setCookieOptions", "setLocation", "setPublisherProvidedId", "setTagForChildDirectedTreatment", "clearTagForChildDirectedTreatment", "setVideoContent", "setForceSafeFrame"]; - -var APIToCallBeforeServiceEnabled = exports.APIToCallBeforeServiceEnabled = ["enableAsyncRendering", "enableSingleRequest", "enableSyncRendering", "disableInitialLoad", "collapseEmptyDivs", "setCentering"]; - -var AdManager = exports.AdManager = function (_EventEmitter) { - _inherits(AdManager, _EventEmitter); - - function AdManager() { - var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - - _classCallCheck(this, AdManager); - - var _this = _possibleConstructorReturn(this, (AdManager.__proto__ || Object.getPrototypeOf(AdManager)).call(this, config)); - - _this._adCnt = 0; - _this._initialRender = true; - _this._syncCorrelator = false; - _this._testMode = false; - _this._foldCheck = (0, _throttleDebounce.throttle)(20, function (event) { - var instances = _this.getMountedInstances(); - instances.forEach(function (instance) { - if (instance.getRenderWhenViewable()) { - instance.foldCheck(event); - } - }); - - if (_this.testMode) { - _this._getTimer(); - } - }); - - _this._handleMediaQueryChange = function (event) { - if (_this._syncCorrelator) { - _this.refresh(); - return; - } - // IE returns `event.media` value differently, need to use regex to evaluate. - // eslint-disable-next-line wrap-regex - var res = /min-width:\s?(\d+)px/.exec(event.media); - var viewportWidth = res && res[1]; - - if (viewportWidth && _this._mqls[viewportWidth]) { - _this._mqls[viewportWidth].listeners.forEach(function (instance) { - instance.refresh(); - if (instance.props.onMediaQueryChange) { - instance.props.onMediaQueryChange(event); - } - }); - } - }; - - _this.render = (0, _throttleDebounce.debounce)(4, function () { - if (!_this._initialRender) { - return; - } - - var checkPubadsReady = function checkPubadsReady(cb) { - if (_this.pubadsReady) { - cb(); - } else { - setTimeout(checkPubadsReady, 50, cb); - } - }; - - var instances = _this.getMountedInstances(); - var hasPubAdsService = false; - var dummyAdSlot = void 0; - - // Define all the slots - instances.forEach(function (instance) { - if (!instance.notInViewport()) { - instance.defineSlot(); - var adSlot = instance.adSlot; - - if (adSlot && adSlot.hasOwnProperty("getServices")) { - var services = adSlot.getServices(); - if (!hasPubAdsService) { - hasPubAdsService = services.filter(function (service) { - return !!service.enableAsyncRendering; - }).length > 0; - } - } - } - }); - // if none of the ad slots uses pubads service, create dummy slot to use pubads service. - if (!hasPubAdsService) { - dummyAdSlot = _this.googletag.defineSlot("/", []); - dummyAdSlot.addService(_this.googletag.pubads()); - } - - // Call pubads API which needs to be called before service is enabled. - _this._processPubadsQueue(); - - // Enable service - _this.googletag.enableServices(); - - // After the service is enabled, check periodically until `pubadsReady` flag returns true before proceeding the rest. - checkPubadsReady(function () { - // destroy dummy ad slot if exists. - if (dummyAdSlot) { - _this.googletag.destroySlots([dummyAdSlot]); - } - // Call the rest of the pubads API that's in the queue. - _this._processPubadsQueue(); - // listen for GPT events - _this._listen(); - // client should be able to set any page-level setting within the event handler. - _this._isReady = true; - _this.emit(_Events2.default.READY, _this.googletag); - - // Call display - instances.forEach(function (instance) { - if (!instance.notInViewport()) { - instance.display(); - } - }); - - _this.emit(_Events2.default.RENDER, _this.googletag); - - _this._initialRender = false; - }); - }); - _this.renderAll = (0, _throttleDebounce.debounce)(4, function () { - if (!_this.apiReady) { - return false; - } - - // first instance updates correlator value and re-render each ad - var instances = _this.getMountedInstances(); - instances.forEach(function (instance, i) { - if (i === 0) { - _this.updateCorrelator(); - } - instance.forceUpdate(); - }); - - return true; - }); - - - if (config.test) { - _this.testMode = config; - } - return _this; - } - - _createClass(AdManager, [{ - key: "_processPubadsQueue", - value: function _processPubadsQueue() { - var _this2 = this; - - if (this._pubadsProxyQueue) { - Object.keys(this._pubadsProxyQueue).forEach(function (method) { - if (_this2.googletag && !_this2.googletag.pubadsReady && APIToCallBeforeServiceEnabled.indexOf(method) > -1 || _this2.pubadsReady) { - _this2._pubadsProxyQueue[method].forEach(function (params) { - return _this2.pubadsProxy(params); - }); - delete _this2._pubadsProxyQueue[method]; - } - }); - if (!Object.keys(this._pubadsProxyQueue).length) { - this._pubadsProxyQueue = null; - } - } - } - }, { - key: "_callPubads", - value: function _callPubads(_ref) { - var method = _ref.method, - args = _ref.args, - resolve = _ref.resolve, - reject = _ref.reject; - - if (typeof this.googletag.pubads()[method] !== "function") { - reject(new Error("googletag.pubads does not support " + method + ", please update pubadsAPI")); - } else { - try { - var _googletag$pubads; - - var result = (_googletag$pubads = this.googletag.pubads())[method].apply(_googletag$pubads, _toConsumableArray(args)); - resolve(result); - } catch (err) { - reject(err); - } - } - } - }, { - key: "_toggleListener", - value: function _toggleListener(add) { - var _this3 = this; - - ["scroll", "resize"].forEach(function (eventName) { - window[add ? "addEventListener" : "removeEventListener"](eventName, _this3._foldCheck); - }); - } - }, { - key: "_getTimer", - value: function _getTimer() { - return Date.now(); - } - }, { - key: "_listen", - value: function _listen() { - var _this4 = this; - - if (!this._listening) { - [_Events2.default.SLOT_RENDER_ENDED, _Events2.default.IMPRESSION_VIEWABLE, _Events2.default.SLOT_VISIBILITY_CHANGED, _Events2.default.SLOT_LOADED].forEach(function (eventType) { - ["pubads", "content", "companionAds"].forEach(function (service) { - // there is no API to remove listeners. - _this4.googletag[service]().addEventListener(eventType, _this4._onEvent.bind(_this4, eventType)); - }); - }); - this._listening = true; - } - } - }, { - key: "_onEvent", - value: function _onEvent(eventType, event) { - // fire to the global listeners - if (this.listeners(eventType, true)) { - this.emit(eventType, event); - } - // call event handler props - var instances = this.getMountedInstances(); - var slot = event.slot; - - var funcName = "on" + eventType.charAt(0).toUpperCase() + eventType.substr(1); - var instance = instances.filter(function (inst) { - return slot === inst.adSlot; - })[0]; - if (instance && instance.props[funcName]) { - instance.props[funcName](event); - } - } - }, { - key: "syncCorrelator", - value: function syncCorrelator() { - var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; - - this._syncCorrelator = value; - } - }, { - key: "generateDivId", - value: function generateDivId() { - return "bling-" + ++this._adCnt; - } - }, { - key: "getMountedInstances", - value: function getMountedInstances() { - if (!this.mountedInstances) { - this.mountedInstances = []; - } - return this.mountedInstances; - } - }, { - key: "addInstance", - value: function addInstance(instance) { - var instances = this.getMountedInstances(); - var index = instances.indexOf(instance); - if (index === -1) { - // The first instance starts listening for the event. - if (instances.length === 0) { - this._toggleListener(true); - } - this.addMQListener(instance, instance.props); - instances.push(instance); - } - } - }, { - key: "removeInstance", - value: function removeInstance(instance) { - var instances = this.getMountedInstances(); - var index = instances.indexOf(instance); - if (index >= 0) { - instances.splice(index, 1); - // The last instance removes listening for the event. - if (instances.length === 0) { - this._toggleListener(false); - } - this.removeMQListener(instance, instance.props); - } - } - }, { - key: "addMQListener", - value: function addMQListener(instance, _ref2) { - var _this5 = this; - - var sizeMapping = _ref2.sizeMapping; - - if (!sizeMapping || !Array.isArray(sizeMapping)) { - return; - } - - sizeMapping.forEach(function (size) { - var viewportWidth = size.viewport && size.viewport[0]; - if (viewportWidth !== undefined) { - if (!_this5._mqls) { - _this5._mqls = {}; - } - if (!_this5._mqls[viewportWidth]) { - var mql = window.matchMedia("(min-width: " + viewportWidth + "px)"); - mql.addListener(_this5._handleMediaQueryChange); - _this5._mqls[viewportWidth] = { - mql: mql, - listeners: [] - }; - } - if (_this5._mqls[viewportWidth].listeners.indexOf(instance) === -1) { - _this5._mqls[viewportWidth].listeners.push(instance); - } - } - }); - } - }, { - key: "removeMQListener", - value: function removeMQListener(instance) { - var _this6 = this; - - if (!this._mqls) { - return; - } - - Object.keys(this._mqls).forEach(function (key) { - var index = _this6._mqls[key].listeners.indexOf(instance); - if (index > -1) { - _this6._mqls[key].listeners.splice(index, 1); - } - if (_this6._mqls[key].listeners.length === 0) { - _this6._mqls[key].mql.removeListener(_this6._handleMediaQueryChange); - delete _this6._mqls[key]; - } - }); - } - }, { - key: "isInViewport", - value: function isInViewport() { - return _isInViewport3.default.apply(undefined, arguments); - } - - /** - * Refreshes all the ads in the page with a new correlator value. - * - * @param {Array} slots An array of ad slots. - * @param {Object} options You can pass `changeCorrelator` flag. - * @static - */ - - }, { - key: "refresh", - value: function refresh(slots, options) { - if (!this.pubadsReady) { - return false; - } - - // gpt already debounces refresh - this.googletag.pubads().refresh(slots, options); - - return true; - } - }, { - key: "clear", - value: function clear(slots) { - if (!this.pubadsReady) { - return false; - } - - this.googletag.pubads().clear(slots); - - return true; - } - - /** - * Re-render(not refresh) all the ads in the page and the first ad will update the correlator value. - * Updating correlator value ensures competitive exclusion. - * - * @method renderAll - * @static - */ - - }, { - key: "getGPTVersion", - value: function getGPTVersion() { - if (!this.apiReady) { - return false; - } - return this.googletag.getVersion(); - } - }, { - key: "getPubadsVersion", - value: function getPubadsVersion() { - if (!this.pubadsReady) { - return false; - } - return this.googletag.pubads().getVersion(); - } - }, { - key: "updateCorrelator", - value: function updateCorrelator() { - if (!this.pubadsReady) { - return false; - } - this.googletag.pubads().updateCorrelator(); - - return true; - } - }, { - key: "load", - value: function load(url) { - var _this7 = this; - - return this._loadPromise || (this._loadPromise = new Promise(function (resolve, reject) { - // test mode can't be enabled in production mode - if (_this7.testMode) { - resolve(_this7.googletag); - return; - } - if (!_exenv.canUseDOM) { - reject(new Error("DOM not available")); - return; - } - if (!url) { - reject(new Error("url is missing")); - return; - } - var onLoad = function onLoad() { - if (window.googletag) { - _this7._googletag = window.googletag; - // make sure API is ready for use. - _this7.googletag.cmd.push(function () { - _this7._isLoaded = true; - resolve(_this7.googletag); - }); - } else { - reject(new Error("window.googletag is not available")); - } - }; - if (window.googletag && window.googletag.apiReady) { - onLoad(); - } else { - var script = document.createElement("script"); - script.async = true; - script.onload = onLoad; - script.onerror = function () { - reject(new Error("failed to load script")); - }; - script.src = url; - document.head.appendChild(script); - } - })); - } - }, { - key: "pubadsProxy", - value: function pubadsProxy(_ref3) { - var _this8 = this; - - var method = _ref3.method, - _ref3$args = _ref3.args, - args = _ref3$args === undefined ? [] : _ref3$args, - resolve = _ref3.resolve, - reject = _ref3.reject; - - if (!resolve) { - // there are couple pubads API which doesn't provide getter methods for later use, - // so remember them here. - if (APIToCallBeforeServiceEnabled.indexOf(method) > -1) { - this["_" + method] = args && args.length && args[0] || true; - } - return new Promise(function (resolve2, reject2) { - var params = { - method: method, - args: args, - resolve: resolve2, - reject: reject2 - }; - if (!_this8.pubadsReady) { - if (!_this8._pubadsProxyQueue) { - _this8._pubadsProxyQueue = {}; - } - if (!_this8._pubadsProxyQueue[method]) { - _this8._pubadsProxyQueue[method] = []; - } - _this8._pubadsProxyQueue[method].push(params); - } else { - _this8._callPubads(params); - } - }); - } - - this._callPubads({ method: method, args: args, resolve: resolve, reject: reject }); - - return Promise.resolve(); - } - }, { - key: "googletag", - get: function get() { - return this._googletag; - } - }, { - key: "isLoaded", - get: function get() { - return !!this._isLoaded; - } - }, { - key: "isReady", - get: function get() { - return !!this._isReady; - } - }, { - key: "apiReady", - get: function get() { - return this.googletag && this.googletag.apiReady; - } - }, { - key: "pubadsReady", - get: function get() { - return this.googletag && this.googletag.pubadsReady; - } - }, { - key: "testMode", - get: function get() { - return this._testMode; - }, - set: function set(config) { - if (process.env.NODE_ENV === "production") { - return; - } - var test = config.test, - GPTMock = config.GPTMock; - - this._isLoaded = true; - this._testMode = !!test; - - if (test) { - (0, _invariant2.default)(test && GPTMock, "Must provide GPTMock to enable testMode. config{GPTMock}"); - this._googletag = new GPTMock(config); - } - } - }]); - - return AdManager; -}(_eventemitter2.default); - -function createManager(config) { - return new AdManager(config); -} \ No newline at end of file diff --git a/lib/index.js b/lib/index.js deleted file mode 100644 index e3f05ae..0000000 --- a/lib/index.js +++ /dev/null @@ -1,23 +0,0 @@ -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _Bling = require("./Bling"); - -Object.defineProperty(exports, "Bling", { - enumerable: true, - get: function get() { - return _interopRequireDefault(_Bling).default; - } -}); - -var _Events = require("./Events"); - -Object.defineProperty(exports, "Events", { - enumerable: true, - get: function get() { - return _interopRequireDefault(_Events).default; - } -}); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } \ No newline at end of file diff --git a/lib/utils/apiList.js b/lib/utils/apiList.js deleted file mode 100644 index 41085d2..0000000 --- a/lib/utils/apiList.js +++ /dev/null @@ -1,12 +0,0 @@ -Object.defineProperty(exports, "__esModule", { - value: true -}); -// DO NOT MODIFY THIS FILE MANUALLY. -// This file is generated by `npm run update-apilist`. -// Note that only APIs that's documented in https://developers.google.com/doubleclick-gpt/reference is officially supported. - -var gptVersion = exports.gptVersion = 110; -var gptAPI = exports.gptAPI = [["getVersion", "function"], ["cmd", "object"], ["getEventLog", "function"], ["enableServices", "function"], ["setAdIframeTitle", "function"], ["impl", "object"], ["pubads", "function"], ["defineOutOfPageSlot", "function"], ["defineSlot", "function"], ["defineUnit", "function"], ["destroySlots", "function"], ["display", "function"], ["companionAds", "function"], ["content", "function"], ["debug_log", "object"], ["service_manager_instance", "object"], ["disablePublisherConsole", "function"], ["onPubConsoleJsLoad", "function"], ["openConsole", "function"], ["sizeMapping", "function"], ["evalScripts", "function"], ["apiReady", "boolean"], ["slot_manager_instance", "object"], ["pubadsReady", "boolean"]]; -var pubadsVersion = exports.pubadsVersion = 110; -var pubadsAPI = exports.pubadsAPI = [["set", "function"], ["get", "function"], ["getAttributeKeys", "function"], ["display", "function"], ["getName", "function"], ["setCookieOptions", "function"], ["setTagForChildDirectedTreatment", "function"], ["clearTagForChildDirectedTreatment", "function"], ["setKidsFriendlyAds", "function"], ["setTargeting", "function"], ["clearTargeting", "function"], ["getTargeting", "function"], ["getTargetingKeys", "function"], ["setCategoryExclusion", "function"], ["clearCategoryExclusions", "function"], ["disableInitialLoad", "function"], ["enableSingleRequest", "function"], ["enableAsyncRendering", "function"], ["enableSyncRendering", "function"], ["setCentering", "function"], ["setPublisherProvidedId", "function"], ["definePassback", "function"], ["defineOutOfPagePassback", "function"], ["refresh", "function"], ["enableVideoAds", "function"], ["setVideoContent", "function"], ["getVideoContent", "function"], ["getCorrelator", "function"], ["setCorrelator", "function"], ["updateCorrelator", "function"], ["isAdRequestFinished", "function"], ["collapseEmptyDivs", "function"], ["clear", "function"], ["setLocation", "function"], ["getVersion", "function"], ["forceExperiment", "function"], ["markAsAmp", "function"], ["setSafeFrameConfig", "function"], ["setForceSafeFrame", "function"], ["enableChromeInterventionSignals", "function"], ["markAsGladeControl", "function"], ["markAsGladeOptOut", "function"], ["getName", "function"], ["getVersion", "function"], ["getSlots", "function"], ["getSlotIdMap", "function"], ["enable", "function"], ["addEventListener", "function"]]; -var slotAPI = exports.slotAPI = [["getPassbackPageUrl", "function"], ["set", "function"], ["get", "function"], ["getAttributeKeys", "function"], ["addService", "function"], ["getName", "function"], ["getAdUnitPath", "function"], ["getInstance", "function"], ["getSlotElementId", "function"], ["getSlotId", "function"], ["getServices", "function"], ["getSizes", "function"], ["defineSizeMapping", "function"], ["hasWrapperDiv", "function"], ["setClickUrl", "function"], ["getClickUrl", "function"], ["setForceSafeFrame", "function"], ["setCategoryExclusion", "function"], ["clearCategoryExclusions", "function"], ["getCategoryExclusions", "function"], ["setTargeting", "function"], ["clearTargeting", "function"], ["getTargetingMap", "function"], ["getTargeting", "function"], ["getTargetingKeys", "function"], ["getOutOfPage", "function"], ["getAudExtId", "function"], ["gtfcd", "function"], ["setCollapseEmptyDiv", "function"], ["getCollapseEmptyDiv", "function"], ["getDivStartsCollapsed", "function"], ["fetchStarted", "function"], ["getContentUrl", "function"], ["fetchEnded", "function"], ["renderStarted", "function"], ["getResponseInformation", "function"], ["renderEnded", "function"], ["loaded", "function"], ["impressionViewable", "function"], ["visibilityChanged", "function"], ["setFirstLook", "function"], ["getFirstLook", "function"], ["getEscapedQemQueryId", "function"], ["setSafeFrameConfig", "function"], ["getCsiId", "function"]]; \ No newline at end of file diff --git a/lib/utils/createManagerTest.js b/lib/utils/createManagerTest.js deleted file mode 100644 index d52474a..0000000 --- a/lib/utils/createManagerTest.js +++ /dev/null @@ -1,18 +0,0 @@ -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _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; }; - -exports.createManagerTest = createManagerTest; - -var _createManager = require("../createManager.js"); - -var _mockGPT = require("./mockGPT"); - -function createManagerTest(config) { - return (0, _createManager.createManager)(_extends({}, config, { - test: true, - GPTMock: _mockGPT.GPTMock - })); -} \ No newline at end of file diff --git a/lib/utils/filterProps.js b/lib/utils/filterProps.js deleted file mode 100644 index cf9fc73..0000000 --- a/lib/utils/filterProps.js +++ /dev/null @@ -1,14 +0,0 @@ -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = filterProps; -function filterProps(propKeys, props, nextProps) { - return propKeys.reduce(function (filtered, key) { - filtered.props[key] = props[key]; - filtered.nextProps[key] = nextProps[key]; - return filtered; - }, { - props: {}, - nextProps: {} - }); -} \ No newline at end of file diff --git a/lib/utils/isInViewport.js b/lib/utils/isInViewport.js deleted file mode 100644 index 7473a1d..0000000 --- a/lib/utils/isInViewport.js +++ /dev/null @@ -1,34 +0,0 @@ -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); - -exports.default = isInViewport; -function isInViewport(el) { - var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [0, 0], - _ref2 = _slicedToArray(_ref, 2), - width = _ref2[0], - height = _ref2[1]; - - var offset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; - - if (!el || el.nodeType !== 1) { - return false; - } - var clientRect = el.getBoundingClientRect(); - var rect = { - top: clientRect.top, - left: clientRect.left, - bottom: clientRect.bottom, - right: clientRect.right - }; - var viewport = { - top: 0, - left: 0, - bottom: window.innerHeight, - right: window.innerWidth - }; - var inViewport = rect.bottom >= viewport.top + height * offset && rect.right >= viewport.left + width * offset && rect.top <= viewport.bottom - height * offset && rect.left <= viewport.right - width * offset; - return inViewport; -} \ No newline at end of file diff --git a/lib/utils/mockGPT.js b/lib/utils/mockGPT.js deleted file mode 100644 index 8bc2e3f..0000000 --- a/lib/utils/mockGPT.js +++ /dev/null @@ -1,467 +0,0 @@ -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.ContentServiceMock = exports.CompanionAdsServiceMock = exports.PubAdsServiceMock = exports.SizeMappingBuilderMock = exports.SlotMock = exports.GPTMock = undefined; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); - -var _apiList = require("./apiList"); - -var _Events = require("../Events"); - -var _Events2 = _interopRequireDefault(_Events); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function createMock(list, obj) { - return list.reduce(function (mock, _ref) { - var _ref2 = _slicedToArray(_ref, 2), - api = _ref2[0], - type = _ref2[1]; - - if (typeof mock[api] === "undefined") { - if (type === "function") { - mock[api] = function () { - if (arguments.length) { - return arguments.length <= 0 ? undefined : arguments[0]; - } - return {}; - }; - } else if (type === "boolean") { - mock[api] = true; - } else { - mock[api] = {}; - } - } - return mock; - }, obj || {}); -} - -function getSize(slot) { - var sizes = slot.getSizes(); - var item = sizes; - while (Array.isArray(item[0])) { - item = item[0]; - } - - return item; -} - -var SlotMock = function () { - function SlotMock(adUnitPath, size, divId) { - _classCallCheck(this, SlotMock); - - this.adUnitPath = adUnitPath; - this.size = size; - this.divId = divId; - this.services = []; - this.attributes = {}; - this.categoryExclusions = []; - this._targeting = {}; - } - - _createClass(SlotMock, [{ - key: "defineSizeMapping", - value: function defineSizeMapping(sizeMapping) { - this.size = sizeMapping; - return this; - } - }, { - key: "addService", - value: function addService(service) { - this.services.push(service); - } - }, { - key: "getServices", - value: function getServices() { - return this.services; - } - }, { - key: "set", - value: function set(key, value) { - this.attributes[key] = value; - return this; - } - }, { - key: "get", - value: function get(key) { - return this.attributes[key]; - } - }, { - key: "getAttributeKeys", - value: function getAttributeKeys() { - return Object.keys(this.attributes); - } - }, { - key: "setCollapseEmptyDiv", - value: function setCollapseEmptyDiv(collapse, collapseBeforeAdFetch) { - this.collapseEmptyDiv = collapse; - this.collapseBeforeAdFetch = collapseBeforeAdFetch; - return this; - } - }, { - key: "getCollapseEmptyDiv", - value: function getCollapseEmptyDiv() { - return this.collapseEmptyDiv; - } - }, { - key: "setClickUrl", - value: function setClickUrl(clickUrl) { - this.clickUrl = clickUrl; - return this; - } - }, { - key: "getClickUrl", - value: function getClickUrl() { - return this.clickUrl; - } - }, { - key: "setCategoryExclusion", - value: function setCategoryExclusion(categoryExclusion) { - this.categoryExclusions.push(categoryExclusion); - return this; - } - }, { - key: "getCategoryExclusions", - value: function getCategoryExclusions() { - return this.categoryExclusions; - } - }, { - key: "clearCategoryExclusions", - value: function clearCategoryExclusions() { - this.categoryExclusions = []; - return this; - } - }, { - key: "setTargeting", - value: function setTargeting(key, value) { - this._targeting[key] = value; - return this; - } - }, { - key: "getAdUnitPath", - value: function getAdUnitPath() { - return this.adUnitPath; - } - }, { - key: "clearTargeting", - value: function clearTargeting() { - this._targeting = {}; - return this; - } - }, { - key: "getTargeting", - value: function getTargeting(key) { - return this._targeting && this._targeting[key]; - } - }, { - key: "getTargetingKeys", - value: function getTargetingKeys() { - return this._targeting && Object.keys(this._targeting); - } - }, { - key: "getSizes", - value: function getSizes() { - return this.size; - } - }, { - key: "getSlotElementId", - value: function getSlotElementId() { - return this.divId; - } - }]); - - return SlotMock; -}(); - -createMock(_apiList.slotAPI, SlotMock.prototype); - -var SizeMappingBuilderMock = function () { - function SizeMappingBuilderMock() { - var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - - _classCallCheck(this, SizeMappingBuilderMock); - - this.config = config; - } - - _createClass(SizeMappingBuilderMock, [{ - key: "addSize", - value: function addSize(viewportSize, slotSize) { - if (!this.mapping) { - this.mapping = []; - } - this.mapping.push([viewportSize, slotSize]); - return this; - } - }, { - key: "build", - value: function build() { - return this.mapping; - } - }]); - - return SizeMappingBuilderMock; -}(); - -var BaseService = function () { - function BaseService() { - var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - - _classCallCheck(this, BaseService); - - this.config = config; - this.listeners = {}; - this.slots = {}; - } - - _createClass(BaseService, [{ - key: "addEventListener", - value: function addEventListener(eventType, cb) { - if (!this.listeners[eventType]) { - this.listeners[eventType] = []; - } - this.listeners[eventType].push(cb); - } - }, { - key: "getSlots", - value: function getSlots() { - var _this = this; - - return Object.keys(this.slots).map(function (key) { - return _this.slots[key]; - }); - } - }]); - - return BaseService; -}(); - -var PubAdsServiceMock = function (_BaseService) { - _inherits(PubAdsServiceMock, _BaseService); - - function PubAdsServiceMock() { - var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - - _classCallCheck(this, PubAdsServiceMock); - - var _this2 = _possibleConstructorReturn(this, (PubAdsServiceMock.__proto__ || Object.getPrototypeOf(PubAdsServiceMock)).call(this, config)); - - _this2.version = _apiList.pubadsVersion; - return _this2; - } - - _createClass(PubAdsServiceMock, [{ - key: "getVersion", - value: function getVersion() { - return this.version; - } - }, { - key: "refresh", - value: function refresh(slots) { - var _this3 = this; - - if (!slots) { - slots = Object.keys(this.slots).map(function (key) { - return _this3.slots[key]; - }); - } - setTimeout(function () { - var key = _Events2.default.SLOT_RENDER_ENDED; - slots.forEach(function (slot) { - if (_this3.listeners[key]) { - _this3.listeners[key].forEach(function (cb) { - var isEmpty = !!_this3.config.emptyAd; - var event = { - isEmpty: isEmpty, - creativeId: isEmpty ? null : Date.now(), - lineItemId: isEmpty ? null : Date.now(), - serviceName: "publisher_ads", - size: isEmpty ? null : getSize(slot), - slot: slot - }; - cb(event); - }); - } - }); - }, 0); - } - }]); - - return PubAdsServiceMock; -}(BaseService); - -createMock(_apiList.pubadsAPI, PubAdsServiceMock.prototype); - -var CompanionAdsServiceMock = function (_BaseService2) { - _inherits(CompanionAdsServiceMock, _BaseService2); - - function CompanionAdsServiceMock() { - var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - - _classCallCheck(this, CompanionAdsServiceMock); - - return _possibleConstructorReturn(this, (CompanionAdsServiceMock.__proto__ || Object.getPrototypeOf(CompanionAdsServiceMock)).call(this, config)); - } - - _createClass(CompanionAdsServiceMock, [{ - key: "enableSyncLoading", - value: function enableSyncLoading() { - this._enableSyncLoading = true; - } - }, { - key: "setRefreshUnfilledSlots", - value: function setRefreshUnfilledSlots(value) { - if (typeof value === "boolean") { - this._refreshUnfilledSlots = value; - } - } - }]); - - return CompanionAdsServiceMock; -}(BaseService); - -var ContentServiceMock = function (_BaseService3) { - _inherits(ContentServiceMock, _BaseService3); - - function ContentServiceMock() { - var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - - _classCallCheck(this, ContentServiceMock); - - return _possibleConstructorReturn(this, (ContentServiceMock.__proto__ || Object.getPrototypeOf(ContentServiceMock)).call(this, config)); - } - - _createClass(ContentServiceMock, [{ - key: "setContent", - value: function setContent(slot, content) { - slot._content = content; - } - }]); - - return ContentServiceMock; -}(BaseService); - -var GPTMock = function () { - function GPTMock() { - var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - - _classCallCheck(this, GPTMock); - - this.pubadsReady = false; - - this.config = config; - this.version = _apiList.gptVersion; - this.cmd = {}; - this.cmd.push = function (cb) { - cb(); - }; - } - - _createClass(GPTMock, [{ - key: "getVersion", - value: function getVersion() { - return this.version; - } - }, { - key: "enableServices", - value: function enableServices() { - var _this6 = this; - - setTimeout(function () { - _this6.pubadsReady = true; - }, 0); - } - }, { - key: "sizeMapping", - value: function sizeMapping() { - if (!this.sizeMappingBuilder) { - this.sizeMappingBuilder = new SizeMappingBuilderMock(this.config); - } - return this.sizeMappingBuilder; - } - }, { - key: "pubads", - value: function pubads() { - if (!this._pubads) { - this._pubads = new PubAdsServiceMock(this.config); - } - return this._pubads; - } - }, { - key: "companionAds", - value: function companionAds() { - if (!this._companionAds) { - this._companionAds = new CompanionAdsServiceMock(this.config); - } - return this._companionAds; - } - }, { - key: "content", - value: function content() { - if (!this._content) { - this._content = new ContentServiceMock(this.config); - } - return this._content; - } - }, { - key: "defineSlot", - value: function defineSlot(adUnitPath, size, divId) { - var slot = new SlotMock(adUnitPath, size, divId); - this.pubads().slots[divId] = slot; - return slot; - } - }, { - key: "defineOutOfPageSlot", - value: function defineOutOfPageSlot(adUnitPath, divId) { - var slot = new SlotMock(adUnitPath, [1, 1], divId); - this.pubads().slots[divId] = slot; - return slot; - } - }, { - key: "display", - value: function display(divId) { - var _this7 = this; - - var pubads = this.pubads(); - setTimeout(function () { - Object.keys(pubads.listeners).forEach(function (key) { - if (pubads.listeners[key]) { - pubads.listeners[key].forEach(function (cb) { - var slot = pubads.slots[divId]; - var isEmpty = !!_this7.config.emptyAd; - var event = { - isEmpty: isEmpty, - creativeId: isEmpty ? null : Date.now(), - lineItemId: isEmpty ? null : Date.now(), - serviceName: "publisher_ads", - size: isEmpty ? null : getSize(slot), - slot: slot - }; - cb(event); - }); - } - }); - }, 0); - } - }]); - - return GPTMock; -}(); - -createMock(_apiList.gptAPI, GPTMock.prototype); - -exports.GPTMock = GPTMock; -exports.SlotMock = SlotMock; -exports.SizeMappingBuilderMock = SizeMappingBuilderMock; -exports.PubAdsServiceMock = PubAdsServiceMock; -exports.CompanionAdsServiceMock = CompanionAdsServiceMock; -exports.ContentServiceMock = ContentServiceMock; \ No newline at end of file diff --git a/package.json b/package.json index 4fe414e..d6b9b30 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dennisinteractive/react-gpt", - "version": "2.2.0", + "version": "2.2.0-optimize-lazyload-v4-test", "description": "A react display ad component using Google Publisher Tag", "main": "lib/index.js", "jsnext:main": "es/index.js", diff --git a/src/Bling.js b/src/Bling.js index 2335259..6c2d3e0 100644 --- a/src/Bling.js +++ b/src/Bling.js @@ -175,6 +175,12 @@ class Bling extends Component { * @property viewableThreshold */ viewableThreshold: PropTypes.number, + /** + * An optional number to trigger rendering when an ad is x% amount below the fold. Overrides viewableThreshold + * + * @property viewableTriggerTop + */ + viewableTriggerTop: PropTypes.number, /** * An optional call back function to notify when the script is loaded. * @@ -517,11 +523,35 @@ class Bling extends Component { : Bling._config.renderWhenViewable; } + isDisplayNone(rect) { + return ( + rect.top === 0 && + rect.bottom === 0 && + rect.left === 0 && + rect.right === 0 + ); + } + foldCheck() { if (this.state.inViewport) { return; } + if ( + this.props.viewableTriggerTop && + this.props.viewableTriggerTop > 0 + ) { + const rect = ReactDOM.findDOMNode(this).getBoundingClientRect(); + if (!this.isDisplayNone(rect)) { + const triggerPercentVal = + window.innerHeight / 100 * this.props.viewableTriggerTop; + if (rect.top <= window.innerHeight + triggerPercentVal) { + this.setState({inViewport: true}); + return; + } + } + } + let slotSize = this.getSlotSize(); if (Array.isArray(slotSize) && Array.isArray(slotSize[0])) { slotSize = slotSize[0];