// // mraid.js // MRAID // // Created by Jay Tucker on 9/16/13. // Copyright (c) 2013 Nexage, Inc. All rights reserved. // (function() { /*************************************************************************** * console logging helper **************************************************************************/ var console = {}; console.log = function(msg) { if (typeof enableLog != 'undefined') { var iframe = document.createElement("IFRAME"); iframe.setAttribute("src", "console-log://" + msg); document.documentElement.appendChild(iframe); iframe.parentNode.removeChild(iframe); iframe = null; } }; LogLevelEnum = { "DEBUG" : 0, "INFO" : 1, "WARNING" : 2, "ERROR" : 3 } var logLevel = LogLevelEnum.DEBUG; var log = {}; log.d = function(msg) { if (logLevel <= LogLevelEnum.DEBUG) { console.log("(D) " + msg); } } log.i = function(msg) { if (logLevel <= LogLevelEnum.INFO) { console.log("(I) " + msg); } } log.w = function(msg) { if (logLevel <= LogLevelEnum.WARN) { console.log("(W) " + msg); } } log.e = function(msg) { console.log("(E) " + msg); } /*************************************************************************** * MRAID declaration **************************************************************************/ log.i("Setting up mraid object"); var mraid = window.mraid = {}; /*************************************************************************** * constants **************************************************************************/ var VERSION = "2.0"; var STATES = mraid.STATES = { "LOADING" : "loading", "DEFAULT" : "default", "EXPANDED" : "expanded", "RESIZED" : "resized", "HIDDEN" : "hidden" }; var PLACEMENT_TYPES = mraid.PLACEMENT_TYPES = { "INLINE" : "inline", "INTERSTITIAL" : "interstitial" }; var RESIZE_PROPERTIES_CUSTOM_CLOSE_POSITION = mraid.RESIZE_PROPERTIES_CUSTOM_CLOSE_POSITION = { "TOP_LEFT" : "top-left", "TOP_CENTER" : "top-center", "TOP_RIGHT" : "top-right", "CENTER" : "center", "BOTTOM_LEFT" : "bottom-left", "BOTTOM_CENTER" : "bottom-center", "BOTTOM_RIGHT" : "bottom-right" }; var ORIENTATION_PROPERTIES_FORCE_ORIENTATION = mraid.ORIENTATION_PROPERTIES_FORCE_ORIENTATION = { "PORTRAIT" : "portrait", "LANDSCAPE" : "landscape", "NONE" : "none" }; var EVENTS = mraid.EVENTS = { "ERROR" : "error", "READY" : "ready", "SIZECHANGE" : "sizeChange", "STATECHANGE" : "stateChange", "VIEWABLECHANGE" : "viewableChange", "SHAKE" : "shake", "TILTCHANGE" : 'tiltChange', "HEADINGCHANGE" : 'headingChange', "NETWORKCHANGE" : 'networkChange', "LOCATIONCHANGE" : 'locationChange', "KEYBOARDSTATECHANGE" : 'keyboardStateChange' }; var SUPPORTED_FEATURES = mraid.SUPPORTED_FEATURES = { "SMS" : "sms", "TEL" : "tel", "CALENDAR" : "calendar", "STOREPICTURE" : "storePicture", "INLINEVIDEO" : "inlineVideo" }; /*************************************************************************** * state **************************************************************************/ var state = STATES.LOADING; var placementType = PLACEMENT_TYPES.INLINE; var supportedFeatures = {}; var isViewable = false; var isResizeReady = false; var expandProperties = { "width" : 0, "height" : 0, "useCustomClose" : false, "isModal" : true }; var orientationProperties = { "allowOrientationChange" : true, "forceOrientation" : ORIENTATION_PROPERTIES_FORCE_ORIENTATION.NONE }; var resizeProperties = { "width" : 0, "height" : 0, "customClosePosition" : RESIZE_PROPERTIES_CUSTOM_CLOSE_POSITION.TOP_RIGHT, "offsetX" : 0, "offsetY" : 0, "allowOffscreen" : true }; var currentPosition = { "x" : 0, "y" : 0, "width" : 0, "height" : 0 }; var defaultPosition = { "x" : 0, "y" : 0, "width" : 0, "height" : 0 }; var maxSize = { "width" : 0, "height" : 0 }; var screenSize = { "width" : 0, "height" : 0 }; var currentOrientation = 0; var listeners = {}; /******************************** * Introduced for Pokkt ********************************/ var shakeProperties = { "interval" : 0, "intensity" : 0 }; var tiltProperties = { "interval" : 0, "intensity" : 0 }; var headingProperties = { "interval" : 0, "intensity" : 0 }; var locationProperties = { "interval" : 0, "distance" : 0 }; var tiltValues = { "x" : 0, "y" : 0, "z" : 0 }; var currentLocation = { "latitude" : 0.0, "longitude" : 0.0, "accuracy" : 0.0 }; var headingValue = 0; var currentNetwork = ""; var currentKeyboardState = 0; /*************************************************************************** * "official" API: methods called by creative **************************************************************************/ mraid.addEventListener = function(event, listener) { log.i("mraid.addEventListener " + event + ": " + String(listener)); if (!event || !listener) { mraid.fireErrorEvent("Both event and listener are required.", "addEventListener"); return; } if (!contains(event, EVENTS)) { mraid.fireErrorEvent("Unknown MRAID event: " + event, "addEventListener"); return; } var listenersForEvent = listeners[event] = listeners[event] || []; // check to make sure that the listener isn't already registered for (var i = 0; i < listenersForEvent.length; i++) { var str1 = String(listener); var str2 = String(listenersForEvent[i]); if (listener === listenersForEvent[i] || str1 === str2) { log.i("listener " + str1 + " is already registered for event " + event); return; } } listenersForEvent.push(listener); }; mraid.createCalendarEvent = function(parameters) { log.i("mraid.createCalendarEvent with " + parameters); callNative("createCalendarEvent?eventJSON="+JSON.stringify(parameters)); }; mraid.close = function() { log.i("mraid.close"); if (state === STATES.LOADING || (state === STATES.DEFAULT && placementType === PLACEMENT_TYPES.INLINE) || state === STATES.HIDDEN) { // do nothing return; } callNative("close"); }; mraid.expand = function(url) { if (url === undefined) { log.i("mraid.expand (1-part)"); } else { log.i("mraid.expand " + url); } // The only time it is valid to call expand is when the ad is // a banner currently in either default or resized state. if (placementType !== PLACEMENT_TYPES.INLINE || (state !== STATES.DEFAULT && state !== STAES.RESIZED)) { return; } if (url === undefined) { callNative("expand"); } else { callNative("expand?url=" + encodeURIComponent(url)); } }; mraid.getCurrentPosition = function() { log.i("mraid.getCurrentPosition"); return currentPosition; }; mraid.getDefaultPosition = function() { log.i("mraid.getDefaultPosition"); return defaultPosition; }; mraid.getExpandProperties = function() { log.i("mraid.getExpandProperties"); return expandProperties; }; mraid.getMaxSize = function() { log.i("mraid.getMaxSize " + maxSize.width + " x " + maxSize.height); return maxSize; }; mraid.getOrientationProperties = function() { log.i("mraid.getOrientationProperties"); return orientationProperties; }; mraid.getPlacementType = function() { log.i("mraid.getPlacementType"); return placementType; }; mraid.getResizeProperties = function() { log.i("mraid.getResizeProperties"); return resizeProperties; }; mraid.getScreenSize = function() { log.i("mraid.getScreenSize"); return screenSize; }; mraid.getState = function() { log.i("mraid.getState"); return state; }; mraid.getVersion = function() { log.i("mraid.getVersion"); return VERSION; }; mraid.isViewable = function() { log.i("mraid.isViewable"); return isViewable; }; mraid.open = function(url) { log.i("mraid.open " + url); callNative("open?url=" + encodeURIComponent(url)); }; mraid.playVideo = function(url) { log.i("mraid.playVideo " + url); callNative("playVideo?url=" + encodeURIComponent(url)); }; mraid.playAudio = function(url) { log.i("mraid.playAudio " + url); callNative("playAudio?url=" + encodeURIComponent(url)); }; mraid.openCamera = function () { log.i("mraid.openCamera"); callNative("openCamera"); } mraid.removeEventListener = function(event, listener) { log.i("mraid.removeEventListener " + event + " : " + String(listener)); if (!event) { mraid.fireErrorEvent("Event is required.", "removeEventListener"); return; } if (!contains(event, EVENTS)) { mraid.fireErrorEvent("Unknown MRAID event: " + event, "removeEventListener"); return; } if (listeners.hasOwnProperty(event)) { if (listener) { var listenersForEvent = listeners[event]; // try to find the given listener var len = listenersForEvent.length; for (var i = 0; i < len; i++) { var registeredListener = listenersForEvent[i]; var str1 = String(listener); var str2 = String(registeredListener); if (listener === registeredListener || str1 === str2) { listenersForEvent.splice(i, 1); break; } } if (i === len) { log.i("listener " + str1 + " not found for event " + event); } if (listenersForEvent.length === 0) { delete listeners[event]; } } else { // no listener to remove was provided, so remove all listeners for given event delete listeners[event]; } } else { log.i("no listeners registered for event " + event); } }; mraid.resize = function() { log.i("mraid.resize"); // The only time it is valid to call resize is when the ad is // a banner currently in either default or resized state. // Trigger an error if the current state is expanded. if (placementType === PLACEMENT_TYPES.INTERSTITIAL || state === STATES.LOADING || state === STATES.HIDDEN) { // do nothing return; } if (state === STATES.EXPANDED) { mraid.fireErrorEvent("mraid.resize called when ad is in expanded state", "mraid.resize"); return; } if (!isResizeReady) { mraid.fireErrorEvent("mraid.resize is not ready to be called", "mraid.resize"); return; } callNative("resize"); }; mraid.setExpandProperties = function(properties) { log.i("mraid.setExpandProperties"); if (!validate(properties, "setExpandProperties")) { log.e("failed validation"); return; } var oldUseCustomClose = expandProperties.useCustomClose; // expandProperties contains 3 read-write properties: width, height, and useCustomClose; // the isModal property is read-only var rwProps = [ "width", "height", "useCustomClose" ]; for (var i = 0; i < rwProps.length; i++) { var propname = rwProps[i]; if (properties.hasOwnProperty(propname)) { expandProperties[propname] = properties[propname]; } } // In MRAID v2.0, all expanded ads by definition cover the entire screen, // so the only property that the native side has to know about is useCustomClose. // (That is, the width and height properties are not needed by the native code.) if (expandProperties.useCustomClose !== oldUseCustomClose) { callNative("useCustomClose?useCustomClose=" + expandProperties.useCustomClose); } }; mraid.setOrientationProperties = function(properties) { log.i("mraid.setOrientationProperties"); if (!validate(properties, "setOrientationProperties")) { log.e("failed validation"); return; } var newOrientationProperties = {}; newOrientationProperties.allowOrientationChange = orientationProperties.allowOrientationChange, newOrientationProperties.forceOrientation = orientationProperties.forceOrientation; // orientationProperties contains 2 read-write properties: allowOrientationChange and forceOrientation var rwProps = [ "allowOrientationChange", "forceOrientation" ]; for (var i = 0; i < rwProps.length; i++) { var propname = rwProps[i]; if (properties.hasOwnProperty(propname)) { newOrientationProperties[propname] = properties[propname]; } } // Setting allowOrientationChange to true while setting forceOrientation to either portrait or landscape // is considered an error condition. if (newOrientationProperties.allowOrientationChange && newOrientationProperties.forceOrientation !== mraid.ORIENTATION_PROPERTIES_FORCE_ORIENTATION.NONE) { mraid.fireErrorEvent("allowOrientationChange is true but forceOrientation is " + newOrientationProperties.forceOrientation, "setOrientationProperties"); return; } orientationProperties.allowOrientationChange = newOrientationProperties.allowOrientationChange; orientationProperties.forceOrientation = newOrientationProperties.forceOrientation; var params = "allowOrientationChange=" + orientationProperties.allowOrientationChange + "&forceOrientation=" + orientationProperties.forceOrientation; callNative("setOrientationProperties?" + params); }; mraid.setResizeProperties = function(properties) { log.i("mraid.setResizeProperties"); isResizeReady = false; // resizeProperties contains 6 read-write properties: // width, height, offsetX, offsetY, customClosePosition, allowOffscreen // The properties object passed into this function must contain width, height, offsetX, offsetY. // The remaining two properties are optional. var requiredProps = [ "width", "height", "offsetX", "offsetY" ]; for (var i = 0; i < requiredProps.length; i++) { var propname = requiredProps[i]; if (!properties.hasOwnProperty(propname)) { mraid.fireErrorEvent( "required property " + propname + " is missing", "mraid.setResizeProperties"); return; } } if (!validate(properties, "setResizeProperties")) { mraid.fireErrorEvent("failed validation", "mraid.setResizeProperties"); return; } var adjustments = { "x": 0, "y": 0 }; var allowOffscreen = properties.hasOwnProperty("allowOffscreen") ? properties.allowOffscreen : resizeProperties.allowOffscreen; if (!allowOffscreen) { if (properties.width > maxSize.width || properties.height > maxSize.height) { mraid.fireErrorEvent("resize width or height is greater than the maxSize width or height", "mraid.setResizeProperties"); return; } adjustments = fitResizeViewOnScreen(properties); } else if (!isCloseRegionOnScreen(properties)) { mraid.fireErrorEvent("close event region will not appear entirely onscreen", "mraid.setResizeProperties"); return; } var rwProps = [ "width", "height", "offsetX", "offsetY", "customClosePosition", "allowOffscreen" ]; for (var i = 0; i < rwProps.length; i++) { var propname = rwProps[i]; if (properties.hasOwnProperty(propname)) { resizeProperties[propname] = properties[propname]; } } var params = "width=" + resizeProperties.width + "&height=" + resizeProperties.height + "&offsetX=" + (resizeProperties.offsetX + adjustments.x) + "&offsetY=" + (resizeProperties.offsetY + adjustments.y) + "&customClosePosition=" + resizeProperties.customClosePosition + "&allowOffscreen=" + resizeProperties.allowOffscreen; callNative("setResizeProperties?" + params); isResizeReady = true; }; mraid.storePicture = function(url) { log.i("mraid.storePicture " + url); callNative("storePicture?url=" + encodeURIComponent(url)); }; mraid.supports = function(feature) { log.i("mraid.supports " + feature + " " + supportedFeatures[feature]); var retval = supportedFeatures[feature]; if (typeof retval === "undefined") { retval = false; } return retval; }; mraid.useCustomClose = function(isCustomClose) { log.i("mraid.useCustomClose " + isCustomClose); if (expandProperties.useCustomClose !== isCustomClose) { expandProperties.useCustomClose = isCustomClose; callNative("useCustomClose?useCustomClose=" + expandProperties.useCustomClose); } }; /*************************************************************************** * helper methods called by SDK **************************************************************************/ // setters to change state mraid.setCurrentPosition = function(x, y, width, height) { log.i("mraid.setCurrentPosition " + x + "," + y + "," + width + "," + height); var previousSize = {}; previousSize.width = currentPosition.width; previousSize.height = currentPosition.height; log.i("previousSize " + previousSize.width + "," + previousSize.height); currentPosition.x = x; currentPosition.y = y; currentPosition.width = width; currentPosition.height = height; if (width !== previousSize.width || height !== previousSize.height) { mraid.fireSizeChangeEvent(width, height); } }; mraid.setDefaultPosition = function(x, y, width, height) { log.i("mraid.setDefaultPosition " + x + "," + y + "," + width + "," + height); defaultPosition.x = x; defaultPosition.y = y; defaultPosition.width = width; defaultPosition.height = height; }; mraid.setExpandSize = function(width, height) { log.i("mraid.setExpandSize " + width + "x" + height); expandProperties.width = width; expandProperties.height = height; }; mraid.setMaxSize = function(width, height) { log.i("mraid.setMaxSize " + width + "x" + height); maxSize.width = width; maxSize.height = height; }; mraid.setPlacementType = function(pt) { log.i("mraid.setPlacementType " + pt); placementType = pt; }; mraid.setScreenSize = function(width, height) { log.i("mraid.setScreenSize " + width + "x" + height); screenSize.width = width; screenSize.height = height; }; mraid.setSupports = function(feature, supported) { log.i("mraid.setSupports " + feature + " " + supported); supportedFeatures[feature] = supported; }; // methods to fire events mraid.fireErrorEvent = function(message, action) { log.i("mraid.fireErrorEvent " + message + " " + action); fireEvent(mraid.EVENTS.ERROR, message, action); }; mraid.fireReadyEvent = function() { log.i("mraid.fireReadyEvent"); fireEvent(mraid.EVENTS.READY); }; mraid.fireSizeChangeEvent = function(width, height) { log.i("mraid.fireSizeChangeEvent " + width + "x" + height); fireEvent(mraid.EVENTS.SIZECHANGE, width, height); }; mraid.fireStateChangeEvent = function(newState) { log.i("mraid.fireStateChangeEvent " + newState); if (state !== newState) { state = newState; fireEvent(mraid.EVENTS.STATECHANGE, state); } }; mraid.fireViewableChangeEvent = function(newIsViewable) { log.i("mraid.fireViewableChangeEvent " + newIsViewable); if (isViewable !== newIsViewable) { isViewable = newIsViewable; fireEvent(mraid.EVENTS.VIEWABLECHANGE, isViewable); } }; /** * Pokkt's extended methods **/ mraid.setShakeProperties = function(properties) { log.i("mraid.setShakeProperties: " + properties); if (!isNaN(properties.interval) && !isNaN(properties.intensity)) { shakeProperties = properties; callNative("setShakeProperties?properties=" + JSON.stringify(properties)); } }; mraid.getShakeProperties = function() { return shakeProperties; }; mraid.setTiltProperties = function(properties) { log.i("mraid.setTiltProperties: " + properties); if (!isNaN(properties.interval) && !isNaN(properties.intensity)) { headingProperties = properties; callNative("setTiltProperties?properties=" + JSON.stringify(properties)); } }; mraid.getTiltProperties = function() { return tiltProperties; } mraid.setHeadingProperties = function(properties) { log.i("mraid.setHeadingProperties: " + properties); if (!isNaN(properties.interval) && !isNaN(properties.intensity)) { headingProperties = properties; callNative("setHeadingProperties?properties=" + JSON.stringify(properties)); } }; mraid.getHeadingProperties = function() { return headingProperties; }; mraid.setLocationProperties = function (properties) { log.i("mraid.setLocationProperties: " + properties); if (!isNaN(properties.interval) && !isNaN(properties.distance)) { locationProperties = properties; callNative("setLocationProperties?properties=" + JSON.stringify(properties)); } }; mraid.getLocationProperties = function () { return locationProperties; }; mraid.setTiltProperties = function(properties) { log.i("mraid.setTiltProperties: " + properties); callNative("setTiltProperties?properties=" + JSON.stringify(properties)); }; mraid.fireShakeEvent = function() { log.i("mraid.fireShakeEvent"); fireEvent(mraid.EVENTS.SHAKE); } mraid.fireTiltChangeEvent = function(x, y, z) { log.i("mraid.fireTiltChangeEvent, x: " + x + " y: " + y + " z: " + z); fireEvent(mraid.EVENTS.TILTCHANGE, x, y, z); } mraid.fireHeadingChangeEvent = function(val) { log.i("mraid.fireHeadingChangeEvent, val: " + val); fireEvent(mraid.EVENTS.HEADINGCHANGE, val); } mraid.fireLocationChangeEvent = function(latitude, longitude, accuracy) { log.i("mraid.fireLocationChangeEvent, latitude: " + latitude + " longitude: " + longitude + " accuracy: " + accuracy); fireEvent(mraid.EVENTS.LOCATIONCHANGE, latitude, longitude, accuracy); } mraid.fireNetworkChangeEvent = function(network) { log.d("mraid.fireNetworkChangeEvent: " + network); fireEvent(mraid.EVENTS.NETWORKCHANGE, network); } mraid.fireKeyboardStateChangeEvent = function(state) { log.d("mraid.fireKeyboardStateChangeEvent: " + state); fireEvent(mraid.EVENTS.KEYBOARDSTATECHANGE, state); } mraid.getTilt = function () { return tiltValues; }; mraid.setTilt = function (newValue) { tiltValues = newValue; }; mraid.getNetwork = function () { return currentNetwork; }; mraid.setNetwork = function (newValue) { currentNetwork = newValue; }; mraid.getLocation = function () { return currentLocation; }; mraid.setLocation = function (newValue) { currentLocation = newValue; }; mraid.getHeading = function () { return headingValue; }; mraid.setHeading = function (newValue) { headingValue = newValue; }; mraid.getKeyboardState = function () { return currentKeyboardState; } mraid.setKeyboardState = function (newValue) { currentKeyboardState = newValue; } /*************************************************************************** * internal helper methods **************************************************************************/ var callNative = function(command) { var iframe = document.createElement("IFRAME"); iframe.setAttribute("src", "mraid://" + command); document.documentElement.appendChild(iframe); iframe.parentNode.removeChild(iframe); iframe = null; }; var fireEvent = function(event) { var args = Array.prototype.slice.call(arguments); args.shift(); log.i("fireEvent " + event + " [" + args.toString() + "]"); var eventListeners = listeners[event]; if (eventListeners) { var len = eventListeners.length; log.i(len + " listener(s) found"); for (var i = 0; i < len; i++) { eventListeners[i].apply(null, args); } } else { log.i("no listeners found"); } }; var contains = function(value, array) { for (var i in array) { if (array[i] === value) { return true; } } return false; }; // The action parameter is a string which is the name of the setter function which called this function // (in other words, setExpandPropeties, setOrientationProperties, or setResizeProperties). // It serves both as the key to get the the appropriate set of validating functions from the allValidators object // as well as the action parameter of any error event that may be thrown. var validate = function(properties, action) { var retval = true; var validators = allValidators[action]; for (var prop in properties) { var validator = validators[prop]; var value = properties[prop]; if (validator && !validator(value)) { mraid.fireErrorEvent("Value of property " + prop + " (" + value + ") is invalid", "mraid." + action); retval = false; } } return retval; }; var allValidators = { "setExpandProperties": { // In MRAID 2.0, the only property in expandProperties we actually care about is useCustomClose. // Still, we'll do a basic sanity check on the width and height properties, too. "width" : function(width) { return !isNaN(width); }, "height" : function(height) { return !isNaN(height); }, "useCustomClose" : function(useCustomClose) { return (typeof useCustomClose === "boolean"); } }, "setOrientationProperties": { "allowOrientationChange" : function(allowOrientationChange) { return (typeof allowOrientationChange === "boolean"); }, "forceOrientation" : function(forceOrientation) { var validValues = [ "portrait","landscape","none" ]; return validValues.indexOf(forceOrientation) !== -1; } }, "setResizeProperties": { "width" : function(width) { return !isNaN(width) && width >= 50; }, "height" : function(height) { return !isNaN(height) && height >= 50; }, "offsetX" : function(offsetX) { return !isNaN(offsetX); }, "offsetY" : function(offsetY) { return !isNaN(offsetY); }, "customClosePosition" : function(customClosePosition) { var validPositions = [ "top-left","top-center","top-right","center","bottom-left","bottom-center","bottom-right" ]; return validPositions.indexOf(customClosePosition) !== -1; }, "allowOffscreen" : function(allowOffscreen) { return (typeof allowOffscreen === "boolean"); } } }; function isCloseRegionOnScreen(properties) { log.d("isCloseRegionOnScreen"); log.d("defaultPosition " + defaultPosition.x + " " + defaultPosition.y); log.d("offset " + properties.offsetX + " " + properties.offsetY); var resizeRect = {}; resizeRect.x = defaultPosition.x + properties.offsetX; resizeRect.y = defaultPosition.y + properties.offsetY; resizeRect.width = properties.width; resizeRect.height = properties.height; printRect("resizeRect", resizeRect); var customClosePosition = properties.hasOwnProperty("customClosePosition") ? properties.customClosePosition : resizeProperties.customClosePosition; log.d("customClosePosition " + customClosePosition); var closeRect = { "width": 50, "height": 50 }; if (customClosePosition.search("left") !== -1) { closeRect.x = resizeRect.x; } else if (customClosePosition.search("center") !== -1) { closeRect.x = resizeRect.x + (resizeRect.width / 2) - 25; } else if (customClosePosition.search("right") !== -1) { closeRect.x = resizeRect.x + resizeRect.width - 50; } if (customClosePosition.search("top") !== -1) { closeRect.y = resizeRect.y; } else if (customClosePosition === "center") { closeRect.y = resizeRect.y + (resizeRect.height / 2) - 25; } else if (customClosePosition.search("bottom") !== -1) { closeRect.y = resizeRect.y + resizeRect.height - 50; } var maxRect = { "x": 0, "y": 0 }; maxRect.width = maxSize.width; maxRect.height = maxSize.height; return isRectContained(maxRect, closeRect); } function fitResizeViewOnScreen(properties) { log.d("fitResizeViewOnScreen"); log.d("defaultPosition " + defaultPosition.x + " " + defaultPosition.y); log.d("offset " + properties.offsetX + " " + properties.offsetY); var resizeRect = {}; resizeRect.x = defaultPosition.x + properties.offsetX; resizeRect.y = defaultPosition.y + properties.offsetY; resizeRect.width = properties.width; resizeRect.height = properties.height; printRect("resizeRect", resizeRect); var maxRect = { "x": 0, "y": 0 }; maxRect.width = maxSize.width; maxRect.height = maxSize.height; var adjustments = { "x": 0, "y": 0 }; if (isRectContained(maxRect, resizeRect)) { log.d("no adjustment necessary"); return adjustments; } if (resizeRect.x < maxRect.x) { adjustments.x = maxRect.x - resizeRect.x; } else if ((resizeRect.x + resizeRect.width) > (maxRect.x + maxRect.width)) { adjustments.x = (maxRect.x + maxRect.width) - (resizeRect.x + resizeRect.width); } log.d("adjustments.x " + adjustments.x); if (resizeRect.y < maxRect.y) { adjustments.y = maxRect.y - resizeRect.y; } else if ((resizeRect.y + resizeRect.height) > (maxRect.y + maxRect.height)) { adjustments.y = (maxRect.y + maxRect.height) - (resizeRect.y + resizeRect.height); } log.d("adjustments.y " + adjustments.y); resizeRect.x = defaultPosition.x + properties.offsetX + adjustments.x; resizeRect.y = defaultPosition.y + properties.offsetY + adjustments.y; printRect("adjusted resizeRect", resizeRect); return adjustments; } function isRectContained(containingRect, containedRect) { log.d("isRectContained"); printRect("containingRect", containingRect); printRect("containedRect", containedRect); return (containedRect.x >= containingRect.x && (containedRect.x + containedRect.width) <= (containingRect.x + containingRect.width) && containedRect.y >= containingRect.y && (containedRect.y + containedRect.height) <= (containingRect.y + containingRect.height)); } function printRect(label, rect) { log.d(label + " [" + rect.x + "," + rect.y + "]" + ",[" + (rect.x + rect.width) + "," + (rect.y + rect.height) + "]" + " (" + rect.width + "x" + rect.height + ")"); } mraid.dumpListeners = function() { var nEvents = Object.keys(listeners).length log.i("dumping listeners (" + nEvents + " events)"); for (var event in listeners) { var eventListeners = listeners[event]; log.i(" " + event + " contains " + eventListeners.length + " listeners"); for (var i = 0; i < eventListeners.length; i++) { log.i(" " + eventListeners[i]); } } }; }());