Share this result

Previews are deleted daily. Get a permanent share link sent to your inbox:
Script
<!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> <title>Gas South Light Up</title> <script src="//media.admob.com/api/v1/google_mobile_app_ads.js"></script> <!-- <script src="mraid.js"></script> --> <script> var labAd = { adCond: null, mode: null, meta: { jiraID: 'tcl7165', //Example: The name of the JIRA ID projectName: 'DUAL:THOR Gas South Light Up - Q3 24', //CVS Stores Preseason (Week Ahead SPON) advertiser: 'GAS SOUTH', // Ex: 'mcdonalds' placement: '', // Ex: 'ros-shopper-moms' created: '10-18-2024', // Ex: '08-23-2018' modified: '', // change when base code changes to current date of change designer: 'eciprian', // Ex: 'coreyd' dev: 'jjvillanueva' //Ex: 'dks' }, product: { productName: 'MAIM - Mobile App Integrated Marquee (Animated)', // Abrev. + Full name of Product version: 'v1.3.3', //This will reflect the Github Version on the stable branch type: 'animated', // 'static', 'animated' interactive: '', // EX: 'locator', 'vertical-video', 'swipe-carousel', etc. adaptor: 'base-conditions', //EX: 'temp-range', 'temp-comparison', 'countdown', etc. milliBGImages: true, //EX: true, false - THOR CHANGE - MILLI ASSETS milliFGImages: false, //EX: true, false - THOR CHANGE - MILLI ASSETS dimensions: { ad: { //default for milli devices sm: { width: 320, height: 190 }, //THOR CHANGE - AD SIZE //default for kilo devices md: { width: 360, height: 190 }, //THOR CHANGE - AD SIZE lg: { width: 360, height: 190 }, //THOR CHANGE - AD SIZE xl: { width: 360, height: 190 } //THOR CHANGE - AD SIZE }, bg: { //default for milli devices sm: { width: 500, height: 720 }, //THOR CHANGE - BG SIZE //default for kilo devices md: { width: 500, height: 720 }, //THOR CHANGE - BG SIZE lg: { width: 500, height: 720 }, //THOR CHANGE - BG SIZE xl: { width: 500, height: 720 } //THOR CHANGE - BG SIZE } }, platforms: ['android', 'ios']// 'ios', 'android', 'web', 'mw' }, appBg: { // object passed to AppEvent - do not add new properties to this object. baseURL: '', imgID: '' }, appBgVid: { // object passed to AppEvent - do not add new properties to this object. vidURL: '47ab603a-7ecb-42a6-afa6-d26524aea659/500x720-bg-cld-dmezz_HVEC_2mbs.mp4' // Ex:'414x210-clear_day@1x.mp4' - @1x filename only for initial assignment. labAd.dir prepended before sending to app event. }, deviceSize: 'sm', // sm, md, lg, xl dir: 'https://v.w-x.co/digital_video/The_Weather_Channel_-_Reach_Engine/', dpr: window.devicePixelRatio, //THOR CHANGE - foreground foregroundElements: { addFg: false, // Set to true if Foreground element is needed | False if no Foreground element is needed fimg: '' // using transparent png since everything is baked into BG image }, default: { cnd: 'cld', dynght: 'D', img: 'https://s.w-x.co/cl/test/1x1_test.png', // using transparent png since everything is baked into BG image previewMode: 'o', reason: 'na' // 'na' is default }, displayed: false, // flag indicating showAd or showDefault has executed successfully. selected: { // for tracking selected values adImages: [], bgEvent: 'adBgVid', // Ex: 'adBg' or 'adBgVid' - set based on ad concept. scenario: 'na' }, els: {}, errors: [], imgs: {}, log: logInfo, logLevel: 1, // 0 = none, 1 = labAd, 2 = everything logs: [], macros: { // macros populated by GAM when ad is served cnd: "%%PATTERN:cnd%%", // current condition. dynght: "%%PATTERN:dynght%%", // day or night? Possible values: 'D', 'N' height: "%%HEIGHT%%", // ad slot height width: "%%WIDTH%%", // ad slot width plat: "%%PATTERN:plat%%", // platform. Used for tracking timeframe: "%%PATTERN:tf%%", // timeframe. Used for tracking gamClick: "%%CLICK_URL_UNESC%%", // Google Ad Manager click track URL gamPreview: '%%PREVIEW_MODE%%', cid: "%ecid!", // creative id lid: "%eaid!", // line item id ord: '%%CACHEBUSTER%%' }, preview: { //THOR CHANGE - previewMode css: { id: 'previewCSS', href: 'preview-im-ani-thor.css', dir: 'hostedcss' }, dirs: { hostedAssets: 'https://s.w-x.co/cl/wxcl/preview-mode/thor/im/', hostedjs: 'https://s.w-x.co/cl/wxcl/preview-mode/thor/im/', hostedcss: 'https://s.w-x.co/cl/wxcl/preview-mode/thor/im/', localAssets: 'preview-mode/assets/', localjs: 'preview-mode/js/', localcss: 'preview-mode/css/' }, images: [ // NOTE: images.src values use split('-'). Extraneous '-' in filenames will cause issues. // Standard Preview Images & Conditions { id: 'logo', type: 'logo', src: 'all-logo-watson-ads.png', dir: 'hostedAssets' }, { id: 'device', type: 'device', src: 'lg-device.png', dir: 'hostedAssets' }, //for devices uis' //THOR CHANGE - previewMode { id: 'ui-clr+D', type: 'ui', src: 'light-lg-ui-clear-day.png', dir: 'hostedAssets' }, { id: 'ui-clr+N', type: 'ui', src: 'light-lg-ui-clear-night.png', dir: 'hostedAssets' }, { id: 'ui-cld+D', type: 'ui', src: 'light-lg-ui-cloudy-day.png', dir: 'hostedAssets' }, { id: 'ui-cld+N', type: 'ui', src: 'light-lg-ui-cloudy-night.png', dir: 'hostedAssets' }, { id: 'ui-rain+D', type: 'ui', src: 'light-lg-ui-rainy-day.png', dir: 'hostedAssets' }, { id: 'ui-rain+N', type: 'ui', src: 'light-lg-ui-rainy-night.png', dir: 'hostedAssets' }, { id: 'ui-snow+D', type: 'ui', src: 'light-lg-ui-snowy-day.png', dir: 'hostedAssets' }, { id: 'ui-snow+N', type: 'ui', src: 'light-lg-ui-snowy-night.png', dir: 'hostedAssets' } ], //THOR CHANGE - previewMode //textMode should be set to 'dark' for daytime conditions //and should be set to 'light' for nighttime conditions by default. //This value can be changed per campaign if needed. textMode: { clrD: 'dark', clrN: 'light', cldD: 'dark', cldN: 'light', rainD: 'dark', rainN: 'light', snowD: 'dark', snowN: 'light' } }, promises: {}, test: {}, time: { log: {}, stamp: 0 // most recent getTime. Updated when logTime is called. }, tracking: { clickTag: 'https://arttrk.com/pixel/?ad_log=ua-00040002-91728328435450&tag=fclick&msg=uid=%%CACHEBUSTER%%%7Crev=1%7Cdfp_ctrk=%eaid!!%ecid!!adxcel!%ebuy!!Gas_South_Q4_2024&pixid=8f898adb-7dea-467d-a64b-c46ad27f468a&consumer_id=%%ADVERTISING_IDENTIFIER_PLAIN%%&enc_url=https%3A%2F%2Fservedby.flashtalking.com%2Fclick%2F8%2F251900%3B8782477%3B4930844%3B211%3B0%2F%3Fgdpr%3D%24%7BGDPR%7D%26gdpr_consent%3D%24%7BGDPR_CONSENT_78%7D%26us_privacy%3D%26url%3D39973030', // Ex: 3rd party click tracker // >>>>>keyword_ INSERT TRACKING HERE<<<<< imp3rdParty1: '', imp3rdParty2: '', imp3rdParty3: '' } } function initAd() { try { // init date & time labAd.time.date = new Date(); logTime('initAd'); // init labAd props and els - especially those needed for tracking and timing operations labAd.els.labAdDiv = document.getElementById('labAdDiv'); labAd.els.labTracking = document.getElementById('labTracking'); // request overall tracking. getImpPixel(labAd.tracking.imp3rdParty1, 'imp-3rdParty1', false); getImpPixel(labAd.tracking.imp3rdParty2, 'imp-3rdParty2', false); getImpPixel(labAd.tracking.imp3rdParty3, 'imp-3rdParty3', false); // get ad mode to determine if vars populated by macros or test hash labAd.mode = getAdMode(); // populate vars from the correct source for mode initAdMode(labAd.mode); // determine adCond based on cnd and dynght values labAd.adCond = labAd.macros.cnd + '-' + labAd.macros.dynght; // init loader method for scripts, imgs and link els initLoader(); // if Preview Mode, load resources needed, then init Preview Mode. if (labAd.mode === 'preview' || labAd.mode === 'gamPreview') { // group loader calls in array so they share the same callback var sPathjs = labAd.preview.dirs.hostedjs; // .standard, .customDir or .local var sPathcss = labAd.preview.dirs.hostedcss; // .standard, .customDir or .local var aPreviewPromises = [ //THOR CHANGE - previewMode labAd.loader.js({ src: sPathjs + 'preview-im-ani-thor.js', append: true }), labAd.loader.css({ src: sPathcss + 'preview-im-ani-thor.css', append: true }) ]; // use promise.all to execute callback when all promises are fulfilled labAd.promises.previewResources = Promise.all(aPreviewPromises).then(function (result) { // log success result labAd.log({ label: 'aPreviewPromises fulfilled. ', detail: result, type: 'log' }); // complete init PreviewMode now that resources are loaded labAd.preview.init(); }).catch(function (err) { labAd.log({ label: 'aPreviewPromises file load error: ', detail: err, type: 'error', isFatal: true }); }); } else { // else proceed to display using ad served initDisplay(labAd.adCond); } } catch (err) { labAd.log({ label: 'initAd error: ', detail: err, type: 'error', isFatal: true }); } } function initAdMode(sMode) { try { var result = ''; // Cases below should define adjustments needed for test modes supported by ad. switch (sMode) { case 'preview': case 'gamPreview': // clear GAM click macro so clicks will work in test modes labAd.macros.gamClick = ""; // assign values from HashParts - hash order is adstest + cnd + dynght + deviceSize + DPR + previewMode labAd.macros.cnd = labAd.test.HashParts[1]; labAd.macros.dynght = labAd.test.HashParts[2].toUpperCase(); labAd.deviceSize = labAd.test.HashParts[3].toLowerCase(); // get dpr from hash if not undefined, otherwise use window property labAd.dpr = (labAd.test.HashParts[4] !== undefined) ? Number(labAd.test.HashParts[4]) : window.devicePixelRatio; // adjust meta height if (labAd.deviceSize !== 'sm') { labAd.meta.width = 360; } break; default: // covers 'live' and 'none' labAd.deviceSize = getDeviceSize(); break; } // log result result = labAd.mode + ' activated'; labAd.log({ label: 'initAdMode ', detail: result, type: 'log' }); } catch (err) { labAd.log({ label: 'initAdMode error: ', detail: err, type: 'error', isFatal: false }); } } function initDisplay(sCond) { logTime('initDisplay'); try { // start the display routine by firing appEvent, selecting files, loading AD & BG images // fire adIM event asap so the app knows to push the feed card down fireAppEvent('adIM', {}); // select files needed for AD & BG display. labAd.selected = fileSelection(sCond); // 1: showBg - should be called first since it cannot be preloaded. // labAd.selected.bg properties will be used to package & send . showBg(labAd.selected.bg); // create an array of img promises to be loaded together labAd.promises.adImages = []; // create a loader.img instance for each selected img labAd.selected.adImages.forEach(function (imgObj) { // add each individual promise to the collection labAd.promises.adImages.push(labAd.loader.img(imgObj)); }); // use promise.all to execute callback when all promises are fulfilled labAd.promises.allAdImages = Promise.all(labAd.promises.adImages).then(function (aLoadedImages) { // log success aLoadedImages labAd.log({ label: 'labAd.promises.allAdImages fulfilled. ', detail: aLoadedImages, type: 'log' }); // call showAd and pass the successfully loaded Image els that still // need to be added to the DOM showAd(aLoadedImages); }).catch(function (err) { labAd.log({ label: 'labAd.promises.allAdImages file load error: ', detail: err, type: 'error', isFatal: true }); }); labAd.log({ label: 'initDisplay ', detail: sCond, type: 'log' }); } catch (err) { labAd.log({ label: 'initDisplay error: ', detail: err, type: 'error', isFatal: false }); } } function initLoader() { try { // initLoader: creates labAd.loader - which is a method that returns a function for loading resources using a Promise to determine success or failure. Currently supports script, link & img els. All different types can be loaded with the same callback. logTime('initLoader'); labAd.loader = (function () { // Function which returns a function: https://davidwalsh.name/javascript-functions function _load(tag) { return function (loadObj) { // This promise will be used by Promise.all to determine success or failure return new Promise(function (resolve, reject) { var element; var parent = 'body'; var attr = 'src'; // Adjust element type & attributes depending on tag type switch (tag) { case 'img': element = new Image(); element.id = loadObj.id; element.src = loadObj.src; break; case 'script': element = document.createElement(tag); element.async = true; break; case 'link': element = document.createElement(tag); element.type = 'text/css'; element.rel = 'stylesheet'; attr = 'href'; parent = 'head'; break; } // Important success and error for the promise element.onload = function () { labAd.log({ label: tag + ' loaded ', detail: { lO: loadObj, el: element, t: tag }, type: 'log' }); // resolve the promise & return the element resolve(element); }; element.onerror = function (err) { labAd.errors.push(err); reject(err); }; // if append is true, element needs to be added to DOM immediately // doing this & applying src will cause the resource to load but // the Promise controls what happens next. if (loadObj.append) { // apply the source & add to DOM element[attr] = loadObj.src; document[parent].appendChild(element); } }); }; } return { css: _load('link'), js: _load('script'), img: _load('img') } })(); labAd.log({ label: 'initLoader ', detail: labAd.loader, type: 'log' }); } catch (err) { labAd.log({ label: 'initLoader error: ', detail: err, type: 'error', isFatal: false }); } } function exitClick(event) { try { event.preventDefault(); var id = event.target.id; var url = labAd.tracking.clickTag; var target = "_blank"; var clickTime = logTime('exitClick'); var btnPos = labAd.els.btnInv.getBoundingClientRect(); labAd.log({ label: 'exitClick from: ' + id, detail: url, type: 'log' }); // launch clickthrough window window.open(labAd.macros.gamClick + url, target); } catch (err) { labAd.log({ label: 'exitClick error: ', detail: err, type: 'error', isFatal: false }); } } function fileSelection(sCond) { try { // selected is a return object containing all relevant details needed to // complete the ad display process. var selected = { adImages: [], // array of AD images to be loaded bg: { eventName: '', // string name AppEvent: 'adBg' or 'adBgVid' fileName: '', // string filename of the selected BG image or video logicalWidth: 500, // logical (aka 1x) width of BG asset - THOR CHANGE - BG SIZE logicalHeight: 720,// logical (aka 1x) height of BG asset - THOR CHANGE - BG SIZE loopCount: 3, // number of times to loop BG video textMode: 'dark' //EX: 'light', 'dark' THOR CHANGE - textMode }, scenario: '' // string name representing the selected scenario }; ///////////////////////////////////////////////////////// // 1: Assign values used for most or all scenarios // ///////////////////////////////////////////////////////// // NOTE: since there's only one image in the AD region for this creative, // its also assigned as the static default - which is why the line below // references that instead of just using the filename string. Also, the // id is being set to 'btnInv' so it will inherit the click handler that // that might be assigned to a transparent png in a more complex ad. selected.adImages.push(imgObj('btnInv', labAd.default.img)); selected.bg.eventName = 'adBgVid'; //THOR CHANGE - foreground ///TOGGLE FOR ADDING FOREGROUND ELEMENT(S)// var fgele = labAd.foregroundElements.addFg; if (fgele === true) { selected.adImages.push(imgObj('fgGrid', labAd.foregroundElements.fimg, labAd.product.dimensions.ad[labAd.deviceSize].width)); } else if (fgele === false) { //DONT PUSH ANYTHING TO THE DOM }; ////////////////////////////////////////////// // 2: Assign BG image/video to appBg or appBgVid // ////////////////////////////////////////////// sCond = sCond.toLowerCase(); switch (sCond) { case 'sun-d': case 'clr-d': selected.scenario = 'Clear Day'; selected.bg.fileName = '9eb42665-d188-49de-a518-90ef9e06c26f/500x720-bg-clr-dmezz_HVEC_2mbs.mp4'; selected.bg.textMode = labAd.preview.textMode.clrD; //THOR CHANGE - textMode break; case 'sun-n': case 'clr-n': selected.scenario = 'Clear Night'; selected.bg.fileName = 'b66d9f38-55b7-4720-a3cf-2fd6e9272004/500x720-bg-clr-nmezz_HVEC_2mbs.mp4'; selected.bg.textMode = labAd.preview.textMode.clrN; //THOR CHANGE - textMode break; case 'cld-n': case 'pcld-n': selected.scenario = 'Cloudy Night'; selected.bg.fileName = '733b1d7b-8283-485a-bf20-d83fda15326e/500x720-bg-cld-nmezz_HVEC_2mbs.mp4'; selected.bg.textMode = labAd.preview.textMode.cldN; //THOR CHANGE - textMode break; case 'rain-d': case 'thdr-d': selected.scenario = 'Rainy Day'; selected.bg.fileName = '371efb78-1545-40d8-a09f-08787d09f494/500x720-bg-rain-dmezz_HVEC_2mbs.mp4'; selected.bg.textMode = labAd.preview.textMode.rainD; //THOR CHANGE - textMode break; case 'rain-n': case 'thdr-n': selected.scenario = 'Rainy Night'; selected.bg.fileName = '73a6a270-55dd-4a81-9e1a-1db410e129d9/500x720-bg-rain-nmezz_HVEC_2mbs.mp4'; selected.bg.textMode = labAd.preview.textMode.rainN; //THOR CHANGE - textMode break; case 'snow-d'://Wintery Day case 'ice-d': //Ice Day selected.scenario = 'Wintry/Icy Day'; selected.bg.fileName = 'd936b416-f74d-4156-ac5c-6c5459ed0a9e/500x720-bg-snow-dmezz_HVEC_2mbs.mp4'; selected.bg.textMode = labAd.preview.textMode.snowD; //THOR CHANGE - textMode break; case 'snow-n'://Wintery Night case 'ice-n': //Ice Night selected.scenario = 'Wintry/Icy Night'; selected.bg.fileName = '42dfb55c-dd3f-4289-8c47-3db9f1b71d21/500x720-bg-snow-nmezz_HVEC_2mbs.mp4'; selected.bg.textMode = labAd.preview.textMode.snowN; //THOR CHANGE - textMode break; default: //Kylie Prevatt - 03/31/22 //Added conditional logic to display correct D/N version of default creative if (labAd.macros.dynght === 'n' || labAd.macros.dynght === 'N') { selected.scenario = 'Cloudy Night - default: ' + sCond; selected.bg.fileName = '733b1d7b-8283-485a-bf20-d83fda15326e/500x720-bg-cld-nmezz_HVEC_2mbs.mp4'; selected.bg.textMode = labAd.preview.textMode.cldN; //THOR CHANGE - textMode } else { selected.scenario = 'Cloudy Day - default: ' + sCond; selected.bg.fileName = '47ab603a-7ecb-42a6-afa6-d26524aea659/500x720-bg-cld-dmezz_HVEC_2mbs.mp4'; selected.bg.textMode = labAd.preview.textMode.cldD; //THOR CHANGE - textMode } break; } // process selected BG filename dimensions by passing through setSrcSize selected.bg.fileName = setSrcSize(selected.bg.fileName); //////////////////////////////////////// // 3: Apply logical BG img dimensions // //////////////////////////////////////// if (labAd.deviceSize !== 'sm') { selected.bg.logicalWidth = 500; selected.bg.logicalHeight = 720; //THOR CHANGE - BG SIZE } // log results labAd.log({ label: 'fileSelection ', detail: selected, type: 'log' }); /////////////////////////////////// // 4: return object with details // /////////////////////////////////// return selected; } catch (err) { labAd.log({ label: 'fileSelection error: ', detail: err, type: 'error', isFatal: true }); } } function fireAppEvent(sEventName, oProps) { try { logTime('fireAppEvent-' + sEventName); // stringify oProps object for use in dispatchAppEvent var payload = JSON.stringify(oProps); admob.events.dispatchAppEvent(sEventName, payload); labAd.log({ label: 'fireAppEvent ' + sEventName, detail: oProps, type: 'log' }); } catch (err) { labAd.log({ label: 'fireAppEvent error: ' + sEventName, detail: err, type: 'error', isFatal: false }); } } function getImpPixel(sURL, sEventName) { try { var regexp = /(https?:\/\/[^\s]+)/g; // begins with http:// or https:// if (regexp.exec(sURL)) { // if url is valid, add tracking pixel to labTracking var pixel = document.createElement('img'); pixel.src = sURL; pixel.alt = sEventName; // add new img to tracking div labAd.els.labTracking.appendChild(pixel); // log success labAd.log({ label: 'getImpPixel: ' + sEventName, detail: pixel, type: 'log' }); } else { // log error for invalid URL. var eO = { message: 'sEventName: ' + sEventName }; labAd.log({ label: 'getImpPixel - invalid URL: ' + sURL, detail: eO, type: 'error', isFatal: false }); } } catch (err) { labAd.log({ label: 'getImpPixel error: ', detail: err, type: 'error', isFatal: false }); } } function getAdMode() { try { labAd.test.HashParts = getTestHash(); // if the zero index === adstest, we go into test mode if (labAd.test.HashParts[0] === "adstest") { labAd.test.mode = 'preview'; } else if (labAd.macros.gamPreview === 'true') { // Macro will return true for GAM Creative Preview. Original macro token will be intact during local dev. labAd.test.mode = 'gamPreview'; } else { labAd.test.mode = 'live'; } labAd.log({ label: 'getAdMode: ' + labAd.test.mode, detail: labAd.test, type: 'log' }); return labAd.test.mode; } catch (err) { labAd.log({ label: 'getAdMode error: ', detail: err, type: 'error', isFatal: true }); } } function getDeviceSize() { try { // return a value for labAd.deviceSize based on WIDTH of ad slot size // requested. For milli devices, size will be 320x190. All other devices // will be 360x190. // default to small & adjust up if needed var sz = 'sm'; if (labAd.macros.width !== '320') { // if macro width is not small, return lg sz = 'lg'; // TODO: any reason (aside from PreviewMode) to pass md or xl? // adjust meta width labAd.meta.width = labAd.macros.width; } labAd.log({ label: 'getDeviceSize ', detail: sz, type: 'log' }); return sz; } catch (err) { labAd.log({ label: 'getDeviceSize error: ', detail: err, type: 'error', isFatal: false }); } } function getTestHash() { try { // expected format & order #adstest + cnd + dynght + deviceSize + dpr labAd.test.hashStr = top.window.location.hash.substring(1); // if this is a local file or gamPreview ith no adstest hash, assign default // hashStr value to eliminate need to manually add it to url if ((top.window.location.protocol === 'file:' || labAd.macros.gamPreview === 'true') && labAd.test.hashStr.indexOf('adstest') === -1) { // get actual deviceSize based on macro value to use as defualt labAd.deviceSize = getDeviceSize(); // build array of default values mapped to labAd props so changes are automatically picked up here labAd.test.defaultHashParts = ['adstest', labAd.default.cnd, labAd.default.dynght, labAd.deviceSize, labAd.dpr, labAd.default.previewMode,]; // set the missing hash by joining parts of this array to assemble default adstest hash string top.window.location.hash = labAd.test.defaultHashParts.join('+'); // now get and use the hashtring labAd.test.hashStr = top.window.location.hash.substring(1); labAd.log({ label: 'getTestHash defaultHashParts', detail: labAd.test.defaultHashParts, type: 'log' }); } // split hash string on '+' delimiter labAd.test.hashArray = labAd.test.hashStr.split("+"); // validate by filtering out empty values: "", undefined labAd.test.hashArrayFiltered = labAd.test.hashArray.filter(function (el) { return el !== null && el !== ""; }); labAd.log({ label: 'getTestHash ', detail: labAd.test.hashArrayFiltered, type: 'log' }); // return validated and sanitized array of #adstest hash values return labAd.test.hashArrayFiltered; } catch (err) { labAd.log({ label: 'getTestHash error: ', detail: err, type: 'error', isFatal: false }); } } function imgDPR(sFilename) { try { // apply img name based on devicePixelRatio (or argument representing dpr) // assuming all base filenames should contain '@1x' var imgName = decodeURIComponent(sFilename); var adjusted = 'not adjusted.'; if (imgName.indexOf('@') !== -1) { // if decoded filename contains @ symbol // make DPR adjustments using string replacement if (labAd.dpr > 3) { // greater than triple density imgName = imgName.replace('@1x', '@4x'); adjusted = 'adjusted to 4x.'; } else if (labAd.dpr > 2 && labAd.dpr <= 3) { // triple density imgName = imgName.replace('@1x', '@3x'); adjusted = 'adjusted to 3x.'; } else if (labAd.dpr > 1 && labAd.dpr <= 2) { // double density aka retina imgName = imgName.replace('@1x', '@2x'); adjusted = 'adjusted to 2x.'; } else { // no adjustment required since default is '@1x' } // log success labAd.log({ label: 'imgDPR: ' + adjusted, detail: imgName, type: 'log' }); } else { // warn in console for files missing @ symbol adjusted = '@ symbol not found in filename so imgDPR adjustment is not possible.' labAd.log({ label: 'imgDPR: ' + adjusted, detail: imgName, type: 'warn' }); } return imgName; } catch (err) { labAd.log({ label: 'imgDPR error: ', detail: err, type: 'error', isFatal: false }); } } function imgObj(sId, sSrc) { try { // adjust dpr as needed var obj = { id: sId, src: imgDPR(sSrc) }; // adjust image size of src obj.src = setSrcSize(obj.src); // prepend labAd.dir if src is not absolute path if (obj.src.indexOf('://') === -1) { obj.src = labAd.dir + obj.src; } // log results labAd.log({ label: 'imgObj ' + sId + ' - ' + sSrc, detail: obj, type: 'log' }); return obj; } catch (err) { labAd.log({ label: 'imgObj error: ', detail: err, type: 'error', isFatal: true }); } } function logInfo(oInfo) { // save to logs array - regardless of type or details this.logs.push(oInfo); // console output format will correspond to type of info being logged. // only local files are eligible for console output. // steps for error logs if (oInfo.type === 'error') { // save to errors array this.errors.push(oInfo); // always output log errors so they cannot be suppressed/missed due to logLevel console[oInfo.type](oInfo); // if the error is fatal, call showDefault with label passed as reason if (oInfo.isFatal) { showDefault(oInfo.label); } } else { // steps for non-error logs // console output is only possible if file is local if (window.location.href.indexOf("file://") !== -1) { // adjust type/level of output based on labAd.logLevel switch (labAd.logLevel) { case 2: // output every individual log console[oInfo.type](oInfo); break; case 0: // output nothing to console break; default: // clear console since this can fire many times but we only need 1 output for this setting console.clear(); // if there are errors, output them before labAd if (labAd.errors.length > 0) { labAd.errors.forEach(function (err, i) { console.error(err); }) } // output labAd object for easy inspection console.log(labAd); } }; } // update labInfo. Example: statefarm-4693437107-1528401281492 setLabInfo(this.meta.advertiser + '-' + this.meta.placement + '-' + this.meta.width + 'x' + this.meta.height + '-' + this.time.date, this); } function logTime(sName) { try { // log timing of key events to time.log for tracking purposes // also return getTime() value so this can be used to get timestamps var d = new Date(); var order = Object.keys(labAd.time.log).length; // create new log obj labAd.time.log[sName] = {}; // stamp this event labAd.time.log[sName].stamp = d.getTime(); // calc split in ms from previous stamp if (sName !== 'initAd') { labAd.time.log[sName].split = (labAd.time.log[sName].stamp - labAd.time.stamp); } else { labAd.time.log[sName].split = 0; } // calc elapsed from initAd - in ms labAd.time.log[sName].elapsed = (labAd.time.log[sName].stamp - labAd.time.log['initAd'].stamp); // capture log order to indicate where in sequence this log occured labAd.time.log[sName].order = order; // capture timestamp to use for next split labAd.time.stamp = d.getTime(); return labAd.time.stamp; } catch (err) { labAd.log({ label: 'logTime error: ', detail: err, type: 'error', isFatal: false }); } } function setLabInfo(sName, obj) { try { // store passed object to labInfo on parent DOM if possible if (labAd.macros.gamPreview === 'true') { // skip logging if running in DFP Preview return; } else { parent.labInfo = parent.labInfo || {}; parent.labInfo[sName] = obj; } } catch (err) { labAd.log({ label: 'setLabInfo error: ', detail: err, type: 'error', isFatal: false }); } } function setSrcSize(sFilename) { try { // perform string replacement to adjust from sm to lg image var imgName = decodeURIComponent(sFilename); var adjusted = 'not adjusted.'; if (labAd.deviceSize === 'sm') { // Adjust to smaller dimensions for small devices // THOR CHANGE - AD SIZE if (labAd.product.milliFGImages === true && imgName.indexOf('360x190') !== -1) { imgName = imgName.replace('360x190', '320x190'); adjusted = "adjusted to 320x190." } // THOR CHANGE - BG SIZE if (labAd.product.milliBGImages === true && imgName.indexOf('500x720') !== -1) { imgName = imgName.replace('9eb42665-d188-49de-a518-90ef9e06c26f/500x720-bg-clr-dmezz_HVEC_2mbs.mp4', 'f0ae9eae-ecc9-451b-a672-6b9fc0bae237/500x720m-bg-clr-dmezz_HVEC_2mbs.mp4'); imgName = imgName.replace('b66d9f38-55b7-4720-a3cf-2fd6e9272004/500x720-bg-clr-nmezz_HVEC_2mbs.mp4', '1abb7c90-66a9-4679-bdb5-0e6c2a1ca95e/500x720m-bg-clr-nmezz_HVEC_2mbs.mp4'); imgName = imgName.replace('47ab603a-7ecb-42a6-afa6-d26524aea659/500x720-bg-cld-dmezz_HVEC_2mbs.mp4', '309f5057-c97f-439b-b360-0c80e96c5385/500x720m-bg-cld-dmezz_HVEC_2mbs.mp4'); imgName = imgName.replace('733b1d7b-8283-485a-bf20-d83fda15326e/500x720-bg-cld-nmezz_HVEC_2mbs.mp4', 'a008e7a5-eca0-4ed1-9769-c792081d5ebb/500x720m-bg-cld-nmezz_HVEC_2mbs.mp4'); imgName = imgName.replace('371efb78-1545-40d8-a09f-08787d09f494/500x720-bg-rain-dmezz_HVEC_2mbs.mp4', '9a017d59-4c85-47bd-90a8-000b0bb7c54e/500x720m-bg-rain-dmezz_HVEC_2mbs.mp4'); imgName = imgName.replace('73a6a270-55dd-4a81-9e1a-1db410e129d9/500x720-bg-rain-nmezz_HVEC_2mbs.mp4', 'e93676b0-2b2d-480f-b87d-4bcecd88b5c9/500x720m-bg-rain-nmezz_HVEC_2mbs.mp4'); imgName = imgName.replace('d936b416-f74d-4156-ac5c-6c5459ed0a9e/500x720-bg-snow-dmezz_HVEC_2mbs.mp4', '57586289-11da-4844-8a4f-6c8b1d8cde00/500x720m-bg-snow-dmezz_HVEC_2mbs.mp4'); imgName = imgName.replace('42dfb55c-dd3f-4289-8c47-3db9f1b71d21/500x720-bg-snow-nmezz_HVEC_2mbs.mp4', 'd1c5f828-0092-4e77-8787-b9f256a1bb6b/500x720m-bg-snow-nmezz_HVEC_2mbs.mp4'); adjusted = "adjusted to 500x720-milli." } } else { adjusted = 'md, lg, or xl device so no adjustment needed.' } // log success labAd.log({ label: 'setSrcSize: ' + adjusted, detail: imgName, type: 'log' }); return imgName; } catch (err) { labAd.log({ label: 'setSrcSize error: ', detail: err, type: 'error', isFatal: false }); } } function showAd(aLoadedImages) { try { if (!labAd.displayed) { // flag to prevent ad from displaying multiple times in the event of failure or timeout labAd.displayed = true; logTime('showAd'); labAd.log({ label: 'showAd: ', detail: aLoadedImages, type: 'log' }); //////////////////////////////////////////////// // 1: Append AD Area (360x105 or 360x140) images to labAdDiv. // //////////////////////////////////////////////// aLoadedImages.forEach(function (elem) {// for each aLoadedImages el: assign CSS and behavior(s) then attach to DOM // add el reference to labAd.els labAd.els[elem.id] = elem; // assign common class to all labAd.els[elem.id].className = 'abs-' + labAd.deviceSize; labAd.els.labAdDiv.className = labAd.deviceSize; // append to labAdDiv labAd.els.labAdDiv.appendChild(labAd.els[elem.id]); // assign specific behavior/format by id if (elem.id === 'btnInv') { // assign click handler to invisible btn labAd.els[elem.id].onclick = exitClick; } }); } else { var err = { message: 'showAd called again.' } labAd.log({ label: 'Display routine called after labAd.displayed === true.', detail: err, type: 'error', isFatal: false }); } } catch (err) { labAd.log({ label: 'showAd error: ', detail: err, type: 'error', isFatal: true }); } } function showBg(bgProps) { try { logTime('showBg'); /////////////////////////////////////////////////////////////////// // 1: Process BG properties and fireAppEvent based on event name // /////////////////////////////////////////////////////////////////// if (bgProps.eventName === 'adBg') { // Static Image BG - assign props from selected labAd.appBg.baseURL = labAd.dir; // assign selected BG filename & adjust DPR if needed labAd.appBg.imgID = imgDPR(bgProps.fileName); // encode BG image name to prevent '@' from breaking app event. labAd.appBg.imgID = encodeURIComponent(labAd.appBg.imgID); // set the logical dimensions labAd.appBg.widthDP = bgProps.logicalWidth; labAd.appBg.heightDP = bgProps.logicalHeight; // set textMode labAd.appBg.textMode = bgProps.textMode; // THOR CHANGE - textMode // fire the app event passing updated props fireAppEvent('adBg', labAd.appBg); } else { // Video BG // Assign bgProps.fileName overwrite to @2x video bg every time. labAd.appBgVid.vidURL = bgProps.fileName.replace('@1x', '@2x'); // encode vidURL - because '@' is not compatible with BG app events labAd.appBgVid.vidURL = encodeURIComponent(labAd.appBgVid.vidURL); // prepend labAd.dir to filename to form vidURL labAd.appBgVid.vidURL = labAd.dir + labAd.appBgVid.vidURL; // set the logical dimensions labAd.appBgVid.widthDP = bgProps.logicalWidth; labAd.appBgVid.heightDP = bgProps.logicalHeight; // set textMode labAd.appBgVid.textMode = bgProps.textMode; // THOR CHANGE - textMode // Set the loopCount property labAd.appBgVid.loop = bgProps.loopCount; // fire the app event passing updated props fireAppEvent('adBgVid', labAd.appBgVid); } } catch (err) { labAd.log({ label: 'showBg error: ', detail: err, type: 'error', isFatal: false }); } } function showDefault(sReason) { try { if (!labAd.displayed) { // flag to prevent ad from displaying multiple times in the event of failure or timeout labAd.displayed = true; logTime('showDefault'); labAd.default.reason = sReason; labAd.log({ label: 'showDefault: ', detail: labAd.default.reason, type: 'log' }); if (labAd.mode === 'live') { } else { // create error & reason output display for PreviewMode labAd.els.errOutput = document.createElement('div'); labAd.els.errOutput.id = 'previewErrorOutput'; // create and apppend heading labAd.els.errReason = document.createElement('h1'); var t = document.createTextNode(sReason); labAd.els.errReason.appendChild(t); labAd.els.errOutput.appendChild(labAd.els.errReason); // create list labAd.els.errList = document.createElement('ol'); // iterate errors and add list item for each labAd.errors.forEach(function (err, i) { // create an li & text node for every error var li = document.createElement('li'); var lit = document.createTextNode(err.label); li.appendChild(lit); // add li to the ul labAd.els.errList.appendChild(li); }); // add ul with all list items to output panel labAd.els.errOutput.appendChild(labAd.els.errList); // create footer text var p = document.createElement('footer'); p.innerHTML = '<strong>Note:</strong> The list above represents the earliest occuring errors - which should be diagnosed first. <p>Check <code>labAd.errors</code> for a complete set of errors and details.</p>'; labAd.els.errOutput.appendChild(p); // empty previewMain and append the errOutput there because GAM Preview // will not permit insertBefore to place the errOutput before other // els in the DOM. labAd.els.previewMain.innerHTML = ''; labAd.els.previewMain.appendChild(labAd.els.errOutput); labAd.els.previewMain.style.opacity = 1; } } else { var err = { message: 'showDefault called again.' } labAd.log({ label: 'Display routine called after labAd.displayed === true.', detail: err, type: 'error', isFatal: false }); } } catch (err) { // not fatal since there's no fallback for this failure. labAd.log({ label: 'showDefault error: ', detail: err, type: 'error', isFatal: false }); } } document.addEventListener('DOMContentLoaded', initAd, false); </script> <style> /* CORE CSS - DO NOT EDIT */ /* VIEWABILITY FIX ADDED 11/18/19 - DO NOT REMOVE */ html { height: 100%; width: 100%; } body { margin: 0; height: 100%; width: 100%; } #labAdDiv { height: 190px; position: relative; margin: 0 auto; } #labAdDiv.sm { width: 320px; } #labAdDiv.md, #labAdDiv.lg, #labAdDiv.xl { width: 360px; } /* Ad Slot Size & Position */ .abs-sm { width: 320px; height: 190px; position: absolute; } .abs-md, .abs-lg, .abs-xl { width: 360px; height: 190px; position: absolute; } .preview #labAdDiv.sm { width: 300px; bottom: -4px; } .preview #labAdDiv.md { width: 360px; left: 2px; bottom: -6px; } .preview #labAdDiv.lg { width: 360px; left: 0px; bottom: -10px; } .preview #labAdDiv.xl { width: 360px; left: 0px; bottom: -14px; } /* Ad Slot Size & Position */ .preview .abs-sm { left: -8px; top: 0px; } .preview .abs-md, .preview .abs-lg, .preview .abs-xl { left: -18px; top: 10px; } /* Foreground element Size */ .preview #fgGrid.abs-sm { width: 320px; height: 190px; } .preview #fgGrid.abs-md, .preview #fgGrid.abs-lg, .preview #fgGrid.abs-xl { width: 360px; height: 190px; } /* Foreground element Position */ .preview #fgGrid.abs-md, .preview #fgGrid.abs-lg, .preview #fgGrid.abs-xl { top: 0px; left: 0px } #btnInv { z-index: 10; cursor: pointer; height: 190px; /* background: rgba(255,255,255, .25);*/ } /* btnInv element Position */ .preview #btnInv.abs-md, .preview #btnInv.abs-lg, .preview #btnInv.abs-xl { top: 0px; left: 0px } .hidden { opacity: 0; } /* END: CORE CSS - DO NOT EDIT */ /* Preview Mode CSS - DO NOT EDIT – VIEWABILITY FIX ADDED 11/18/19 */ #previewMainContainer { opacity: 0; display: none; } #previewAltContainer { display: none; } /* END: Preview Mode CSS - DO NOT EDIT */ </style> </head> <body> <!-- #labAdDiv is the main container for all AD elements --> <div id="labAdDiv"></div> <!-- Container for all tracking pixels - manually placed or dynamically generated. --> <div id="labTracking" style="display:none;"> <!-- 3P IAS OR MOAT TRACKING GOES HERE IF APPLICABLE --> <SCRIPT TYPE="application/javascript" SRC="https://pixel.adsafeprotected.com/rjss/st/2216208/82877213/skeleton.js"></SCRIPT> </div> <!-- Preview Mode Structure - DO NOT EDIT --> <div id="previewMainContainer"> <!-- LEFT FORM COL --> <div id="previewColLeft"> <hr> <img id="previewFormLogo" src="" alt="The Weather Company"> <hr> <p id="previewFormProduct"> Mobile App Integrated Marquee </p> <hr> <p id="previewFormClientName"> Client Name Here </p> <hr> <div id="previewFormDeviceSize"> <p>Device Size</p> <!-- // added this for XL sizes preview - wodev comment--> <input type="radio" name="deviceSize" value="sm" id="deviceSmall"> <label for="deviceSmall" id="label-01">SM</label> <input type="radio" name="deviceSize" value="md" id="deviceMedium"> <label for="deviceMedium" id="label-02">RG</label> <input type="radio" name="deviceSize" value="lg" id="deviceLarge"> <label for="deviceLarge" id="label-03">LG</label> <input type="radio" name="deviceSize" value="xl" id="deviceXLarge"> <label for="deviceXLarge" id="label-04">XL</label> <!-- // added this for medium sizes preview - wodev comment --> </div> <hr> <div id="previewFormCondition"> <div id="btnPrevCond"><img src="https://s.w-x.co/cl/wxcl/preview-mode/idd/prev.png" /></div> <div id="txtCondName"></div> <div id="btnNextCond"><img src="https://s.w-x.co/cl/wxcl/preview-mode/idd/next.png" /></div> </div> <hr> <div id="previewFormConditionIndex"></div> </div> <!-- RIGHT AD COL --> <div id="previewColRight"> <div id="previewAppOverlay"> <!-- previewAppOverlay = newer layout with images for device and app ui. --> <div id="previewDeviceToggleBtn"></div> <div id="previewDeviceOverlay"></div> <!-- START: ADD THIS for city, state textfield --> <!-- <div id="previewCityStateOverlay"> <input type="text" id="cityStateInput" value="Durango, CO" readonly> </div> --> <!-- END: ADD THIS for city, state textfield --> <div id="previewUiCon"> <div id="previewUiOverlay"></div> </div> <div id="previewUiFCOverlay"></div> <div id="previewBlockerBottom"></div> </div> <div id="previewAppLayout"> <!-- previewAppLayout (previously previewAppContainer) = older layout with colored divs representing different regions of app. --> <div id="previewAppHeader"></div> <div id="previewAppToggle"></div> <div id="previewAppChart"></div> <div id="previewAppInsight"></div> <div id="previewAppGradient"></div> <div id="previewAppNav"></div> <div id="previewAppCoverRight"></div> <div id="previewAppCoverLeft"></div> </div> <!-- End Right Column --> </div> </div> <div id="previewAltContainer"> <img id="previewAltLogo" src="" alt="The Weather Company"> <p>Please increase browser width to view creative preview form.</p> </div> </body> </html>
Landing Page
URL
http://www.previewads.com/html-tag-ad-tester/2ccb940b-ffc0-4f0c-9005-b5642fb3cda0/%%CLICK_URL_UNESC%%https://arttrk.com/pixel/?ad_log=ua-00040002-91728328435450&tag=fclick&msg=uid=%%CACHEBUSTER%%%7Crev=1%7Cdfp_ctrk=%eaid!!%ecid!!adxcel!%ebuy!!Gas_South_Q4_2024&pixid=8f898adb-7dea-467d-a64b-c46ad27f468a&consumer_id=%%ADVERTISING_IDENTIFIER_PLAIN%%&enc_url=https%3A%2F%2Fservedby.flashtalking.com%2Fclick%2F8%2F251900%3B8782477%3B4930844%3B211%3B0%2F%3Fgdpr%3D%24%7BGDPR%7D%26gdpr_consent%3D%24%7BGDPR_CONSENT_78%7D%26us_privacy%3D%26url%3D39973030
Query Parameters
ad_log
ua-00040002-91728328435450
tag
fclick
msg
uid=%ΚCHEBUSTER%%|rev=1|dfp_ctrk=κid!!μid!!adxcel!λuy!!Gas_South_Q4_2024
pixid
8f898adb-7dea-467d-a64b-c46ad27f468a
consumer_id
%­VERTISING_IDENTIFIER_PLAIN%%
enc_url
https://servedby.flashtalking.com/click/8/251900;8782477;4930844;211;0/?gdpr=${GDPR}&gdpr_consent=${GDPR_CONSENT_78}&us_privacy=&url=39973030
Network Timeline
Performance Summary

14

Requests

6

Domains

139KB

Transfer Size

470KB

Content Size

208.0ms

Dom Content Loaded

335.0ms

First Paint

516.0ms

Load Time
Domain Breakdown
Transfer Size (bytes)
Loading...
Content Size (bytes)
Loading...
Header Size (bytes)
Loading...
Requests
Loading...
Timings (ms)
Loading...
Total Time
Loading...
Content Breakdown
Transfer Size (bytes)
Loading...
Content Size (bytes)
Loading...
Header Size (bytes)
Loading...
Requests
Loading...