mraid-webtester
Version:
MRAID Web Tester
1,203 lines (1,042 loc) • 49.5 kB
JavaScript
/*
* Copyright (c) 2012 The mraid-web-tester project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
/*
* Code flow is
* (0) prepareMraidView initializes version and "supports" properties
INFO MRAID version 2.0
INFO placement type inline
INFO [sms,tel,calendar,storePicture,inlineVideo]
* (1) buttons on interface call renderAd() - Flight tab>ad fragment or renderHtmlAd - Flight tab>ad url
INFO rendering
INFO creating adWindow
* (.) onload event of new browser window
INFO adWindow loaded
* (2) render() calls initAdFrame()
INFO initializing ad frame
* (3) initAdFrame() calls initAdBridge() and loadHtml()
INFO initializing bridge object [object Object]
* (4) initAdBridge() calls
* (a) EventListeners.add for info reporting
INFO activating info
* (b) EventListeners.add for error reporting
INFO activating error
* (c) pushChange() for initialization of all other properties
INFO controller initialized
INFO setting state to loading
INFO setting screenSize to {'width':320,'height':480}
INFO setting orientation to 0
INFO setting size to {'width':320,'height':50}
INFO setting default position to {'width':320,'height':50,'y':0,'x':0}
INFO setting maxSize to {'width':320,'height':480}
INFO merging expandProperties with {'width':0,'height':0,'useCustomClose':false,'isModal':false}
INFO setting supports to [screen]
* (5) pushChange() calls the addEventListener() method in mraid-main.js
* (6) addEventListener() calls changeHandlers.[listener]
* (7) changeHandlers.state() through signalReady, send ready event
INFO activating ready
* (8) identification script loaded
INFO mraid.js identification script found
*/
(function() {
var mraidview = window.mraidview = {};
// CONSTANTS ///////////////////////////////////////////////////////////////
var VERSIONS = mraidview.VERSIONS = {
V1 : '1.0',
V2 : '2.0'
};
var PLACEMENTS = mraidview.PLACEMENTS = {
UNKNOWN : 'unknown',
INLINE : 'inline',
INTERSTITIAL : 'interstitial'
}
var STATES = mraidview.STATES = {
UNKNOWN :'unknown',
LOADING :'loading',
DEFAULT :'default',
RESIZED :'resized',
EXPANDED :'expanded',
HIDDEN :'hidden'
};
var EVENTS = mraidview.EVENTS = {
INFO :'info',
ORIENTATIONCHANGE :'orientationChange',
READY :'ready',
ERROR :'error',
STATECHANGE :'stateChange',
VIEWABLECHANGE :'viewableChange',
SIZECHANGE :'sizeChange',
};
var FEATURES = mraidview.FEATURES = {
SMS :'sms',
TEL :'tel',
CALENDAR :'calendar',
STOREPICTURE:'storePicture',
INLINEVIDEO :'inlineVideo'
};
// EVENT HANDLING ///////////////////////////////////////////////////////////////
var listeners = {};
var broadcastEvent = function() {
var args = new Array(arguments.length);
for (var i = 0; i < arguments.length; i++) args[i] = arguments[i];
var event = args.shift();
for (var key in listeners[event]) {
var handler = listeners[event][key];
handler.func.apply(handler.func.scope, args);
}
}
mraidview.broadcastEvent = broadcastEvent;
mraidview.addEventListener = function(event, listener, scope) {
var key = String(listener) + String(scope);
var map = listeners[event]
if (!map) {
map = {};
listeners[event] = map;
}
map[key] = {scope:(scope?scope:{}),func:listener};
};
mraidview.removeEventListener = function(event, listener, scope) {
var key = String(listener) + String(scope);
var map = listeners[event];
if (map) {
map[key] = null;
delete map[key];
}
};
// PRIVATE VARIABLES ///////////////////////////////////////////////////////////////
var
adURI = "",
adURIFragment = true,
adHtml = '',
useHtml = false;
adContent = '',
adWindow = null,
adWindowAdj = {x:0,y:0},
adFrame = null,
adFrameExpanded = null,
adContainer = null,
adResizeContainer = null,
adExpandedContainer = null,
closeEventRegion = null,
adBridge = null,
adController = null,
inactiveAdBridge = null,
inactiveAdController = null,
intervalID = null,
timeoutID = null,
active = {},
previousPosition = { x:0, y:0, width:0, height:0 },
previousState = null,
defaultWindowSize = null,
adContainerOrientation = -1,
counter = 10;
// MRAID state variables - shared with frame
var
state = STATES.LOADING,
screenSize = { width:0, height:0 },
size = { width:0, height:0 },
defaultPosition = { width:0, height:0, y:0, x:0 },
c = { width:0, height:0, y:0, x:0 },
maxSize = { width:0, height:0, x:0, y:0 },
expandProperties = { width:0, height:0, useCustomClose:false, isModal:false},
orientationProperties = { allowOrientationChange:true, forceOrientation:'none' },
resizeProperties = { initialized: false, validated: false, width:0, height:0, customClosePosition:'top-right', offsetX:undefined, offsetY:undefined, allowOffscreen:true},
supports = [],
version = VERSIONS.UNKNOWN,
placement = PLACEMENTS.UNKNOWN,
isViewable = false;
orientation = -1;
// PUBLIC ACCESSOR METHODS ///////////////////////////////////////////////////////////////
mraidview.getAdContent = function() {
return adContent;
};
mraidview.setScreenSize = function(width, height) {
screenSize.width = width;
screenSize.height = height;
orientation = (width >= height)?90:0;
adContainerOrientation = orientation;
};
mraidview.setDefaultPosition = function(x, y, width, height) {
defaultPosition.x = parseInt(x);
defaultPosition.y = parseInt(y);
defaultPosition.width = parseInt(width);
defaultPosition.height = parseInt(height);
currentPosition = defaultPosition;
};
mraidview.setMaxAdPosition= function(x, y, width, height) {
maxSize.x = x;
maxSize.y = y;
if (orientation % 180 === 0) {
maxSize.width = width;
maxSize.height = height;
} else {
maxSize.width = height;
maxSize.height = width;
}
};
mraidview.setAdURI = function(uri, fragment) {
adURI = uri;
adURIFragment = (fragment)?true:false;
};
mraidview.setUseHtml = function(useThisHtml, html) {
useHtml = useThisHtml;
if (useHtml) {
adHtml = html;
} else {
adHtml = '';
}
};
mraidview.resetSupports = function() {
supports = [];
};
mraidview.setSupports = function(feature, doesSupport) {
if (doesSupport) {
supports.push(feature);
broadcastEvent(EVENTS.INFO, stringify(supports));
}
};
mraidview.setVersion = function(value) {
mraidview.version = value;
broadcastEvent(EVENTS.INFO, 'MRAID version ' + value);
};
mraidview.setPlacement = function(value) {
placement = mraidview.placement = value;
broadcastEvent(EVENTS.INFO, 'placement type ' + value);
};
mraidview.setOffScreen = function(value) {
offscreen = value;
};
mraidview.rotateOrientation = function() {
mraidview.setOrientation(orientation = (orientation + 90) % 180);
};
mraidview.setOrientation = function (degree, forceOrientation) {
if (degree%90 !== 0) return;
if (!adWindow || !adWindow.document) return;
var body = adWindow.document.getElementsByTagName('body')[0],
maxDiv = adWindow.document.getElementById('maxArea');
maxDiv.style['-webkit-transform'] = '';
if (degree%180 === 0) { // Portrait
adWindow.resizeTo(defaultWindowSize.outerWidth, defaultWindowSize.outerHeight);
body.style.width = Math.min(screenSize.width, screenSize.height) + 'px';
body.style.height = Math.max(screenSize.width, screenSize.height) + 'px';
if (orientationProperties.forceOrientation === 'landscape' && (!orientationProperties.allowOrientationChange || forceOrientation)
&& (state === STATES.EXPANDED || placement === PLACEMENTS.INTERSTITIAL)) {
maxDiv.style['-webkit-transform'] = 'rotate(90deg)';
var dx = (maxSize.height - maxSize.width)/2;
updateAdSize({'width':maxSize.height,'height':maxSize.width,'x':maxSize.y-dx, 'y':maxSize.x+dx});
if (state === STATES.EXPANDED) {
setAdResizeContainerStyle((adExpandedContainer || adResizeContainer), {'width':maxSize.height,'height':maxSize.width,'x':0, 'y':0});
} else if (placement === PLACEMENTS.INTERSTITIAL) {
adContainer.style.width = defaultPosition.height + 'px';
adContainer.style.height = defaultPosition.width + 'px';
adContainer.style.top = defaultPosition.y + 'px';
adContainer.style.left = defaultPosition.x + 'px';
}
setAdOrientation(90);
} else {
updateAdSize(maxSize);
if (state === STATES.EXPANDED) {
setAdResizeContainerStyle((adExpandedContainer || adResizeContainer), {'width':maxSize.width,'height':maxSize.height,'x':0, 'y':0});
} else if (placement === PLACEMENTS.INTERSTITIAL) {
setContainerDefaultPosition();
}
setAdOrientation(0);
}
} else { // Landscape
var w = (defaultWindowSize.outerWidth - defaultWindowSize.innerWidth) + defaultWindowSize.innerHeight,
h = (defaultWindowSize.outerHeight - defaultWindowSize.innerHeight) + defaultWindowSize.innerWidth;
adWindow.resizeTo(w, h);
body.style.height = Math.min(screenSize.width, screenSize.height) + 'px';
body.style.width = Math.max(screenSize.width, screenSize.height) + 'px';
if (orientationProperties.forceOrientation === 'portrait' && (!orientationProperties.allowOrientationChange || forceOrientation)
&& (state === STATES.EXPANDED || placement === PLACEMENTS.INTERSTITIAL)) {
maxDiv.style['-webkit-transform'] = 'rotate(90deg)';
var dx = (maxSize.height - maxSize.width)/2;
updateAdSize({'width':maxSize.width,'height':maxSize.height,'x':maxSize.y+dx, 'y':maxSize.x-dx});
if (state === STATES.EXPANDED) {
setAdResizeContainerStyle((adExpandedContainer || adResizeContainer), {'width':maxSize.width,'height':maxSize.height,'x':0, 'y':0});
} else if (placement === PLACEMENTS.INTERSTITIAL) {
setContainerDefaultPosition();
}
setAdOrientation(0);
} else {
updateAdSize({'width':maxSize.height,'height':maxSize.width,'x':maxSize.x, 'y':maxSize.y})
if (state === STATES.EXPANDED) {
setAdResizeContainerStyle((adExpandedContainer || adResizeContainer), {'width':maxSize.height,'height':maxSize.width,'x':0, 'y':0});
} else if (placement === PLACEMENTS.INTERSTITIAL) {
adContainer.style.width = defaultPosition.height + 'px';
adContainer.style.height = defaultPosition.width + 'px';
adContainer.style.top = defaultPosition.y + 'px';
adContainer.style.left = defaultPosition.x + 'px';
}
setAdOrientation(90);
}
}
if (offscreen) {
adWindow.setNavigation();
}
};
mraidview.setDefaultWindowSize = function () {
defaultWindowSize = {};
if ((adWindow.outerHeight === 0 || adWindow.outerWidth === 0) && counter > 0) {
counter--;
setTimeout(mraidview.setDefaultWindowSize, 50);
}
if (orientation % 180 === 0) {
defaultWindowSize.outerWidth = adWindow.outerWidth;
defaultWindowSize.innerWidth = adWindow.innerWidth;
defaultWindowSize.outerHeight = adWindow.outerHeight;
defaultWindowSize.innerHeight = adWindow.innerHeight;
} else {
defaultWindowSize.innerWidth = adWindow.innerHeight;
defaultWindowSize.innerHeight = adWindow.innerWidth;
defaultWindowSize.outerWidth = defaultWindowSize.innerWidth + (adWindow.outerWidth - adWindow.innerWidth); // + (adWindow.outerHeight - adWindow.innerHeight);
defaultWindowSize.outerHeight = defaultWindowSize.innerHeight + (adWindow.outerHeight - adWindow.innerHeight);
}
};
// PUBLIC ACTION METHODS ///////////////////////////////////////////////////////////////
mraidview.render = function() {
broadcastEvent(EVENTS.INFO, 'rendering');
counter = 10;
if (!adFrame || !adWindow || !adWindow.document || !adFrame.contentWindow) {
broadcastEvent(EVENTS.INFO, 'creating adWindow');
adWindow = window.open((offscreen) ? 'safari/device-pages.html': 'safari/device.html', 'adWindow', 'left=1000,width='+screenSize.width+',height='+screenSize.height+',menubar=no,location=no,toolbar=no,status=no,personalbar=no,resizable=no,scrollbars=no,chrome=no,all=no');
adWindow.onload = function() {
broadcastEvent(EVENTS.INFO, 'adWindow loaded');
adWindowAdj.x = window.outerWidth - screenSize.width;
adWindowAdj.y = window.outerHeight - screenSize.height;
adWindow.document.getElementsByTagName('body')[0].style.width = screenSize.width + 'px';
adWindow.document.getElementsByTagName('body')[0].style.height = screenSize.height + 'px';
adContainer = adWindow.document.getElementById('adContainer');
adContainer.addEventListener('ViewableChange', function(e) {
changeViewable();
});
adResizeContainer = adWindow.document.getElementById('adResizeContainer');
adFrame = adWindow.document.getElementById('adFrame');
adFrame.contentWindow.orientation = 0; // Set initial orientation.
closeEventRegion = adWindow.document.getElementById('closeEventRegion');
closeEventRegion.addEventListener('click', closeAd);
window.setTimeout(function () { //timeout needed to get the actual window size
mraidview.setDefaultWindowSize();
if (offscreen) {
adWindow.setNavigation();
}
}, 250);
loadAd();
};
} else {
adWindow.close();
adWindow = null;
mraidview.render();
}
};
// PRIVATE METHODS ///////////////////////////////////////////////////////////////
var clone = function(obj) {
var f = function() {};
f.prototype = obj;
return new f();
};
var stringify = function(obj) {
if (typeof obj == 'object') {
if (obj.push) {
var out = [];
for (var p = 0; p < obj.length; p++) {
out.push(obj[p]);
}
return '[' + out.join(',') + ']';
} else {
var out = [];
for (var p in obj) {
out.push('\''+p+'\':'+obj[p]);
}
return '{' + out.join(',') + '}';
}
} else {
return String(obj);
}
};
var reset = function() {
adContent = '';
adBridge = null;
adController = null;
adFrame.style.display = 'block';
adContainer.style.display = 'block';
adResizeContainer.style.display = 'block';
intervalID = null;
timeoutID = null;
active = {};
size.width = defaultPosition.width;
size.height = defaultPosition.height;
previousPosition = { x:0, y:0, width:0, height:0 };
previousState = null;
state = STATES.DEFAULT;
expandProperties = { width:maxSize.width, height:maxSize.height, useCustomClose:false, isModal:false};
resizeProperties = { initialized: false, validated: false, width:0, height:0, customClosePosition:'top-right', offsetX:undefined, offsetY:undefined, allowOffscreen:true};
orientationProperties = {allowOrientationChange:true, forceOrientation:'none'};
orientation = (screenSize.width >= screenSize.height)?90:0;
version = VERSIONS.UNKNOWN;
currentPosition = { 'x':0, 'y':0, 'width':defaultPosition.width, 'height':defaultPosition.height };
isViewable = false;
};
var showMraidCloseButton = function(toggle) {
var closeDiv = closeEventRegion;
closeDiv.style.position = 'absolute';
if (toggle) {
closeDiv.style.top = '';
closeDiv.style.left = '';
closeDiv.style.bottom = '';
closeDiv.style.right = '';
closeDiv.style.width = '50px';
closeDiv.style.height = '50px';
closeDiv.style.display = 'none';
closeDiv.style.zIndex = getHighestZindex()+2;
closeDiv.style.cursor = 'pointer';
closeDiv.style.background = (expandProperties.useCustomClose) ? '': 'url("close.png") no-repeat 8px 8px';
if (state === STATES.RESIZED) {
closeDiv.style.background = '';
var pos = resizeProperties.customClosePosition;
if (/top/i.test(pos)) {
closeDiv.style.top = '0px';
} else if (/bottom/i.test(pos)) {
closeDiv.style.bottom = '0px';
} else {
closeDiv.style.top = [(resizeProperties.height - 50 ) / 2, 'px'].join('');
}
if (/left/i.test(pos)) {
closeDiv.style.left = '0px';
} else if (/right/i.test(pos)) {
closeDiv.style.right = '0px';
} else {
closeDiv.style.left = [(resizeProperties.width - 50 ) / 2, 'px'].join('');
}
} else {
closeDiv.style.top = '0';
closeDiv.style.right = '0';
}
closeDiv.style.display = 'block';
broadcastEvent (EVENTS.INFO, 'adding MRAID close button');
} else {
closeDiv.style.display = 'none';
broadcastEvent (EVENTS.INFO, 'removing MRAID close button');
}
};
var loadAd = function() {
reset();
if (adFrame.attachEvent) {
adFrame.attachEvent("onload", initAdFrame);
} else {
adFrame.onload = initAdFrame;
}
setContainerDefaultPosition(defaultPosition);
if (useHtml) {
var doc = adFrame.contentWindow.document;
doc.body.innerHTML = '<body style="margin: 0px;"><div id="_mraidCloseDiv" onclick="mraid.close()"></div><div id="adHtml"></div></body>';
doc.body.style.margin = '0px';
initAdFrame.call(adFrame);
} else {
if (adURIFragment) {
document.cookie = 'uri='+encodeURIComponent(adURI);
adFrame.contentWindow.location.replace('ad.html');
} else {
adFrame.contentWindow.location.replace(adURI);
}
}
if (orientation%180 === 0){
setMaxAdArea(maxSize);
} else {
setMaxAdArea({'width':maxSize.height, 'height': maxSize.width, 'x': maxSize.x, 'y': maxSize.y});
}
};
var loadHtml = function(adHtml) {
var doc = adFrame.contentWindow.document,
adDiv = doc.getElementById('adHtml'),
scripts,
scriptsCount,
script,
i;
if (!adHtml || !adDiv) {
return;
}
broadcastEvent(EVENTS.INFO, 'loading ad html');
adDiv.innerHTML = adHtml;
scripts = doc.body.getElementsByTagName("script");
scriptsCount = scripts.length;
for (i=0; i<scriptsCount; i++) {
script = doc.createElement('script');
script.type = "text/javascript";
if (scripts[i].src !== '') {
script.src = scripts[i].src;
} else {
script.text = scripts[i].text;
}
doc.body.appendChild(script);
}
};
var insertAdURI = function(newAdFrame, uri) {
var qs = 'htmlproxy.php?url=' + encodeURIComponent(uri),
success,
twoPartHtml = '';
success = (function () {
return function (data) {
var scripts = '<script type="text/javascript" src="mraidview-bridge.js"></script><script type="text/javascript" src="mraid-main.js"></script>',
headStart,
headEnd,
headContent = ''; // Grab the contents of the head. We'll add these later so we have time to initialize mraid before any inline scripts run.
twoPartHtml = data;
headStart = data.indexOf('<head>') + 6;
headEnd = data.indexOf('</head>');
headContent = data.substr(headStart, headEnd - headStart);
twoPartHtml = twoPartHtml.replace(headContent, scripts);
newAdFrame.src = 'javascript: ' + twoPartHtml;
if (newAdFrame.contentWindow.document.readyState === 'complete') {
init2PartAdFrame(headContent);
} else {
if (newAdFrame.attachEvent) {
newAdFrame.attachEvent("onload", function () {
init2PartAdFrame(headContent);
});
} else {
newAdFrame.onload = function () {
init2PartAdFrame(headContent);
};
}
}
if (adURIFragment) {
document.cookie = 'uri='+encodeURIComponent(uri);
}
};
})();
try {
if (window.jQuery !== undefined) {
jQuery.get(qs, success);
}
} catch(e) {
}
};
var setContainerDefaultPosition = function() {
adContainer.style.left = defaultPosition.x + 'px';
adContainer.style.top = defaultPosition.y + 'px';
adContainer.style.width = defaultPosition.width + 'px';
adContainer.style.height = defaultPosition.height + 'px';
};
var resizeAd = function() {
adContainer.style.overflow = 'visible';
var arcs = adResizeContainer.style;
arcs.position = 'absolute';
arcs.top = [resizeProperties.offsetY, 'px'].join('');
arcs.left = [resizeProperties.offsetX, 'px'].join('');
arcs.width = [resizeProperties.width, 'px'].join('');
arcs.height = [resizeProperties.height, 'px'].join('');
arcs['z-index'] = getHighestZindex()+1;
currentPosition.x = defaultPosition.x + resizeProperties.offsetX;
currentPosition.y = defaultPosition.y + resizeProperties.offsetY;
currentPosition.width = resizeProperties.width;
currentPosition.height = resizeProperties.height;
size.width = currentPosition.width = resizeProperties.width;
size.height = currentPosition.height = resizeProperties.height;
adBridge.pushChange({ 'currentPosition': currentPosition, 'size': size});
};
var setMaxAdArea = function (size) {
var maxDiv = adWindow.document.getElementById('maxArea');
maxDiv.style.width = [size.width, 'px'].join('');
maxDiv.style.height = [size.height, 'px'].join('');
maxDiv.style.position = 'absolute';
maxDiv.style.left = [size.x, 'px'].join('');
maxDiv.style.top = [size.y, 'px'].join('');
!adBridge || adBridge.pushChange({'maxSize': size});
};
var setExpandProperties = function(size){
!adBridge || adBridge.pushChange({'expandProperties': size});
};
var setAdResizeContainerStyle = function (resizeContainer, _maxSize) {
var acs = resizeContainer.style;
if (mraidview.version == VERSIONS.V2) {
if (adExpandedContainer) {
acs.left = [0, 'px'].join('');
acs.top = [0, 'px'].join('');
} else {
acs.left = ['-', defaultPosition.x, 'px'].join('');
acs.top = ['-', defaultPosition.y, 'px'].join('');
}
acs.width = [_maxSize.width, 'px'].join('');
acs.height = [_maxSize.height, 'px'].join('');
currentPosition.width = size.width = _maxSize.width;
currentPosition.height = size.height = _maxSize.height;
} else if (mraidview.version === VERSIONS.V1) {
var left = _maxSize.x + (_maxSize.width - expandProperties.width)/2,
top = _maxSize.y + (_maxSize.height - expandProperties.height)/2;
acs.left = [0, 'px'].join('');
acs.top = [0, 'px'].join('');
acs.width = [expandProperties.width, 'px'].join('');
acs.height = [expandProperties.height, 'px'].join('');
currentPosition.height = size.height = expandProperties.height;
currentPosition.width = size.width = expandProperties.width;
}
};
var resetDefaultSize = function () {
adResizeContainer.style.overflow = 'hidden';
var arcs = adResizeContainer.style;
arcs.position = 'static';
arcs.top = '0';
arcs.left = '0';
arcs.width = '100%';
arcs.height = '100%';
adContainer['z-index'] = 0;
size.width = currentPosition.width = defaultPosition.width;
size.height = currentPosition.height = defaultPosition.height;
adBridge.pushChange({'size': size});
};
var getSupports = function(feature) {
for (var i=0; i<supports.length; i++) {
if (supports[i] == feature) return true;
}
return false;
};
var getHighestZindex = function() {
var zi = 0,
eles = document.getElementsByTagName('*');
for (var i = 0, ele; ele = eles[i]; i++){
if (ele.style['z-index'] && parseInt(ele.style['z-index']) > zi) {
zi = parseInt(ele.style['z-index']);
}
}
return zi;
};
var endExpanded = function() {
if (adExpandedContainer) {
adResizeContainer.appendChild(closeEventRegion);
adExpandedContainer.parentNode.removeChild(adExpandedContainer);
adExpandedContainer = null;
adFrameExpanded = null;
} else {
resetDefaultSize();
}
mraidview.setOrientation(orientation);
};
var setResizeProperties = function(properties) {
resizeProperties.validated = false;
if (!properties || !properties.width || !properties.height) {
adFrame.contentWindow.broadcastEvent(EVENTS.ERROR, 'missing properties for setResizeProperties' , 'setResizeProperties');
}
var regex = new RegExp('^(((top|bottom)-(left|right|center))|center)$', 'i');
if (!regex.test(resizeProperties.customClosePosition)) {
resizeProperties.customClosePosition = 'top-left';
}
if (!properties.allowOffscreen) {
if (properties.width > maxSize.width || properties.height > maxSize.height) {
adFrame.contentWindow.broadcastEvent(EVENTS.ERROR, 'invalid properties for setResizeProperties: width or height is too big' , 'setResizeProperties');
} else {
var posX = Math.max(0, Math.min(maxSize.width - properties.width, defaultPosition.x + properties.offsetX)),
posY = Math.max(0, Math.min(maxSize.height - properties.height, defaultPosition.y + properties.offsetY));
properties.offsetX = posX - defaultPosition.x;
properties.offsetY = posY - defaultPosition.y;
properties.validated = true;
setResizePropertyValues(properties);
}
} else {
var pos = properties.customClosePosition,
closeOffsetX = 0,
closeOffsetY = 0,
closeTotalPositionX = 0,
closeTotalPositionY = 0;
if (/top/i.test(pos)) {
closeOffsetY = 0;
} else if (/bottom/i.test(pos)) {
closeOffsetY = properties.height-50;
} else {
closeOffsetY = properties.height/2-25;
}
if (/left/i.test(pos)) {
closeOffsetX = 0;
} else if (/right/i.test(pos)) {
closeOffsetX = properties.width-50;
} else {
closeOffsetX = properties.width/2-25;
}
closeTotalPositionX = defaultPosition.x + properties.offsetX + closeOffsetX;
closeTotalPositionY = defaultPosition.y + properties.offsetY + closeOffsetY;
if (closeTotalPositionX < 0 ||
closeTotalPositionX > maxSize.width - 50 ||
closeTotalPositionY < 0 ||
closeTotalPositionY > maxSize.height - 50) {
//broadcastEvent(EVENTS.ERROR, 'invalid properties for setResizeProperties' , 'setResizeProperties');
adFrame.contentWindow.broadcastEvent(EVENTS.ERROR, 'invalid properties for setResizeProperties', 'setResizeProperties');
} else {
properties.validated = true;
setResizePropertyValues(properties);
}
}
adBridge.pushChange({'resizeProperties':resizeProperties});
};
var setOrientationProperties = function (properties) {
if (!properties) return;
if (properties.forceOrientation) {
orientationProperties.forceOrientation = properties.forceOrientation;
if (defaultWindowSize === null) {
mraidview.setDefaultWindowSize();
}
mraidview.setOrientation(orientation, true);
}
if (typeof(properties.allowOrientationChange) === 'boolean') {
orientationProperties.allowOrientationChange = properties.allowOrientationChange;
}
};
var setResizePropertyValues = function(properties) {
for (var property in resizeProperties) {
if (properties && typeof (properties[property]) !== 'undefined' && properties[property] !== '')
resizeProperties[property] = properties[property];
}
if (resizeProperties.initialized === false) {
resizeProperties.initialized = true;
}
};
var closeAd = function () {
showMraidCloseButton(false);
if (state === STATES.DEFAULT) {
adBridge.broadcastEvent('hide');
state = STATES.HIDDEN;
adBridge.pushChange({'state':state});
} else if (state === STATES.EXPANDED) {
state = STATES.DEFAULT;
if (inactiveAdBridge) {
adBridge = inactiveAdBridge;
adController = inactiveAdController;
inactiveAdBridge = null;
adController = null;
}
/* If forceOrientation is enabled, we need to disable it and update our size and position properties. */
if (orientationProperties.forceOrientation === 'portrait' || orientationProperties.forceOrientation === 'landscape') {
orientationProperties = {'allowOrientationChange':true, 'forceOrientation':'none'};
adBridge.pushChange({'orientationProperties': orientationProperties});
}
adBridge.pushChange({'state':state});
endExpanded();
} else if (state === STATES.RESIZED) {
state = STATES.DEFAULT;
adBridge.pushChange({'state':state});
resetDefaultSize();
} else {
return;
}
adBridge.pushChange({'currentPosition':currentPosition});
repaintAdWindow();
};
var repaintAdWindow = function () {
if (!adWindow) return;
adWindow.resizeBy(-1,0);
adWindow.resizeBy(1,0);
};
var initAdBridge = function(bridge, controller) {
broadcastEvent(EVENTS.INFO, 'initializing bridge object ' + bridge + controller);
inactiveAdBridge = adBridge;
inactiveAdController = adController;
adBridge = bridge;
adController = controller;
if (placement === PLACEMENTS.INTERSTITIAL) {
showMraidCloseButton(true);
}
bridge.addEventListener('activate', function(service) {
active[service] = true;
}, this);
bridge.addEventListener('deactivate', function(service) {
if (active[service]) {
active[service] = false;
}
}, this);
bridge.addEventListener('expand', function(uri) {
if (state === STATES.HIDDEN || state === STATES.EXPANDED || state === STATES.UNKNOWN || state === STATES.LOADING) {
return;
}
state = STATES.EXPANDED;
showMraidCloseButton(true);
var ac = adResizeContainer;
acs = adResizeContainer.style,
topAdContainer = adContainer;
if (uri && uri !== '') {
state = STATES.LOADING;
adExpandedContainer = document.createElement('div');
adFrameExpanded = document.createElement('iframe');
adFrameExpanded.setAttribute('scrolling', 'no');
adFrameExpanded.setAttribute('frameborder', '0');
adFrameExpanded.setAttribute('id', 'adFrameExpanded');
adFrameExpanded.style.height = '100%';
adFrameExpanded.style.width = '100%';
adFrameExpanded.style.position = 'absolute';
adFrameExpanded.style.overflow = 'hidden';
adFrameExpanded.style.padding = '0px';
adFrameExpanded.style.margin = '0px';
adFrameExpanded.style.border = 'none';
adFrameExpanded.style['z-index'] = getHighestZindex()+1;
ac = adExpandedContainer;
acs = ac.style;
insertAdURI(adFrameExpanded, uri);
adExpandedContainer.appendChild(adFrameExpanded);
adExpandedContainer.appendChild(closeEventRegion);
adContainer.parentNode.appendChild(adExpandedContainer);
adExpandedContainer.style['z-index'] = getHighestZindex()+1;
topAdContainer = adFrameExpanded;
}
acs.position = 'absolute';
setAdResizeContainerStyle(ac, maxSize);
// topAdContainer['z-index'] = getHighestZindex()+1;
if (!uri || uri == '') {
adBridge.pushChange({'state':state, 'currentPosition': currentPosition, 'size': size });
broadcastEvent(EVENTS.INFO, 'expanding one-part ad');
repaintAdWindow();
} else {
broadcastEvent(EVENTS.INFO, 'expanding two-part ad: ' + uri);
}
mraidview.setOrientation(orientation, true);
}, this);
bridge.addEventListener('close', closeAd , this);
bridge.addEventListener('hide', function() {
adFrame.style.display = 'none';
adResizeContainer.disabled = 'none';
adContainer.style.display = 'none';
previousState = state;
state = STATES.HIDDEN;
adBridge.pushChange({ state:state, isViewable:false });
}, this);
bridge.addEventListener('show', function() {
adFrame.style.display = 'block';
adResizeContainer.style.display = 'block';
adContainer.style.display = 'block';
state = previousState;
adBridge.pushChange({ state:state });
}, this);
bridge.addEventListener('open', function(URL) {
broadcastEvent(EVENTS.INFO, 'opening ' + URL);
window.open(URL, '_blank', 'left=1000,width='+screenSize.width+',height='+screenSize.height+',menubar=no,location=no,toolbar=no,status=no,personalbar=no,resizable=no,scrollbars=no,chrome=no,all=no');
}, this);
bridge.addEventListener('playVideo', function(URL) {
broadcastEvent(EVENTS.INFO, 'playing ' + URL);
window.open(URL, '_blank');
}, this);
bridge.addEventListener('storePicture', function(URL) {
var allow = confirm('CONFIRM: Store this image to gallery?\nURL:' + URL);
if (allow) {
window.open('../imageDownload.php?imageUrl=' + URL);
broadcastEvent(EVENTS.INFO, 'storing the image ' + URL);
} else {
adFrame.contentWindow.broadcastEvent(EVENTS.ERROR, 'Permission denied by user', 'storePicture');
}
}, this);
bridge.addEventListener('resize', function(uri) {
if (state === STATES.EXPANDED) {
adFrame.contentWindow.broadcastEvent(EVENTS.ERROR, 'Can not expand a resized ad', 'resize');
return;
} else if (state === STATES.HIDDEN || state === STATES.UNKNOWN || state === STATES.LOADING) {
return;
}
state = STATES.RESIZED;
showMraidCloseButton(true);
resizeAd();
adBridge.pushChange({ 'state':state, 'currentPosition':currentPosition, 'size':size });
}, this);
bridge.addEventListener('setExpandProperties', function(properties) {
broadcastEvent(EVENTS.INFO, 'setting expand properties to ' + stringify(properties));
!properties.width || (expandProperties.width = properties.width);
!properties.height || (expandProperties.height = properties.height);
!properties.useCustomClose || (expandProperties.useCustomClose = properties.useCustomClose);
adBridge.pushChange({'expandProperties':expandProperties});
}, this);
bridge.addEventListener('setResizeProperties', function(properties) {
broadcastEvent(EVENTS.INFO, 'setting resize properties to ' + stringify(properties));
setResizeProperties(properties);
adBridge.pushChange({'resizeProperties':resizeProperties});
}, this);
bridge.addEventListener('createCalendarEvent', function(params) {
var allow = confirm('CONFIRM: Create this calendar event?\n' + stringify(params));
if (allow) {
broadcastEvent(EVENTS.INFO, 'creating event ' + stringify(params));
} else {
adFrame.contentWindow.broadcastEvent(EVENTS.ERROR, 'Permission denied by user', 'createCalendarEvent');
}
}, this);
bridge.addEventListener('setOrientationProperties', function(properties) {
broadcastEvent(EVENTS.INFO, 'setting orientation properties to ' + stringify(properties));
setOrientationProperties(properties);
adBridge.pushChange({'orientationProperties':orientationProperties});
}, this);
bridge.addEventListener('useCustomClose', function(useCustomCloseIndicator) {
broadcastEvent(EVENTS.INFO, 'setting useCustomClose properties to ' + stringify(useCustomCloseIndicator));
expandProperties.useCustomClose = !!useCustomCloseIndicator;
}, this);
controller.addEventListener('info', function(message) {
broadcastEvent(EVENTS.INFO, message);
}, this);
controller.addEventListener('error', function(message) {
broadcastEvent(EVENTS.ERROR, message);
}, this);
var initProps = {
state:STATES.LOADING,
screenSize:screenSize,
orientation:orientation,
size:size,
defaultPosition:defaultPosition,
maxSize:maxSize,
expandProperties:expandProperties,
resizeProperties:resizeProperties,
orientationProperties:orientationProperties,
supports:supports,
version:mraidview.version,
placement:mraidview.placement,
currentPosition:defaultPosition,
isViewable:isAdViewAble()
};
bridge.pushChange({version:mraidview.version});
bridge.pushChange(initProps);
if (!!inactiveAdBridge) {
state = STATES.EXPANDED;
mraidview.setOrientation(orientation, true);
bridge.pushChange({'state':state, 'currentPosition': currentPosition });
repaintAdWindow();
}
bridge.pushChange({ state:state });
};
var initAdFrame = function() {
if (this.detachEvent) {
this.detachEvent("onload", initAdFrame);
} else {
this.onload = '';
}
broadcastEvent(EVENTS.INFO, 'initializing ad frame');
var win = this.contentWindow,
doc = win.document,
adScreen = {};
for (var prop in win.screen) {
if (prop !== 'width' && prop !== 'height') {
adScreen[prop] = win.screen[prop];
}
}
adScreen.width = screenSize.width;
adScreen.height = screenSize.height;
win.screen = adScreen;
var bridgeJS = doc.createElement('script');
bridgeJS.setAttribute('type', 'text/javascript');
bridgeJS.setAttribute('src', 'mraidview-bridge.js');
doc.getElementsByTagName('head')[0].appendChild(bridgeJS);
intervalID = win.setInterval(function() {
if (win.mraidview) {
win.clearInterval(intervalID);
var mraidJS = doc.createElement('script');
mraidJS.setAttribute('type', 'text/javascript');
mraidJS.setAttribute('src', 'mraid-main.js');
doc.getElementsByTagName('head')[0].appendChild(mraidJS);
intervalID = win.setInterval(function() {
if (win.mraid) {
win.clearInterval(intervalID);
window.clearTimeout(timeoutID);
initAdBridge(win.mraidview, win.mraid);
loadHtml(adHtml);
}
}, 30);
}
}, 30);
};
/**
* init2PartAdFrame initializes the second ad frame used by two-part ads.
*/
var init2PartAdFrame = function(headContent) {
if (this.detachEvent) {
this.detachEvent("onload", init2PartAdFrame);
} else {
this.onload = '';
}
broadcastEvent(EVENTS.INFO, 'initializing ad frame for part 2');
var win = adFrameExpanded.contentWindow,
doc = win.document,
adScreen = {};
function loadPartTwo() {
var headDump = doc.createElement('div'),
script,
scripts,
scriptsCount,
i;
headDump.id = 'headDump';
doc.querySelector('body').appendChild(headDump);
headDump.innerHTML = headContent;
scripts = headDump.getElementsByTagName("script");
scriptsCount = scripts.length;
for (i=0; i<scriptsCount; i++) {
script = doc.createElement('script');
script.type = "text/javascript";
if (scripts[i].src !== '') {
script.src = scripts[i].src;
} else {
var text = scripts[i].text.replace(/\\'/g, "'");
script.text = text;
}
doc.body.appendChild(script);
}
}
for (var prop in win.screen) {
if (prop !== 'width' && prop !== 'height') {
adScreen[prop] = win.screen[prop];
}
}
adScreen.width = screenSize.width;
adScreen.height = screenSize.height;
win.screen = adScreen;
intervalID = win.setInterval(function() {
if (win.mraidview) {
win.clearInterval(intervalID);
intervalID = win.setInterval(function() {
if (win.mraid) {
win.clearInterval(intervalID);
window.clearTimeout(timeoutID);
initAdBridge(win.mraidview, win.mraid);
loadPartTwo();
}
}, 30);
}
}, 30);
};
var changeViewable = function (toggle) {
if (!isViewable && isAdViewAble()) {
isViewable = true;
adBridge.pushChange({ 'isViewable': isViewable});
if (inactiveAdBridge) inactiveAdBridge.pushChange({'isViewable': isViewable});
} else if (isViewable && !isAdViewAble()) {
isViewable = false;
adBridge.pushChange({ 'isViewable': isViewable});
if (inactiveAdBridge) inactiveAdBridge.pushChange({'isViewable': isViewable});
}
};
var isAdViewAble = function () {
var viewableAttr = adContainer.getAttribute('data-isViewable');
return ((typeof(viewableAttr) === 'string' && viewableAttr === 'true') || (typeof(viewableAttr) === 'boolean' && viewableAttr));
};
var setAdOrientation = function (degree) {
if (adContainerOrientation !== degree) {
adContainerOrientation = degree;
/*
* The code below has been commented for two reasons:
* 1. The device should always report the correct orientation, so we don't want to override the
* window.orientation property.
* 2. There is no MRAID orientation api, so we don't need to trigger an orientationchange event. This code is here
* as legacy from when MRAID orientation was under consideration.
* ---
* UPDATE: 7/1/2014
* Because we state that it is the creative's responsibility to ensure that the close button is not off-screen, we need to provide
* an orientationchange event so that any listeners they might be using to meet this responsibility after an orientation change can respond as intended.
*/
adFrame.contentWindow.orientation = degree;
var orientationChangeEvent = adFrame.contentWindow.document.createEvent('HTMLEvents');
orientationChangeEvent.initEvent('orientationchange', false, false);
adFrame.contentWindow.dispatchEvent(orientationChangeEvent);
//adBridge.pushChange({'size': size, 'orientation': adContainerOrientation, 'currentPosition': currentPosition});
currentPosition = {'x': currentPosition.y, 'y': (maxSize.width - expandProperties.width - currentPosition.x), 'width': currentPosition.height, 'height': currentPosition.width};
adBridge.pushChange({'size': size, 'orientation': adContainerOrientation, 'currentPosition': currentPosition});
}
};
var updateAdSize = function(val){
setMaxAdArea(val);
setExpandProperties(val);
};
})();