UNPKG

vpaid-html5-client

Version:
231 lines (196 loc) 6.94 kB
'use strict'; var IVPAIDAdUnit = require('./IVPAIDAdUnit'); var Subscriber = require('./subscriber'); var checkVPAIDInterface = IVPAIDAdUnit.checkVPAIDInterface; var utils = require('./utils'); var METHODS = IVPAIDAdUnit.METHODS; var ERROR = 'AdError'; var AD_CLICK = 'AdClickThru'; var FILTERED_EVENTS = IVPAIDAdUnit.EVENTS.filter(function (event) { return event != AD_CLICK; }); /** * This callback is displayed as global member. The callback use nodejs error-first callback style * @callback NodeStyleCallback * @param {string|null} * @param {undefined|object} */ /** * VPAIDAdUnit * @class * * @param VPAIDCreative * @param {HTMLElement} [el] this will be used in initAd environmentVars.slot if defined * @param {HTMLVideoElement} [video] this will be used in initAd environmentVars.videoSlot if defined */ function VPAIDAdUnit(VPAIDCreative, el, video, iframe) { this._isValid = checkVPAIDInterface(VPAIDCreative); if (this._isValid) { this._creative = VPAIDCreative; this._el = el; this._videoEl = video; this._iframe = iframe; this._subscribers = new Subscriber(); utils.setFullSizeStyle(el); $addEventsSubscribers.call(this); } } VPAIDAdUnit.prototype = Object.create(IVPAIDAdUnit.prototype); /** * isValidVPAIDAd will return if the VPAIDCreative passed in constructor is valid or not * * @return {boolean} */ VPAIDAdUnit.prototype.isValidVPAIDAd = function isValidVPAIDAd() { return this._isValid; }; IVPAIDAdUnit.METHODS.forEach(function(method) { //NOTE: this methods arguments order are implemented differently from the spec var ignores = [ 'subscribe', 'unsubscribe', 'initAd' ]; if (ignores.indexOf(method) !== -1) return; VPAIDAdUnit.prototype[method] = function () { var ariaty = IVPAIDAdUnit.prototype[method].length; // TODO avoid leaking arguments // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments var args = Array.prototype.slice.call(arguments); var callback = (ariaty === args.length) ? args.pop() : undefined; setTimeout(function () { var result, error = null; try { result = this._creative[method].apply(this._creative, args); } catch(e) { error = e; } callOrTriggerEvent(callback, this._subscribers, error, result); }.bind(this), 0); }; }); /** * initAd concreate implementation * * @param {number} width * @param {number} height * @param {string} viewMode can be 'normal', 'thumbnail' or 'fullscreen' * @param {number} desiredBitrate indicates the desired bitrate in kbps * @param {object} [creativeData] used for additional initialization data * @param {object} [environmentVars] used for passing implementation-specific of js version, if el & video was used in constructor slot & videoSlot will be added to the object * @param {NodeStyleCallback} callback */ VPAIDAdUnit.prototype.initAd = function initAd(width, height, viewMode, desiredBitrate, creativeData, environmentVars, callback) { creativeData = creativeData || {}; environmentVars = utils.extend({ slot: this._el, videoSlot: this._videoEl }, environmentVars || {}); setTimeout(function () { var error; try { this._creative.initAd(width, height, viewMode, desiredBitrate, creativeData, environmentVars); } catch (e) { error = e; } callOrTriggerEvent(callback, this._subscribers, error); }.bind(this), 0); }; /** * subscribe * * @param {string} event * @param {nodeStyleCallback} handler * @param {object} context */ VPAIDAdUnit.prototype.subscribe = function subscribe(event, handler, context) { this._subscribers.subscribe(handler, event, context); }; /** * unsubscribe * * @param {string} event * @param {nodeStyleCallback} handler */ VPAIDAdUnit.prototype.unsubscribe = function unsubscribe(event, handler) { this._subscribers.unsubscribe(handler, event); }; //alias VPAIDAdUnit.prototype.on = VPAIDAdUnit.prototype.subscribe; VPAIDAdUnit.prototype.off = VPAIDAdUnit.prototype.unsubscribe; IVPAIDAdUnit.GETTERS.forEach(function(getter) { VPAIDAdUnit.prototype[getter] = function (callback) { setTimeout(function () { var result, error = null; try { result = this._creative[getter](); } catch(e) { error = e; } callOrTriggerEvent(callback, this._subscribers, error, result); }.bind(this), 0); }; }); /** * setAdVolume * * @param volume * @param {nodeStyleCallback} callback */ VPAIDAdUnit.prototype.setAdVolume = function setAdVolume(volume, callback) { setTimeout(function () { var result, error = null; try { this._creative.setAdVolume(volume); result = this._creative.getAdVolume(); } catch(e) { error = e; } if (!error) { error = utils.validate(result === volume, 'failed to apply volume: ' + volume); } callOrTriggerEvent(callback, this._subscribers, error, result); }.bind(this), 0); }; VPAIDAdUnit.prototype._destroy = function destroy() { this.stopAd(); this._subscribers.unsubscribeAll(); }; function $addEventsSubscribers() { // some ads implement // so they only handle one subscriber // to handle this we create our one FILTERED_EVENTS.forEach(function (event) { this._creative.subscribe($trigger.bind(this, event), event); }.bind(this)); // map the click event to be an object instead of depending of the order of the arguments // and to be consistent with the flash this._creative.subscribe($clickThruHook.bind(this), AD_CLICK); // because we are adding the element inside the iframe // the user is not able to click in the video if (this._videoEl) { var documentElement = this._iframe.contentDocument.documentElement; var videoEl = this._videoEl; documentElement.addEventListener('click', function(e) { if (e.target === documentElement) { videoEl.click(); } }); } } function $clickThruHook(url, id, playerHandles) { this._subscribers.triggerSync(AD_CLICK, {url: url, id: id, playerHandles: playerHandles}); } function $trigger(event) { // TODO avoid leaking arguments // https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments this._subscribers.trigger(event, Array.prototype.slice(arguments, 1)); } function callOrTriggerEvent(callback, subscribers, error, result) { if (callback) { callback(error, result); } else if (error) { subscribers.trigger(ERROR, error); } } module.exports = VPAIDAdUnit;