kosx

ia_mraid_bridge

Jan 11th, 2021
727
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <script language='javascript' type='text/javascript'>
  2.   (function() {
  3.   // Establish the root mraidbridge object.
  4.   var mraidbridge = window.mraidbridge = {};
  5.   // Listeners for bridge events.
  6.   var listeners = {};
  7.   // Queue to track pending calls to the native SDK.
  8.   var nativeCallQueue = [];
  9.   // Whether a native call is currently in progress.
  10.   var nativeCallInFlight = false;
  11.   //////////////////////////////////////////////////////////////////////////////////////////////////
  12.   mraidbridge.windowLoaded = false;
  13.   window.addEventListener('load', function(e) { mraidbridge.windowLoaded = true });
  14.   mraidbridge.fireReadyEvent = function() {
  15.     mraidbridge.fireEvent('ready');
  16.   };
  17.   mraidbridge.fireChangeEvent = function(properties) {
  18.     mraidbridge.fireEvent('change', properties);
  19.   };
  20.   mraidbridge.fireErrorEvent = function(message, action) {
  21.     mraidbridge.fireEvent('error', message, action);
  22.   };
  23.   mraidbridge.fireEvent = function(type) {
  24.   console.log("mraidBridge: firing event of type: " + type);
  25.     var ls = listeners[type];
  26.     if (ls) {
  27.       var args = Array.prototype.slice.call(arguments);
  28.       args.shift();
  29.       var l = ls.length;
  30.       for (var i = 0; i < l; i++) {
  31.         ls[i].apply(null, args);
  32.       }
  33.     }
  34.   };
  35.   mraidbridge.nativeCallComplete = function(command) {
  36.     console.log("native Call complete: " + command);
  37.     if (nativeCallQueue.length === 0) {
  38.       nativeCallInFlight = false;
  39.       return;
  40.     }
  41.  
  42.     var nextCall = nativeCallQueue.pop();
  43.     window.location = nextCall;
  44.   };
  45.   mraidbridge.executeNativeCall = function(command) {
  46.     if (!mraidbridge.windowLoaded) {
  47.       console.log("rejecting native call, window onload has not been invoked");
  48.       return;
  49.     }
  50.     var call = 'mraid://' + command;
  51.     var key, value;
  52.     var isFirstArgument = true;
  53.     for (var i = 1; i < arguments.length; i += 2) {
  54.       key = arguments[i];
  55.       value = arguments[i + 1];
  56.       if (value === null) continue;
  57.       if (isFirstArgument) {
  58.         call += '?';
  59.         isFirstArgument = false;
  60.       } else {
  61.         call += '&';
  62.       }
  63.       call += encodeURIComponent(key) + '=' + encodeURIComponent(value);
  64.     }
  65.     if (nativeCallInFlight) {
  66.       nativeCallQueue.push(call);
  67.     } else {
  68.       nativeCallInFlight = true;
  69.       window.location = call;
  70.     }
  71.   };
  72.   //////////////////////////////////////////////////////////////////////////////////////////////////
  73.   mraidbridge.addEventListener = function(event, listener) {
  74.     var eventListeners;
  75.     listeners[event] = listeners[event] || [];
  76.     eventListeners = listeners[event];
  77.     for (var l in eventListeners) {
  78.       // LoadListener already registered, so no need to add it.
  79.       if (listener === l) return;
  80.     }
  81.     eventListeners.push(listener);
  82.   };
  83.   mraidbridge.removeEventListener = function(event, listener) {
  84.     if (listeners.hasOwnProperty(event)) {
  85.       var eventListeners = listeners[event];
  86.       if (eventListeners) {
  87.         var idx = eventListeners.indexOf(listener);
  88.         if (idx !== -1) {
  89.           eventListeners.splice(idx, 1);
  90.         }
  91.       }
  92.     }
  93.   };
  94.   }());
  95.   (function() {
  96.   var mraid = window.mraid = {};
  97.   var bridge = window.mraidbridge;
  98.               // Constants. ////////////////////////////////////////////////////////////////////////////////////
  99.               var VERSION = mraid.VERSION = '2.0';
  100.               var STATES = mraid.STATES = {
  101.     LOADING: 'loading',     // Initial state.
  102.     DEFAULT: 'default',
  103.     EXPANDED: 'expanded',
  104.     HIDDEN: 'hidden',
  105.     RESIZED: 'resized'
  106.   };
  107.               var EVENTS = mraid.EVENTS = {
  108.     ERROR: 'error',
  109.     INFO: 'info',
  110.     READY: 'ready',
  111.     STATECHANGE: 'stateChange',
  112.     VIEWABLECHANGE: 'viewableChange',
  113.     SIZECHANGE: 'sizeChange'
  114.   };
  115.               var PLACEMENT_TYPES = mraid.PLACEMENT_TYPES = {
  116.     UNKNOWN: 'unknown',
  117.     INLINE: 'inline',
  118.     INTERSTITIAL: 'interstitial'
  119.   };
  120.               // External MRAID state: may be directly or indirectly modified by the ad JS. ////////////////////
  121.               // Properties which define the behavior of an expandable ad.
  122.   var expandProperties = {
  123.     width: -1,
  124.     height: -1,
  125.     useCustomClose: false,
  126.     isModal: true,
  127.     lockOrientation: false
  128.   };
  129.   var hasSetCustomSize = false;
  130.   var hasSetCreativeSize = false;
  131.   var hasSetCreativeOffset = false;
  132.   var hasSetCustomClose = false;
  133.   var listeners = {};
  134.   // Internal MRAID state. Modified by the native SDK. /////////////////////////////////////////////
  135.   var state = STATES.LOADING;
  136.   var isViewable = false;
  137.   var screenSize = { width: -1, height: -1 };
  138.   var maxSize = { width: -1, height: -1 };
  139.   var adSize = { width: -1, height: -1 };
  140.    var currentPosition = {
  141.       x:0,
  142.       y:0,
  143.       width:0,
  144.       height:0
  145.    };
  146.     var mraidDefaultPosition = {
  147.       x:0,
  148.       y:0,
  149.       width:0,
  150.       height:0
  151.    };
  152.   // Properties which define the behavior of an resized ad.
  153.    var resizeProperties = {
  154.        width:-1,
  155.        height:-1,
  156.        customClosePosition:'top-right',
  157.        offsetX:0,
  158.        offsetY:0,
  159.        allowOffscreen:true
  160.    };
  161.   var orientationProperties = {
  162.     allowOrientationChange:true,
  163.     forceOrientation:'none'
  164.   };
  165.   var placementType = PLACEMENT_TYPES.UNKNOWN;
  166.   var supports = {
  167.     sms: false,
  168.     tel: false,
  169.     calendar: false,
  170.     storePicture: false,
  171.     inlineVideo: false
  172.   };
  173.               //////////////////////////////////////////////////////////////////////////////////////////////////
  174.   var EventListeners = function(event) {
  175.     this.event = event;
  176.     this.count = 0;
  177.     var listeners = {};
  178.     this.add = function(func) {
  179.       var id = String(func);
  180.       if (!listeners[id]) {
  181.         listeners[id] = func;
  182.         this.count++;
  183.       }
  184.     };
  185.     this.remove = function(func) {
  186.       var id = String(func);
  187.       if (listeners[id]) {
  188.         listeners[id] = null;
  189.         delete listeners[id];
  190.         this.count--;
  191.         return true;
  192.       } else {
  193.         return false;
  194.       }
  195.     };
  196.     this.removeAll = function() {
  197.       for (var id in listeners) {
  198.         if (listeners.hasOwnProperty(id)) this.remove(listeners[id]);
  199.       }
  200.     };
  201.     this.broadcast = function(args) {
  202.       var localListners = {}
  203.       for (var id in listeners) localListners[id] = listeners[id]
  204.       for (var id in localListners) {
  205.           if (localListners.hasOwnProperty(id)) localListners[id].apply({}, args);
  206.       }
  207.     };
  208.     this.toString = function() {
  209.       var out = [event, ':'];
  210.       for (var id in listeners) {
  211.         if (listeners.hasOwnProperty(id)) out.push('|', id, '|');
  212.       }
  213.       return out.join('');
  214.     };
  215.   };
  216.   var broadcastEvent = function() {
  217.     var args = new Array(arguments.length);
  218.     var l = arguments.length;
  219.     for (var i = 0; i < l; i++) args[i] = arguments[i];
  220.     var event = args.shift();
  221.     if (listeners[event]) listeners[event].broadcast(args);
  222.   };
  223.   var contains = function(value, array) {
  224.     for (var i in array) {
  225.       if (array[i] === value) return true;
  226.     }
  227.     return false;
  228.   };
  229.   var clone = function(obj) {
  230.     if (obj === null) return null;
  231.     var f = function() {};
  232.     f.prototype = obj;
  233.     return new f();
  234.   };
  235.   var stringify = function(obj) {
  236.     if (typeof obj === 'object') {
  237.       var out = [];
  238.       if (obj.push) {
  239.         // Array.
  240.         for (var p in obj) out.push(obj[p]);
  241.         return '[' + out.join(',') + ']';
  242.       } else {
  243.         // Other object.
  244.         for (var p in obj) out.push("'" + p + "': " + obj[p]);
  245.         return '{' + out.join(',') + '}';
  246.       }
  247.     } else return String(obj);
  248.   };
  249.   // Functions that will be invoked by the native SDK whenever a 'change' event occurs.
  250.   var changeHandlers = {
  251.     state: function(val) {
  252.       if (state === STATES.LOADING) {
  253.         broadcastEvent(EVENTS.INFO, 'Native SDK initialized.');
  254.       }
  255.       state = val;
  256.       broadcastEvent(EVENTS.INFO, 'Set state to ' + stringify(val));
  257.       broadcastEvent(EVENTS.STATECHANGE, state);
  258.     },
  259.     viewable: function(val) {
  260.       isViewable = val;
  261.       broadcastEvent(EVENTS.INFO, 'Set isViewable to ' + stringify(val));
  262.       broadcastEvent(EVENTS.VIEWABLECHANGE, isViewable);
  263.     },
  264.     placementType: function(val) {
  265.       broadcastEvent(EVENTS.INFO, 'Set placementType to ' + stringify(val));
  266.       placementType = val;
  267.     },
  268.     adSize: function(val) {
  269.       for (var key in val) {
  270.         if (val.hasOwnProperty(key)) adSize[key] = val[key];
  271.       }
  272.       if (!hasSetCustomSize) {
  273.         broadcastEvent(EVENTS.SIZECHANGE, adSize['width'], adSize['height']);
  274.       }
  275.     },
  276.     screenSize: function(val) {
  277.       broadcastEvent(EVENTS.INFO, 'Set screenSize to ' + stringify(val));
  278.       for (var key in val) {
  279.         if (val.hasOwnProperty(key)) screenSize[key] = val[key];
  280.       }
  281.       if (!hasSetCustomSize) {
  282.         expandProperties['width'] = screenSize['width'];
  283.         expandProperties['height'] = screenSize['height'];
  284.       }
  285.     },
  286.     maxSize: function(val) {
  287.       broadcastEvent(EVENTS.INFO, 'Set maxSize to ' + stringify(val));
  288.       for (var key in val) {
  289.         if (val.hasOwnProperty(key)) maxSize[key] = val[key];
  290.       }
  291.     },
  292.     currentPosition: function(val) {
  293.       broadcastEvent(EVENTS.INFO, 'Set currentPosition to ' + stringify(val));
  294.       for (var key in val) {
  295.         if (val.hasOwnProperty(key)) currentPosition[key] = val[key];
  296.       }
  297.  
  298.       broadcastEvent(EVENTS.SIZECHANGE, val.width, val.height);
  299.     },
  300.     expandProperties: function(val) {
  301.       broadcastEvent(EVENTS.INFO, 'Merging expandProperties with ' + stringify(val));
  302.       for (var key in val) {
  303.         if (val.hasOwnProperty(key)) expandProperties[key] = val[key];
  304.       }
  305.     },
  306.     resizeProperties: function(val) {
  307.       broadcastEvent(EVENTS.INFO, 'Merging resizeProperties with ' + stringify(val));
  308.       for (var key in val) {
  309.         if (val.hasOwnProperty(key)) resizeProperties[key] = val[key];
  310.       }
  311.     },
  312.     orientationProperties: function(val) {
  313.       broadcastEvent(EVENTS.INFO, 'Merging orientationProperties with ' + stringify(val));
  314.       for (var key in val) {
  315.         if (val.hasOwnProperty(key)) orientationProperties[key] = val[key];
  316.       }
  317.     },
  318.     supports: function(val) {
  319.       broadcastEvent(EVENTS.INFO, 'Set supports to ' + stringify(val));
  320.         supports = val;
  321.     }
  322.   };
  323.   var validate = function(obj, validators, action, merge) {
  324.     if (!merge) {
  325.       // Check to see if any required properties are missing.
  326.       if (obj === null) {
  327.         broadcastEvent(EVENTS.ERROR, 'Required object not provided.', action);
  328.         return false;
  329.       } else {
  330.         for (var i in validators) {
  331.           if (validators.hasOwnProperty(i) && obj[i] === undefined) {
  332.             broadcastEvent(EVENTS.ERROR, 'Object is missing required property: ' + i + '.', action);
  333.             return false;
  334.           }
  335.         }
  336.       }
  337.     }
  338.     for (var prop in obj) {
  339.       var validator = validators[prop];
  340.       var value = obj[prop];
  341.       if (validator && !validator(value)) {
  342.         // Failed validation.
  343.         broadcastEvent(EVENTS.ERROR, 'Value of property ' + prop + ' is invalid.',
  344.           action);
  345.         return false;
  346.       }
  347.     }
  348.     return true;
  349.   };
  350.   var expandPropertyValidators = {
  351.     width: function(v) { return !isNaN(v) && v >= 0; },
  352.     height: function(v) { return !isNaN(v) && v >= 0; },
  353.     useCustomClose: function(v) { return (typeof v === 'boolean'); },
  354.     lockOrientation: function(v) { return (typeof v === 'boolean'); }
  355.   };
  356.   var resizePropertyValidators = {
  357.     width: function(v) { return !isNaN(v) && v >= 0; },
  358.     height: function(v) { return !isNaN(v) && v >= 0; },
  359.     offsetX: function(v) { return !isNaN(v); },
  360.     offsetY: function(v) { return !isNaN(v); },
  361.     allowOffscreen: function(v) { return (typeof v === 'boolean'); }
  362.   };
  363.   var orientationPropertyValidators = {
  364.     allowOrientationChange: function(v) { return (typeof v === 'boolean'); },
  365.     forceOrientation: function(v) { return !isNaN(v)}
  366.   };
  367.               //////////////////////////////////////////////////////////////////////////////////////////////////
  368.   bridge.addEventListener('change', function(properties) {
  369.     for (var p in properties) {
  370.       if (properties.hasOwnProperty(p)) {
  371.         var handler = changeHandlers[p];
  372.         handler(properties[p]);
  373.       }
  374.     }
  375.   });
  376.   bridge.addEventListener('error', function(message, action) {
  377.     broadcastEvent(EVENTS.ERROR, message, action);
  378.   });
  379.   bridge.addEventListener('ready', function() {
  380.     broadcastEvent(EVENTS.READY);
  381.   });
  382.               //////////////////////////////////////////////////////////////////////////////////////////////////
  383.   mraid.addEventListener = function(event, listener) {
  384.    if (!event || !listener) {
  385.       broadcastEvent(EVENTS.ERROR, 'Both event and listener are required.', 'addEventListener');
  386.     } else if (!contains(event, EVENTS)) {
  387.       broadcastEvent(EVENTS.ERROR, 'Unknown MRAID event: ' + event, 'addEventListener');
  388.     } else {
  389.       if (!listeners[event]) listeners[event] = new EventListeners(event);
  390.       listeners[event].add(listener);
  391.     }
  392.   };
  393.   mraid.close = function() {
  394.     if (state === STATES.HIDDEN) {
  395.       broadcastEvent(EVENTS.ERROR, 'Ad cannot be closed when it is already hidden.',
  396.         'close');
  397.     } else bridge.executeNativeCall('close');
  398.   };
  399.   mraid.expand = function(URL) {
  400.     if (state !== STATES.DEFAULT) {
  401.       broadcastEvent(EVENTS.ERROR, 'Ad can only be expanded from the default state.', 'expand');
  402.     } else {
  403.       var args = ['expand'];
  404.                   if (mraid.getHasSetCustomClose()) {
  405.         args = args.concat(['shouldUseCustomClose', expandProperties.useCustomClose ? 'true' : 'false']);
  406.       }
  407.                   if (mraid.getHasSetCustomSize()) {
  408.         if (expandProperties.width >= 0 && expandProperties.height >= 0) {
  409.           args = args.concat(['w', expandProperties.width, 'h', expandProperties.height]);
  410.         }
  411.       }
  412.                   if (typeof expandProperties.lockOrientation !== 'undefined') {
  413.         args = args.concat(['lockOrientation', expandProperties.lockOrientation]);
  414.       }
  415.                   if (URL) {
  416.         args = args.concat(['url', URL]);
  417.       }
  418.                   bridge.executeNativeCall.apply(this, args);
  419.     }
  420.   };
  421.   mraid.getHasSetCustomClose = function() {
  422.       return hasSetCustomClose;
  423.   };
  424.   mraid.getHasSetCustomSize = function() {
  425.       return hasSetCustomSize;
  426.   };
  427.   mraid.getExpandProperties = function() {
  428.     var properties = {
  429.       width: expandProperties.width,
  430.       height: expandProperties.height,
  431.       useCustomClose: expandProperties.useCustomClose,
  432.       isModal: expandProperties.isModal
  433.     };
  434.     return properties;
  435.   };
  436.   mraid.getPlacementType = function() {
  437.     return placementType;
  438.   };
  439.   mraid.getState = function() {
  440.     return state;
  441.   };
  442.   mraid.getVersion = function() {
  443.     return mraid.VERSION;
  444.   };
  445.   mraid.isViewable = function() {
  446.     return isViewable;
  447.   };
  448.   mraid.open = function(URL) {
  449.     if (!URL) broadcastEvent(EVENTS.ERROR, 'URL is required.', 'open');
  450.     else bridge.executeNativeCall('open', 'url', URL);
  451.   };
  452.   mraid.removeEventListener = function(event, listener) {
  453.     if (!event) broadcastEvent(EVENTS.ERROR, 'Event is required.', 'removeEventListener');
  454.     else {
  455.       if (listener && (!listeners[event] || !listeners[event].remove(listener))) {
  456.         broadcastEvent(EVENTS.ERROR, 'LoadListener not currently registered for event.',
  457.           'removeEventListener');
  458.         return;
  459.       } else if (listeners[event]) listeners[event].removeAll();
  460.                   if (listeners[event] && listeners[event].count === 0) {
  461.         listeners[event] = null;
  462.         delete listeners[event];
  463.       }
  464.     }
  465.   };
  466.   mraid.setExpandProperties = function(properties) {
  467.     if (validate(properties, expandPropertyValidators, 'setExpandProperties', true)) {
  468.       if (properties.hasOwnProperty('width') || properties.hasOwnProperty('height')) {
  469.         hasSetCustomSize = true;
  470.       }
  471.                   if (properties.hasOwnProperty('useCustomClose')) hasSetCustomClose = true;
  472.                   var desiredProperties = ['width', 'height', 'useCustomClose', 'lockOrientation'];
  473.       var length = desiredProperties.length;
  474.       for (var i = 0; i < length; i++) {
  475.         var propname = desiredProperties[i];
  476.         if (properties.hasOwnProperty(propname)) expandProperties[propname] = properties[propname];
  477.       }
  478.     }
  479.   };
  480.   mraid.useCustomClose = function(shouldUseCustomClose) {
  481.     expandProperties.useCustomClose = shouldUseCustomClose;
  482.     hasSetCustomClose = true;
  483.     bridge.executeNativeCall('usecustomclose', 'shouldUseCustomClose', shouldUseCustomClose);
  484.   };
  485.               // MRAID 2.0 APIs ////////////////////////////////////////////////////////////////////////////////
  486.  
  487.   mraid.createCalendarEvent = function(parameters) {
  488.     CalendarEventParser.initialize(parameters);
  489.     if (CalendarEventParser.parse()) {
  490.       bridge.executeNativeCall.apply(this, CalendarEventParser.arguments);
  491.     } else {
  492.       broadcastEvent(EVENTS.ERROR, CalendarEventParser.errors[0], 'createCalendarEvent');
  493.     }
  494.   };
  495.   mraid.supports = function(feature) {
  496.     return supports[feature];
  497.   };
  498.   mraid.playVideo = function(uri) {
  499.     if (!mraid.isViewable()) {
  500.       broadcastEvent(EVENTS.ERROR, 'playVideo cannot be called until the ad is viewable', 'playVideo');
  501.       return;
  502.     }
  503.                 if (!uri) {
  504.       broadcastEvent(EVENTS.ERROR, 'playVideo must be called with a valid URI', 'playVideo');
  505.     } else {
  506.       bridge.executeNativeCall.apply(this, ['playVideo', 'uri', uri]);
  507.     }
  508.   };
  509.   mraid.storePicture = function(uri) {
  510.     if (!mraid.isViewable()) {
  511.       broadcastEvent(EVENTS.ERROR, 'storePicture cannot be called until the ad is viewable', 'storePicture');
  512.       return;
  513.     }
  514.     if (!uri) {
  515.       broadcastEvent(EVENTS.ERROR, 'storePicture must be called with a valid URI', 'storePicture');
  516.     } else {
  517.       bridge.executeNativeCall.apply(this, ['storePicture', 'uri', uri]);
  518.     }
  519.   };
  520.   mraid.resize = function() {
  521.     if (state !== STATES.DEFAULT) {
  522.       broadcastEvent(EVENTS.ERROR, 'Ad can only be expanded from the default state.', 'resize');
  523.     } else {
  524.       var args = ['resize'];
  525.       if (mraid.getHasSetCreativeSize()) {
  526.         if (resizeProperties.width >= 0 && resizeProperties.height >= 0) {
  527.           args = args.concat(['w', resizeProperties.width, 'h', resizeProperties.height]);
  528.         }
  529.       }
  530.       if (mraid.getHasSetCreativeOffset()) {
  531.         args = args.concat(['offsetX', resizeProperties.offsetX, 'offsetY', resizeProperties.offsetY]);
  532.       }
  533.       if (typeof resizeProperties.allowOffscreen !== 'undefined') {
  534.         args = args.concat(['allowOffscreen', resizeProperties.allowOffscreen]);
  535.       }
  536.       if (typeof resizeProperties.customClosePosition !== 'undefined') {
  537.         args = args.concat(['customClosePosition', resizeProperties.customClosePosition]);
  538.       }
  539.                   bridge.executeNativeCall.apply(this, args);
  540.     }
  541.   };
  542.   mraid.getResizeProperties = function() {
  543.     var properties = {
  544.       width: resizeProperties.width,
  545.       height: resizeProperties.height,
  546.       customClosePosition: resizeProperties.customClosePosition,
  547.       offsetX: resizeProperties.offsetX,
  548.       offsetY: resizeProperties.offsetY,
  549.       allowOffscreen: resizeProperties.allowOffscreen
  550.     };
  551.     return properties;
  552.   };
  553.   mraid.setResizeProperties = function(properties) {
  554.     if (validate(properties, resizePropertyValidators, 'setResizeProperties', true)) {
  555.       if (properties.hasOwnProperty('width') || properties.hasOwnProperty('height')) {
  556.         hasSetCreativeSize = true;
  557.       }
  558.       if (properties.hasOwnProperty('offsetX') || properties.hasOwnProperty('offsetY')) {
  559.         hasSetCreativeOffset = true;
  560.       }
  561.       if (properties.hasOwnProperty('useCustomClose')) hasSetCustomClose = true;
  562.       var desiredProperties = ['width', 'height', 'offsetX', 'offsetY', 'customClosePosition', 'allowOffscreen'];
  563.       var length = desiredProperties.length;
  564.       for (var i = 0; i < length; i++) {
  565.         var propname = desiredProperties[i];
  566.         if (properties.hasOwnProperty(propname)) resizeProperties[propname] = properties[propname];
  567.       }
  568.     }
  569.   };
  570.  
  571.   mraid.setOrientationProperties = function (properties) {
  572.     var args = ['setOrientationProperties'];
  573.  //   if (validate(properties, orientationPropertyValidators, 'setOrientationProperties', true)) {
  574.       var desiredProperties = ['allowOrientationChange', 'forceOrientation'];
  575.       var length = desiredProperties.length;
  576.       for (var i = 0; i < length; i++) {
  577.         var propname = desiredProperties[i];
  578.         if (properties.hasOwnProperty(propname)) orientationProperties[propname] = properties[propname];
  579.         args = args.concat([propname, orientationProperties[propname]]);
  580.       }
  581.  //   }
  582.  
  583.     bridge.executeNativeCall.apply(this, args);
  584.   };
  585.  
  586.   mraid.getHasSetCreativeSize = function() {
  587.       return hasSetCreativeSize;
  588.   };
  589.  
  590.   mraid.getHasSetCreativeOffset = function() {
  591.       return hasSetCreativeOffset;
  592.   };
  593.  
  594.   mraid.getOrientationProperties = function () {
  595.       return clone(orientationProperties);
  596.   };
  597.  
  598.   mraid.getCurrentPosition = function () {
  599.     return clone(currentPosition);
  600.   };
  601.  
  602.   mraid.getDefaultPosition = function() {
  603.     return clone(mraidDefaultPosition);
  604.   };
  605.  
  606.   mraid.getMaxSize = function() {
  607.     return clone(maxSize);
  608.   };
  609.  
  610.   mraid.getScreenSize = function() {
  611.     return clone(screenSize);
  612.   };
  613.  
  614.   var CalendarEventParser = {
  615.     initialize: function(parameters) {
  616.       this.parameters = parameters;
  617.       this.errors = [];
  618.       this.arguments = ['createCalendarEvent'];
  619.     },
  620.     parse: function() {
  621.       if (!this.parameters) {
  622.         this.errors.push('The object passed to createCalendarEvent cannot be null.');
  623.       } else {
  624.         this.parseDescription();
  625.         this.parseLocation();
  626.         this.parseSummary();
  627.         this.parseStartAndEndDates();
  628.         this.parseReminder();
  629.         this.parseRecurrence();
  630.         this.parseTransparency();
  631.       }
  632.       var errorCount = this.errors.length;
  633.       if (errorCount) {
  634.         this.arguments.length = 0;
  635.       }
  636.       return (errorCount === 0);
  637.     },
  638.     parseDescription: function() {
  639.       this._processStringValue('description');
  640.     },
  641.     parseLocation: function() {
  642.       this._processStringValue('location');
  643.     },
  644.     parseSummary: function() {
  645.       this._processStringValue('summary');
  646.     },
  647.     parseStartAndEndDates: function() {
  648.       this._processDateValue('start');
  649.       this._processDateValue('end');
  650.     },
  651.     parseReminder: function() {
  652.       var reminder = this._getParameter('reminder');
  653.       if (!reminder) {
  654.         return;
  655.       }
  656.       if (reminder < 0) {
  657.         this.arguments.push('relativeReminder');
  658.         this.arguments.push(parseInt(reminder) / 1000);
  659.       } else {
  660.         this.arguments.push('absoluteReminder');
  661.         this.arguments.push(reminder);
  662.       }
  663.     },
  664.     parseRecurrence: function() {
  665.       var recurrenceDict = this._getParameter('recurrence');
  666.       if (!recurrenceDict) {
  667.         return;
  668.       }
  669.       this.parseRecurrenceInterval(recurrenceDict);
  670.       this.parseRecurrenceFrequency(recurrenceDict);
  671.       this.parseRecurrenceEndDate(recurrenceDict);
  672.       this.parseRecurrenceArrayValue(recurrenceDict, 'daysInWeek');
  673.       this.parseRecurrenceArrayValue(recurrenceDict, 'daysInMonth');
  674.       this.parseRecurrenceArrayValue(recurrenceDict, 'daysInYear');
  675.       this.parseRecurrenceArrayValue(recurrenceDict, 'monthsInYear');
  676.     },
  677.     parseTransparency: function() {
  678.       var validValues = ['opaque', 'transparent'];
  679.                   if (this.parameters.hasOwnProperty('transparency')) {
  680.         var transparency = this.parameters['transparency'];
  681.         if (contains(transparency, validValues)) {
  682.           this.arguments.push('transparency');
  683.           this.arguments.push(transparency);
  684.         } else {
  685.           this.errors.push('transparency must be opaque or transparent');
  686.         }
  687.       }
  688.     },
  689.     parseRecurrenceArrayValue: function(recurrenceDict, kind) {
  690.       if (recurrenceDict.hasOwnProperty(kind)) {
  691.         var array = recurrenceDict[kind];
  692.         if (!array || !(array instanceof Array)) {
  693.           this.errors.push(kind + ' must be an array.');
  694.         } else {
  695.           var arrayStr = array.join(',');
  696.           this.arguments.push(kind);
  697.           this.arguments.push(arrayStr);
  698.         }
  699.       }
  700.     },
  701.     parseRecurrenceInterval: function(recurrenceDict) {
  702.       if (recurrenceDict.hasOwnProperty('interval')) {
  703.         var interval = recurrenceDict['interval'];
  704.         if (!interval) {
  705.           this.errors.push('Recurrence interval cannot be null.');
  706.         } else {
  707.           this.arguments.push('interval');
  708.           this.arguments.push(interval);
  709.         }
  710.       } else {
  711.         // If a recurrence rule was specified without an interval, use a default value of 1.
  712.         this.arguments.push('interval');
  713.         this.arguments.push(1);
  714.       }
  715.     },
  716.     parseRecurrenceFrequency: function(recurrenceDict) {
  717.       if (recurrenceDict.hasOwnProperty('frequency')) {
  718.         var frequency = recurrenceDict['frequency'];
  719.         var validFrequencies = ['daily', 'weekly', 'monthly', 'yearly'];
  720.         if (contains(frequency, validFrequencies)) {
  721.           this.arguments.push('frequency');
  722.           this.arguments.push(frequency);
  723.         } else {
  724.           this.errors.push("Recurrence frequency must be one of: 'daily, 'weekly', 'monthly', 'yearly'.");
  725.         }
  726.       }
  727.     },
  728.     parseRecurrenceEndDate: function(recurrenceDict) {
  729.       var expires = recurrenceDict['expires'];
  730.                   if (!expires) {
  731.         return;
  732.       }
  733.                   this.arguments.push('expires');
  734.       this.arguments.push(expires);
  735.     },
  736.     _getParameter: function(key) {
  737.       if (this.parameters.hasOwnProperty(key)) {
  738.         return this.parameters[key];
  739.       }
  740.                   return null;
  741.     },
  742.     _processStringValue: function(kind) {
  743.       if (this.parameters.hasOwnProperty(kind)) {
  744.         var value = this.parameters[kind];
  745.         this.arguments.push(kind);
  746.         this.arguments.push(value);
  747.       }
  748.     },
  749.     _processDateValue: function(kind) {
  750.       if (this.parameters.hasOwnProperty(kind)) {
  751.         var dateString = this._getParameter(kind);
  752.         this.arguments.push(kind);
  753.         this.arguments.push(dateString);
  754.       }
  755.     }
  756.   };
  757.   }());
  758.   </script>
RAW Paste Data