UNPKG

vpaid-html5-client

Version:
232 lines (193 loc) 5.7 kB
'use strict'; var utils = require('./utils'); var unique = utils.unique('vpaidIframe'); var VPAIDAdUnit = require('./VPAIDAdUnit'); var defaultTemplate = '<!DOCTYPE html>' + '<html lang="en">' + '<head><meta charset="UTF-8"></head>' + '<body style="margin:0;padding:0"><div class="ad-element"></div>' + '<script type="text/javascript" src="{{iframeURL_JS}}"></script>' + '<script type="text/javascript">' + 'window.parent.postMessage(\'{"event": "ready", "id": "{{iframeID}}"}\', \'{{origin}}\');' + '</script>' + '</body>' + '</html>'; var AD_STOPPED = 'AdStopped'; /** * This callback is displayed as global member. The callback use nodejs error-first callback style * @callback NodeStyleCallback * @param {string|null} * @param {undefined|object} */ /** * VPAIDHTML5Client * @class * * @param {HTMLElement} el that will contain the iframe to load adUnit and a el to add to adUnit slot * @param {HTMLVideoElement} video default video element to be used by adUnit * @param {object} [templateConfig] template: html template to be used instead of the default, extraOptions: to be used when rendering the template * @param {object} [vpaidOptions] timeout: when loading adUnit */ function VPAIDHTML5Client(el, video, templateConfig, vpaidOptions) { templateConfig = templateConfig || {}; this._id = unique(); this._destroyed = false; this._frameContainer = utils.createElementInEl(el, 'div'); this._videoEl = video; this._vpaidOptions = vpaidOptions || {timeout: 10000}; this._templateConfig = { template: templateConfig.template || defaultTemplate, extraOptions: templateConfig.extraOptions || {} }; } /** * destroy * */ VPAIDHTML5Client.prototype.destroy = function destroy() { if (this._destroyed) { return; } this._destroyed = true; $unloadPreviousAdUnit.call(this); }; /** * isDestroyed * * @return {boolean} */ VPAIDHTML5Client.prototype.isDestroyed = function isDestroyed() { return this._destroyed; }; /** * loadAdUnit * * @param {string} adURL url of the js of the adUnit * @param {nodeStyleCallback} callback */ VPAIDHTML5Client.prototype.loadAdUnit = function loadAdUnit(adURL, callback) { $throwIfDestroyed.call(this); $unloadPreviousAdUnit.call(this); var that = this; var frame = utils.createIframeWithContent( this._frameContainer, this._templateConfig.template, utils.extend({ iframeURL_JS: adURL, iframeID: this.getID(), origin: getOrigin() }, this._templateConfig.extraOptions) ); this._frame = frame; this._onLoad = utils.callbackTimeout( this._vpaidOptions.timeout, onLoad.bind(this), onTimeout.bind(this) ); window.addEventListener('message', this._onLoad); function onLoad (e) { /*jshint validthis: false */ //don't clear timeout if (e.origin !== getOrigin()) return; var result = JSON.parse(e.data); //don't clear timeout if (result.id !== that.getID()) return; var adUnit, error, createAd; if (!that._frame.contentWindow) { error = 'the iframe is not anymore in the DOM tree'; } else { createAd = that._frame.contentWindow.getVPAIDAd; error = utils.validate(typeof createAd === 'function', 'the ad didn\'t return a function to create an ad'); } if (!error) { var adEl = that._frame.contentWindow.document.querySelector('.ad-element'); adUnit = new VPAIDAdUnit(createAd(), adEl, that._videoEl, that._frame); adUnit.subscribe(AD_STOPPED, $adDestroyed.bind(that)); error = utils.validate(adUnit.isValidVPAIDAd(), 'the add is not fully complaint with VPAID specification'); } that._adUnit = adUnit; $destroyLoadListener.call(that); callback(error, error ? null : adUnit); //clear timeout return true; } function onTimeout() { callback('timeout', null); } }; /** * unloadAdUnit * */ VPAIDHTML5Client.prototype.unloadAdUnit = function unloadAdUnit() { $unloadPreviousAdUnit.call(this); }; /** * getID will return the unique id * * @return {string} */ VPAIDHTML5Client.prototype.getID = function () { return this._id; }; /** * $removeEl * * @param {string} key */ function $removeEl(key) { var el = this[key]; if (el) { el.remove(); delete this[key]; } } function $adDestroyed() { $removeAdElements.call(this); delete this._adUnit; } function $unloadPreviousAdUnit() { $removeAdElements.call(this); $destroyAdUnit.call(this); } function $removeAdElements() { $removeEl.call(this, '_frame'); $destroyLoadListener.call(this); } /** * $destroyLoadListener * */ function $destroyLoadListener() { if (this._onLoad) { window.removeEventListener('message', this._onLoad); utils.clearCallbackTimeout(this._onLoad); delete this._onLoad; } } function $destroyAdUnit() { if (this._adUnit) { this._adUnit.stopAd(); delete this._adUnit; } } /** * $throwIfDestroyed * */ function $throwIfDestroyed() { if (this._destroyed) { throw new Error ('VPAIDHTML5Client already destroyed!'); } } function getOrigin() { if( window.location.origin ) { return window.location.origin; } else { return window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: ''); } } module.exports = VPAIDHTML5Client;