├── .gitignore ├── AdHelper ├── AdHelper.js ├── AdHelper.min.js ├── README.md ├── README_1.jpg ├── docs │ ├── api.js │ ├── assets │ │ ├── css │ │ │ ├── external-small.png │ │ │ ├── logo.png │ │ │ └── main.css │ │ ├── favicon.png │ │ ├── img │ │ │ └── spinner.gif │ │ ├── index.html │ │ ├── js │ │ │ ├── api-filter.js │ │ │ ├── api-list.js │ │ │ ├── api-search.js │ │ │ ├── apidocs.js │ │ │ └── yui-prettify.js │ │ └── vendor │ │ │ └── prettify │ │ │ ├── CHANGES.html │ │ │ ├── COPYING │ │ │ ├── README.html │ │ │ ├── prettify-min.css │ │ │ └── prettify-min.js │ ├── classes │ │ └── AdHelper.html │ ├── files │ │ └── _Users_grant_Documents_JS_CreateJS_html5ads_AdHelper_AdHelper.js.html │ └── index.html ├── garyad.fla ├── garyad.html ├── garyad.js ├── garyad_deploy.html ├── index.html ├── sounds │ ├── EnemyHit.mp3 │ └── LaserGunShot.mp3 └── tools │ ├── gulpfile.js │ └── package.json ├── README.md ├── assets ├── TOC.js ├── styles.css └── workflow.png └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | .idea 4 | -------------------------------------------------------------------------------- /AdHelper/AdHelper.js: -------------------------------------------------------------------------------- 1 | /* 2 | * AdHelper 3 | * Visit http://createjs.com/ for documentation, updates and examples. 4 | * 5 | * 6 | * Copyright (c) 2015 gskinner.com, inc. 7 | * 8 | * Permission is hereby granted, free of charge, to any person 9 | * obtaining a copy of this software and associated documentation 10 | * files (the "Software"), to deal in the Software without 11 | * restriction, including without limitation the rights to use, 12 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the 14 | * Software is furnished to do so, subject to the following 15 | * conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | * OTHER DEALINGS IN THE SOFTWARE. 28 | */ 29 | 30 | // namespace: 31 | this.createjs = this.createjs || {}; 32 | 33 | (function(){ 34 | "use strict"; 35 | 36 | // constructor 37 | /** 38 | * NOTE: This class is specifically designed to work in an advertising environment, where the ad is isolated 39 | * to its own iframe. It can cause problems if there are multiple CreateJS experiences in the same document. 40 | * 41 | * Class that provides a number of helpful capabilities for online advertisements such as: 50 | * These features work together. For example, sleep time will be deferred and performance 51 | * measurements will be halted when an ad is paused due to being in a background tab. 52 | * 53 | * Background tab detection is enabled automatically, and works in all browsers that support the page visibility API. This includes all 54 | * modern browsers except IE <10, Opera Mini, and the Android Browser <4.4. Note that audio is currently muted, not 55 | * paused, which can cause audio to become desynched. Use the "sleep" and "wake" events to pause/resume your audio 56 | * if this is a problem. 57 | * 58 | * Most methods can be chained to allow single line initialization. For example, this would 59 | * create an ad helper that sleeps after 15s, and has alt content: 60 | * 61 | * var ad = new AdHelper(myStage).setSleep(15).highDPI(); 62 | * ad.on("sleep", handleSleep, this); 63 | * 64 | * @class AdHelper 65 | * @param {Stage} stage The target Stage object. 66 | * @extends EventDispatcher 67 | */ 68 | function AdHelper(stage) { 69 | this._stage = stage; // up here because its used by pixelRatio. 70 | 71 | // public properties: 72 | /** 73 | * This listener will be removed from the Ticker when the ad sleeps, and added back when it wakes. 74 | * By default this will be the stage, to stop updates when sleeping, however if you define your own tick 75 | * handler that subsequently calls `stage.update` you should specify it instead. 76 | * 77 | * Your listener can alternatively check the `paused` property on tick events, which will be true when the 78 | * ad is asleep. 79 | * 80 | * NOTE: if using `on` to add your tick listener, make sure to use the generated listener object as 81 | * the tickListener. Example: 82 | * 83 | * var listener = createjs.Ticker.on("tick", myTickFunction, scope); 84 | * myAdHelper.setSleep(15, 3, 0, listener); 85 | * 86 | * @property tickListener 87 | * @type {Function|Object} 88 | */ 89 | this.tickListener = null; 90 | 91 | /** 92 | * True when awake, false when sleeping. 93 | * @property awake 94 | * @type {Boolean} 95 | * @readonly 96 | */ 97 | this.awake = true; 98 | 99 | /** 100 | * Disables sleep if false. Set to true automatically when `setSleep()` is called. 101 | * @property sleepEnabled 102 | * @type {Boolean} 103 | * @default false 104 | */ 105 | this.sleepEnabled = false; 106 | 107 | /** 108 | * True when the ad is hidden (ex. in a background tab). 109 | * @property hidden 110 | * @type {Boolean} 111 | * @readonly 112 | */ 113 | this.hidden = false; 114 | 115 | /** 116 | * Returns the pixel ratio that is being used to draw the canvas on a high dpi device. On browsers that 117 | * automatically utilize high dpi backing stores (like Safari), this returns the backingStorePixelRatio. For 118 | * other browsers, this returns 1 by default. This is also affected by the `nominalScale` passed to `highDPI()`. 119 | * 120 | * If you call the `highDPI()` method, then `pixelRatio` will be set to the resulting scale. 121 | * 122 | * This value is primarily useful for loading appropriately sized bitmap images. 123 | * 124 | * myAdHelper.highDPI(); 125 | * if (myAdHelper.pixelRatio > 1.5) { 126 | * // load high res images. 127 | * } else { 128 | * // load low res images. 129 | * } 130 | * @property pixelRatio 131 | * @type {Number} 132 | * @readonly 133 | */ 134 | this.pixelRatio = this._getBackingRatio(); 135 | 136 | // private properties: 137 | this._time = 0; 138 | 139 | this._awake = true; // whether the ad should be awake ignoring tab visibility 140 | this._sleepy = false; // indicates it should sleep on the next tick 141 | this._sleepT = 0; // time to go to sleep 142 | this._sleepMousedownT = null; // time before sleep if user clicks on the stage 143 | this._sleepInBoundsT = null; // time before sleep if the mouse is in bounds 144 | this._sleepUseTicks = false; // must be set in props if using startDelay 145 | this._mouseInDoc = false; // iframes can break stage.mouseInBounds 146 | 147 | this._perfDelay = 0; // wait a few ticks before measuring performance 148 | this._perfCount = 0; 149 | this._perfThreshold = 0; 150 | this._perfFPS = 0; 151 | 152 | this._width = stage.canvas.width; // for use with highDPI in case of multiple calls. 153 | this._height = stage.canvas.height; 154 | 155 | createjs.Ticker.on("tick", this); 156 | } 157 | var p = AdHelper.prototype; 158 | if (createjs.EventDispatcher) { p = AdHelper.prototype = new createjs.EventDispatcher(); } 159 | 160 | 161 | // public static methods: 162 | /** 163 | * Returns true if CreateJS is supported on this browser. For example, this can be used in conjunction with the 164 | * `showAlt` methods to display alternate content when the CreateJS banner is not supported. You should run this 165 | * check before initializing the ad. For example: 166 | * 167 | * function init() { 168 | * if (!createjs.AdHelper.isSupported()) { 169 | * // not supported, show alt content, and skip everything else. 170 | * createjs.AdHelper.showAltImage("myImage.jpg", "url"); 171 | * return; 172 | * } 173 | * // supported, so continue with normal init... 174 | * } 175 | * 176 | * @method isSupported 177 | * @static 178 | * @return {Boolean} True if CreateJS is supported on this browser. 179 | */ 180 | AdHelper.isSupported = function() { 181 | return !!window.CanvasRenderingContext2D; 182 | }; 183 | 184 | /** 185 | * Helper method that generates HTML and passes it to `showAltHTML` to replace the specified canvas. 186 | * You can set a link href/url, an image, and alt text. If you require more control over the content 187 | * use `setAltHTML` directly. 188 | * @method setAltImage 189 | * @static 190 | * @param {String|HTMLCanvasElement} canvas The canvas element to replace, or its id. 191 | * @param {String} src The URL for the image to display. 192 | * @param {String} [href] The URL to link. 193 | * @param {String} [alt=""] Text to use as alt text for the image. 194 | * @param {String} [target="_blank"] The link target to use (ex. _blank, _parent). Default is _blank. 195 | * @return {HTMLElement} The div that was created by showAltHTML and swapped with the canvas. 196 | */ 197 | AdHelper.showAltImage = function(canvas, src, href, alt, target) { 198 | return AdHelper.showAltHTML(canvas, 199 | (href?"":"")+ 200 | ""+(alt||"")+""+ 201 | (href?"":"")); 202 | }; 203 | 204 | /** 205 | * Replaces the specified canvas with a new div containing the specified HTML content. The created div is assigned 206 | * an id of "adAlt" for referencing in code or styling with CSS. 207 | * @method showAltHTML 208 | * @static 209 | * @param {String|HTMLCanvasElement} canvas The canvas element to replace, or its id. 210 | * @param {String} html The HTML content to display. 211 | * @return {HTMLElement} The div that was created and swapped with the canvas. 212 | */ 213 | AdHelper.showAltHTML = function(canvas, html) { 214 | var div = document.createElement("div"); 215 | div.innerHTML = html || ""; 216 | div.id = "adAlt"; 217 | return AdHelper.showAlt(canvas, div); 218 | }; 219 | 220 | /** 221 | * Swaps the specified canvas with an HTML element as alternative content. The element will have its CSS `display` 222 | * value set to `block`. This allows you to set the element's CSS `display` value to `none` by default to 223 | * prevent it from displaying when the page loads. 224 | * 225 | * Note that any images or scripts you have in your element will be loaded and run as usual, so using showAltHTML 226 | * may be preferable in some situations. 227 | * @method showAlt 228 | * @static 229 | * @param {String|HTMLCanvasElement} canvas The canvas element to replace, or its id. 230 | * @param {HTMLElement} element The HTML element to display. 231 | * @return {HTMLElement} The element that was passed in. 232 | */ 233 | AdHelper.showAlt = function(canvas, element) { 234 | if (typeof canvas == "string") { canvas = document.getElementById(canvas); } 235 | element.style.display = "block"; 236 | canvas.parentNode.replaceChild(element, canvas); 237 | return element; 238 | }; 239 | 240 | 241 | // events: 242 | /** 243 | * Dispatched when the ad wakes, either via the `wake()` method or automatically due to user interaction or 244 | * the browser tab coming to the foreground. 245 | * @event wake 246 | */ 247 | 248 | /** 249 | * Dispatched when the ad sleeps, either via the `sleep()` method or automatically due to sleep scheduling or 250 | * the browser tab being hidden. 251 | * @event sleep 252 | */ 253 | 254 | /** 255 | * Dispatched if performance monitoring (via watchFPS) detects that the ad is running slowly. 256 | * @event slow 257 | */ 258 | 259 | // public methods 260 | /** 261 | * Causes all MovieClip instances to run in time synched mode, so their duration remains consistent regardless of 262 | * real framerate (ex. if framerate drops due to performance issues). 263 | * 264 | * NOTE: If a `framerate` value is not specified, it will use `lib.properties.fps` if available, and finally fall back to `Ticker.getFPS()`. 265 | * If the latter occurs, and the `Ticker` framerate has not been correctly set yet, you may see unexpected playback speed. 266 | * 267 | * This feature works by injecting code into EaselJS that causes all MovieClip instances to use a master frame rate as 268 | * their `framerate` property value. See `MovieClip.framerate` for more information. 269 | * @method timeSync 270 | * @param {Number} [framerate] The target framerate. Usually the framerate your ad was authored at. 271 | * @return {AdHelper} The AdHelper instance the method is called on (useful for chaining calls.) 272 | * @chainable 273 | */ 274 | p.timeSync = function(framerate) { 275 | var futureVersion = (this._stage.masterFrameRate !== undefined); 276 | this._stage.masterFrameRate = framerate || (lib&&lib.properties&&lib.properties.fps) || this._getTickerFPS(); 277 | 278 | // try to be forwards compatible: 279 | if (futureVersion) { return this; } 280 | 281 | var stage_p = createjs.Stage.prototype, mc_p = createjs.MovieClip.prototype; 282 | stage_p.__tick = stage_p._tick; 283 | stage_p._tick = function(evt) { 284 | evt.stage = this; 285 | this.__tick(evt); 286 | } 287 | 288 | mc_p.__tick = mc_p._tick; 289 | mc_p._tick = function(evt) { 290 | if (!this.ignoreMasterFrameRate && evt.stage) { 291 | this.framerate = evt.stage.masterFrameRate || null; 292 | } 293 | this.__tick(evt); 294 | } 295 | return this; 296 | }; 297 | 298 | 299 | /** 300 | * Watches the real framerate for the ad, and applies a simple heuristic to determine when the ad has been 301 | * running too slowly for too long. When this happens a `slow` event is dispatched, which you can use to modify 302 | * your content, for example by displaying alternative content: 303 | * 304 | * myAdHelper.watchFPS().on("slow", function(evt) { 305 | * createjs.AdHelper.showAltImage(myStage.canvas, "myImage.jpg", "myURL"); 306 | * }); 307 | * 308 | * By default, when the slow event fires, AdHelper will call `sleep()` and set `sleepEnabled=true`. You can prevent 309 | * this behaviour by calling `preventDefault()` on the slow event object. You can also restart the framerate watcher 310 | * after making adjustments: 311 | * 312 | * myAdHelper.on("slow", function(evt) { 313 | * if (particleCount > 0) { 314 | * // if we can speed things up by removing particles, try that first. 315 | * evt.preventDefault(); // the ad will not be put to sleep. 316 | * particleCount -= 100; // or whatever will make it run faster. 317 | * this.watchFPS(); // restart the framerate watcher 318 | * } else { 319 | * // no more particles to remove, so let the default sleep happen 320 | * // and swap in some alt content: 321 | * createjs.AdHelper.showAltImage(myStage.canvas, "myImage.jpg", "myURL"); 322 | * } 323 | * }); 324 | * 325 | * @method watchFPS 326 | * @param {Number} [minFPS] The minimum framerate considered acceptable. Calculated automatically if null. 327 | * @param {Number} [tolerance=1] The tolerance of the system. A higher value (ex. 2) allows more slow frames before acting than a lower number (ex. 0.5). 328 | * @return {AdHelper} The AdHelper instance the method is called on (useful for chaining calls.) 329 | * @chainable 330 | */ 331 | p.watchFPS = function(minFPS, tolerance) { 332 | this._perfFPS = minFPS || (this._getTickerFPS()*0.9-1|0); 333 | this._perfThreshold = tolerance || 1; 334 | this._perfCount = 0; 335 | this._perfDelay = 5; 336 | return this; 337 | }; 338 | 339 | 340 | /** 341 | * Scales the canvas and content as appropriate to display full resolution graphics on high dpi devices and updates 342 | * the `pixelRatio` property accordingly. 343 | * 344 | * If `false` is passed to the `enabled` parameter, then high DPI rendering will be disabled, including downscaling 345 | * the canvas on devices that automatically render at high DPI. This can be useful for reducing render cost on slower 346 | * devices. 347 | * 348 | * The `nominalScale` param allows you to author content at higher resolution, and have AdHelper scale it appropriately 349 | * for the device. For example, you may find it easier to author a 728x90 banner at 1456x180 (2x scale) so that 350 | * bitmaps and cacheAsBitmap are high resolution, then specify a `nominalScale` of 2 to display it at the intended 351 | * size of 728x90. 352 | * 353 | * It will change the canvas width/height attributes, the canvas's CSS width/height, and the stage's scaleX/Y as 354 | * necessary. 355 | * @method highDPI 356 | * @param {Boolean} [enabled=true] If false, disables high DPI rendering. 357 | * @param {Number} [nominalScale=1] The scale the content was authored at. The ad will be downscaled by this value. 358 | * @return {AdHelper} The AdHelper instance the method is called on (useful for chaining calls.) 359 | * @chainable 360 | */ 361 | p.highDPI = function(enabled, nominalScale) { 362 | nominalScale = nominalScale || 1; 363 | var backingRatio = this._getBackingRatio(); 364 | var scale = Math.max(1, (window.devicePixelRatio || 1) / backingRatio); 365 | var stage = this._stage, canvas = stage.canvas, style = canvas.style; 366 | var w = this._width / nominalScale, h = this._height / nominalScale; 367 | 368 | // downscale if highDPI is explicitly disabled: 369 | if (enabled === false) { scale = 1/backingRatio; } 370 | 371 | canvas.width = w * scale; 372 | canvas.height = h * scale; 373 | style.width = w+"px"; 374 | style.height = h+"px"; 375 | stage.scaleX = stage.scaleY = scale/nominalScale; 376 | 377 | this.pixelRatio = (backingRatio === 1 ? scale : enabled === false ? 1 : backingRatio) / nominalScale; 378 | return this; 379 | }; 380 | 381 | 382 | /** 383 | * Sets the sleep schedule for the ad. The system will always use the latest sleep time. For example, if you called: 384 | * `setSleep(15, 3)` and the user clicked the ad after 4 seconds, the ad would still sleep after 15 seconds (15 > 3+4). 385 | * @method setSleep 386 | * @param {Number} start The delay in seconds after this call to wait before sleeping. Set to null to ignore this behaviour. 387 | * @param {Number} [mousedown=null] The delay after the user clicks the banner to wait before sleeping. Set to null to ignore this behaviour. 388 | * @param {Number} [inBounds=null] The delay after the user's mouse leaves the banner to wait before sleeping. Set to null to ignore this behaviour. For example, set to 0 to wake when the mouse enters, and sleep immediately when it leaves. 389 | * @param {Boolean} [useTicks=false] If true, the sleep times are specified in ticks instead of in seconds. 390 | * @param {Function|Object} [listener] Defaults to the stage. The listener to add/remove from Ticker when waking/sleeping. See `tickListener` for more details. 391 | * @return {AdHelper} The AdHelper instance the method is called on (useful for chaining calls.) 392 | * @chainable 393 | */ 394 | p.setSleep = function(start, mousedown, inBounds, useTicks, listener) { 395 | if (mousedown != null) { stage.addEventListener("stagemousedown", this); } 396 | if (inBounds != null) { 397 | document.addEventListener("mouseout", this, true); 398 | document.addEventListener("mousemove", this, true); 399 | } 400 | this.tickListener = listener || this._stage; 401 | this._sleepMousedownT = mousedown; 402 | this._sleepInBoundsT = inBounds; 403 | this._sleepUseTicks = !!useTicks; 404 | this.sleepEnabled = true; 405 | 406 | this._sleepy = false; // indicates it should sleep on the next tick 407 | this._sleepT = (start != null) ? this._getTime() + start*1000 : 0; 408 | return this; 409 | }; 410 | 411 | /** 412 | * Sleeps the ad after the specified delay. This pauses the ticker, unsubscribes the `tickListener`, 413 | * and pauses GreenSock TweenLite/TweenMax tweens. 414 | * @method sleep 415 | * @param {Number} [delay=0] The delay before sleeping, or 0 to sleep immediately. 416 | */ 417 | p.sleep = function(delay) { 418 | // TODO: switch to seconds. 419 | if (delay) { this._sleepT = this._getTime()+(delay||0); return; } 420 | this._sleepy = false; 421 | this._sleepT = 0; 422 | this._awake = false; 423 | this._sleep(); 424 | }; 425 | 426 | /** 427 | * Wakes the ad for a specified amount of time. 428 | * @method wake 429 | * @param {Number} [time=null] The amount of time to wake for, or null to wake permanently. 430 | */ 431 | p.wake = function(time) { 432 | // TODO: switch to seconds. 433 | this._sleepy = false; 434 | if (time != null) { this._sleepT = Math.max(this._sleepT, this._getTime()+(time||0)); } 435 | else { this._sleepT = 0; } 436 | this._awake = true; 437 | this._wake(); 438 | }; 439 | 440 | p.handleEvent = function(evt) { 441 | if (evt.type === "tick") { 442 | this._tick(evt); 443 | } else if (evt.type === "stagemousedown") { 444 | var d = this._sleepMousedownT; 445 | if (this.sleepEnabled && d != null) { this.wake(d*1000); } 446 | } else if (evt.type === "mousemove") { 447 | this._mouseInDoc = true; 448 | } else if (evt.type === "mouseout") { 449 | this._mouseInDoc = false; 450 | } 451 | }; 452 | 453 | 454 | // private methods: 455 | p._getTickerFPS = function() { 456 | return (createjs.Ticker.timingMode == createjs.Ticker.RAF ? 60 : createjs.Ticker.framerate); 457 | }; 458 | 459 | p._sleep = function() { 460 | if (!this.awake) { return; } 461 | createjs.Ticker.paused = true; 462 | if (this.tickListener) { createjs.Ticker.removeEventListener("tick", this.tickListener); } 463 | window.TweenLite && TweenLite.ticker && TweenLite.ticker.sleep(); 464 | this.dispatchEvent("sleep"); 465 | this.awake = false; 466 | }; 467 | 468 | p._wake = function() { 469 | if (this.awake) { return; } 470 | createjs.Ticker.paused = false; 471 | if (this.tickListener) { createjs.Ticker.addEventListener("tick", this.tickListener); } 472 | 473 | if (window.TweenLite) { 474 | var ticker = TweenLite.ticker, originalFrame = ticker.frame; //record the original frame temporarily so we can revert 475 | ticker.frame = 1; //hack to make legacy versions of GSAP apply lag smoothing upon wake 476 | ticker.wake(true); 477 | ticker.frame = originalFrame; 478 | } 479 | 480 | this.dispatchEvent("wake"); 481 | this.awake = true; 482 | }; 483 | 484 | p._tick = function(evt) { 485 | /* tab visibility */ 486 | if (document.hidden || document.webkitHidden || document.mozHidden) { 487 | this.hidden = true; 488 | this._sleep(); 489 | if (createjs.Sound) { createjs.Sound.muted = true; } 490 | return; 491 | } else if (this.hidden) { 492 | this.hidden = false; 493 | if (this._awake) { this._wake(); } 494 | this._perfDelay = 3; 495 | if (createjs.Sound) { createjs.Sound.muted = false; } 496 | } 497 | this._time += this._sleepUseTicks ? 1 : evt.delta; 498 | 499 | /* perf */ 500 | var fps; 501 | if (this._perfFPS && (--this._perfDelay <= 0) && (fps = createjs.Ticker.getMeasuredFPS(1)) > -1) { 502 | var val = 1-Math.max(0, Math.min(1, fps / this._perfFPS)); 503 | this._perfCount = Math.max(0, this._perfCount + (val === 0 ? -0.2 : val*val*0.5+0.1)); 504 | if (this._perfCount > this._perfThreshold) { 505 | this._perfFPS = 0; 506 | if (this.dispatchEvent(new createjs.Event("slow", false, true))) { 507 | this.sleep(); 508 | this.sleepEnabled = false; 509 | } 510 | } 511 | } 512 | 513 | /* sleep */ 514 | if (this.sleepEnabled) { 515 | if (this._sleepInBoundsT != null && this._stage.mouseInBounds && this._mouseInDoc) { this.wake(this._sleepInBoundsT*1000); } 516 | if (this._sleepy) { this.sleep(); } 517 | else if (this._sleepT && (this._getTime() >= this._sleepT)) { this._sleepy = true; } // delay 1 tick. 518 | } 519 | }; 520 | 521 | p._getTime = function() { 522 | return this._time; 523 | }; 524 | 525 | p._getBackingRatio = function() { 526 | var ctx = this._stage.canvas.getContext("2d"); 527 | return ctx.backingStorePixelRatio || ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || 1; 528 | }; 529 | 530 | createjs.AdHelper = AdHelper; 531 | })(); -------------------------------------------------------------------------------- /AdHelper/AdHelper.min.js: -------------------------------------------------------------------------------- 1 | this.createjs=this.createjs||{},function(){"use strict";function e(e){this._stage=e,this.tickListener=null,this.awake=!0,this.sleepEnabled=!1,this.hidden=!1,this.pixelRatio=this._getBackingRatio(),this._time=0,this._awake=!0,this._sleepy=!1,this._sleepT=0,this._sleepMousedownT=null,this._sleepInBoundsT=null,this._sleepUseTicks=!1,this._mouseInDoc=!1,this._perfDelay=0,this._perfCount=0,this._perfThreshold=0,this._perfFPS=0,this._width=e.canvas.width,this._height=e.canvas.height,createjs.Ticker.on("tick",this)}var t=e.prototype;createjs.EventDispatcher&&(t=e.prototype=new createjs.EventDispatcher),e.isSupported=function(){return!!window.CanvasRenderingContext2D},e.showAltImage=function(t,i,s,n,h){return e.showAltHTML(t,(s?"":"")+""+(n||"")+""+(s?"":""))},e.showAltHTML=function(t,i){var s=document.createElement("div");return s.innerHTML=i||"",s.id="adAlt",e.showAlt(t,s)},e.showAlt=function(e,t){return"string"==typeof e&&(e=document.getElementById(e)),t.style.display="block",e.parentNode.replaceChild(t,e),t},t.timeSync=function(e){var t=void 0!==this._stage.masterFrameRate;if(this._stage.masterFrameRate=e||lib&&lib.properties&&lib.properties.fps||this._getTickerFPS(),t)return this;var i=createjs.Stage.prototype,s=createjs.MovieClip.prototype;return i.__tick=i._tick,i._tick=function(e){e.stage=this,this.__tick(e)},s.__tick=s._tick,s._tick=function(e){!this.ignoreMasterFrameRate&&e.stage&&(this.framerate=e.stage.masterFrameRate||null),this.__tick(e)},this},t.watchFPS=function(e,t){return this._perfFPS=e||.9*this._getTickerFPS()-1|0,this._perfThreshold=t||1,this._perfCount=0,this._perfDelay=5,this},t.highDPI=function(e,t){t=t||1;var i=this._getBackingRatio(),s=Math.max(1,(window.devicePixelRatio||1)/i),n=this._stage,h=n.canvas,a=h.style,r=this._width/t,o=this._height/t;return e===!1&&(s=1/i),h.width=r*s,h.height=o*s,a.width=r+"px",a.height=o+"px",n.scaleX=n.scaleY=s/t,this.pixelRatio=(1===i?s:e===!1?1:i)/t,this},t.setSleep=function(e,t,i,s,n){return null!=t&&stage.addEventListener("stagemousedown",this),null!=i&&(document.addEventListener("mouseout",this,!0),document.addEventListener("mousemove",this,!0)),this.tickListener=n||this._stage,this._sleepMousedownT=t,this._sleepInBoundsT=i,this._sleepUseTicks=!!s,this.sleepEnabled=!0,this._sleepy=!1,this._sleepT=null!=e?this._getTime()+1e3*e:0,this},t.sleep=function(e){return e?void(this._sleepT=this._getTime()+(e||0)):(this._sleepy=!1,this._sleepT=0,this._awake=!1,void this._sleep())},t.wake=function(e){this._sleepy=!1,null!=e?this._sleepT=Math.max(this._sleepT,this._getTime()+(e||0)):this._sleepT=0,this._awake=!0,this._wake()},t.handleEvent=function(e){if("tick"===e.type)this._tick(e);else if("stagemousedown"===e.type){var t=this._sleepMousedownT;this.sleepEnabled&&null!=t&&this.wake(1e3*t)}else"mousemove"===e.type?this._mouseInDoc=!0:"mouseout"===e.type&&(this._mouseInDoc=!1)},t._getTickerFPS=function(){return createjs.Ticker.timingMode==createjs.Ticker.RAF?60:createjs.Ticker.framerate},t._sleep=function(){this.awake&&(createjs.Ticker.paused=!0,this.tickListener&&createjs.Ticker.removeEventListener("tick",this.tickListener),window.TweenLite&&TweenLite.ticker&&TweenLite.ticker.sleep(),this.dispatchEvent("sleep"),this.awake=!1)},t._wake=function(){if(!this.awake){if(createjs.Ticker.paused=!1,this.tickListener&&createjs.Ticker.addEventListener("tick",this.tickListener),window.TweenLite){var e=TweenLite.ticker,t=e.frame;e.frame=1,e.wake(!0),e.frame=t}this.dispatchEvent("wake"),this.awake=!0}},t._tick=function(e){if(document.hidden||document.webkitHidden||document.mozHidden)return this.hidden=!0,this._sleep(),void(createjs.Sound&&(createjs.Sound.muted=!0));this.hidden&&(this.hidden=!1,this._awake&&this._wake(),this._perfDelay=3,createjs.Sound&&(createjs.Sound.muted=!1)),this._time+=this._sleepUseTicks?1:e.delta;var t;if(this._perfFPS&&--this._perfDelay<=0&&(t=createjs.Ticker.getMeasuredFPS(1))>-1){var i=1-Math.max(0,Math.min(1,t/this._perfFPS));this._perfCount=Math.max(0,this._perfCount+(0===i?-.2:i*i*.5+.1)),this._perfCount>this._perfThreshold&&(this._perfFPS=0,this.dispatchEvent(new createjs.Event("slow",!1,!0))&&(this.sleep(),this.sleepEnabled=!1))}this.sleepEnabled&&(null!=this._sleepInBoundsT&&this._stage.mouseInBounds&&this._mouseInDoc&&this.wake(1e3*this._sleepInBoundsT),this._sleepy?this.sleep():this._sleepT&&this._getTime()>=this._sleepT&&(this._sleepy=!0))},t._getTime=function(){return this._time},t._getBackingRatio=function(){var e=this._stage.canvas.getContext("2d");return e.backingStorePixelRatio||e.webkitBackingStorePixelRatio||e.mozBackingStorePixelRatio||e.msBackingStorePixelRatio||e.oBackingStorePixelRatio||1},createjs.AdHelper=e}(); -------------------------------------------------------------------------------- /AdHelper/README.md: -------------------------------------------------------------------------------- 1 | AdHelper Class and Sample CreateJS Banner Ad 2 | ======= 3 | 4 | Interactive HTML5 banner ad demonstrating use of the AdHelper class. 5 | 6 | ![ScreenShot](https://raw.githubusercontent.com/CreateJS/html5ads/master/AdHelper/README_1.jpg) 7 | 8 | The AdHelper class is only 2kb over the wire, and provides a number of capabilities for HTML5 banner ads built with 9 | CreateJS: 10 | - detecting if CreateJS is supported on the browser 11 | - displaying alternative content 12 | - pausing & muting while in background tabs 13 | - setting sleep schedules (ex. pause after 15s) 14 | - waking on interaction for configurable time 15 | - ensure full resolution graphics on high DPI screens 16 | - performance monitoring 17 | - time syncing content 18 | 19 | See the documentation in `/docs` and the source of `garyad_deploy.html` for more information. 20 | 21 | The interactive sample ad was created entirely as a Flash Pro HTML5 Canvas document, and has a total "over the wire" 22 | (gzipped) size of only 66kb (including 25kb of audio), excluding the CDN hosted CreateJS libraries. It uses vector 23 | graphics, to provide high fidelity art on any display. 24 | It was created entirely by a designer / illustrator, including the timeline code for interaction. 25 | 26 | Files: 27 | - `AdHelper.js` the unminified AdHelper class 28 | - `AdHelper.min.js` minified AdHelper class 29 | - `docs/` documentation for the AdHelper class 30 | - `garyad_deploy.html` the ad html with AdHelper implemented 31 | - `garyad.fla` the Flash Pro HTML5 Canvas document 32 | - `garyad.html` the html published by Flash Pro 33 | - `garyad.js` the JS library published by Flash Pro 34 | - `index.html` test environment with the ad in an iframe 35 | - `tools` gulp tasks for building the docs and min file 36 | 37 | All art is copyright 2013 gskinner.com, inc. and cannot be used without permission. -------------------------------------------------------------------------------- /AdHelper/README_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CreateJS/html5ads/acc307901503f2ac61511d94ab96a6191d315904/AdHelper/README_1.jpg -------------------------------------------------------------------------------- /AdHelper/docs/api.js: -------------------------------------------------------------------------------- 1 | YUI.add("yuidoc-meta", function(Y) { 2 | Y.YUIDoc = { meta: { 3 | "classes": [ 4 | "AdHelper" 5 | ], 6 | "modules": [], 7 | "allModules": [] 8 | } }; 9 | }); -------------------------------------------------------------------------------- /AdHelper/docs/assets/css/external-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CreateJS/html5ads/acc307901503f2ac61511d94ab96a6191d315904/AdHelper/docs/assets/css/external-small.png -------------------------------------------------------------------------------- /AdHelper/docs/assets/css/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CreateJS/html5ads/acc307901503f2ac61511d94ab96a6191d315904/AdHelper/docs/assets/css/logo.png -------------------------------------------------------------------------------- /AdHelper/docs/assets/css/main.css: -------------------------------------------------------------------------------- 1 | /* 2 | Font sizes for all selectors other than the body are given in percentages, 3 | with 100% equal to 13px. To calculate a font size percentage, multiply the 4 | desired size in pixels by 7.6923076923. 5 | 6 | Here's a quick lookup table: 7 | 8 | 10px - 76.923% 9 | 11px - 84.615% 10 | 12px - 92.308% 11 | 13px - 100% 12 | 14px - 107.692% 13 | 15px - 115.385% 14 | 16px - 123.077% 15 | 17px - 130.769% 16 | 18px - 138.462% 17 | 19px - 146.154% 18 | 20px - 153.846% 19 | */ 20 | 21 | html { 22 | background: #fff; 23 | color: #333; 24 | overflow-y: scroll; 25 | } 26 | 27 | body { 28 | /*font: 13px/1.4 'Lucida Grande', 'Lucida Sans Unicode', 'DejaVu Sans', 'Bitstream Vera Sans', 'Helvetica', 'Arial', sans-serif;*/ 29 | font: 13px/1.4 'Helvetica', 'Arial', sans-serif; 30 | margin: 0; 31 | padding: 0; 32 | } 33 | 34 | /* -- Links ----------------------------------------------------------------- */ 35 | a { 36 | color: #356de4; 37 | text-decoration: none; 38 | } 39 | 40 | .hidden { 41 | display: none; 42 | } 43 | 44 | a:hover { text-decoration: underline; } 45 | 46 | /* "Jump to Table of Contents" link is shown to assistive tools, but hidden from 47 | sight until it's focused. */ 48 | .jump { 49 | position: absolute; 50 | padding: 3px 6px; 51 | left: -99999px; 52 | top: 0; 53 | } 54 | 55 | .jump:focus { left: 40%; } 56 | 57 | /* -- Paragraphs ------------------------------------------------------------ */ 58 | p { margin: 1.3em 0; } 59 | dd p, td p { margin-bottom: 0; } 60 | dd p:first-child, td p:first-child { margin-top: 0; } 61 | 62 | /* -- Headings -------------------------------------------------------------- */ 63 | h1, h2, h3, h4, h5, h6 { 64 | color: #D98527;/*was #f80*/ 65 | font-family: 'Trebuchet MS', sans-serif; 66 | font-weight: bold; 67 | line-height: 1.1; 68 | margin: 1.1em 0 0.5em; 69 | } 70 | 71 | h1 { 72 | font-size: 184.6%; 73 | color: #30418C; 74 | margin: 0.75em 0 0.5em; 75 | } 76 | 77 | h2 { 78 | font-size: 153.846%; 79 | color: #E48A2B; 80 | } 81 | 82 | h3 { font-size: 138.462%; } 83 | 84 | h4 { 85 | border-bottom: 1px solid #DBDFEA; 86 | color: #E48A2B; 87 | font-size: 115.385%; 88 | font-weight: normal; 89 | padding-bottom: 2px; 90 | } 91 | 92 | h5, h6 { font-size: 107.692%; } 93 | 94 | /* -- Code and examples ----------------------------------------------------- */ 95 | code, kbd, pre, samp { 96 | font-family: Menlo, Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace; 97 | font-size: 92.308%; 98 | line-height: 1.35; 99 | } 100 | 101 | p code, p kbd, p samp, li code { 102 | background: #FCFBFA; 103 | border: 1px solid #EFEEED; 104 | padding: 0 3px; 105 | } 106 | 107 | a code, a kbd, a samp, 108 | pre code, pre kbd, pre samp, 109 | table code, table kbd, table samp, 110 | .intro code, .intro kbd, .intro samp, 111 | .toc code, .toc kbd, .toc samp { 112 | background: none; 113 | border: none; 114 | padding: 0; 115 | } 116 | 117 | pre.code, pre.terminal, pre.cmd { 118 | overflow-x: auto; 119 | *overflow-x: scroll; 120 | padding: 0.3em 0.6em; 121 | } 122 | 123 | pre.code { 124 | background: #FCFBFA; 125 | border: 1px solid #EFEEED; 126 | border-left-width: 5px; 127 | } 128 | 129 | pre.terminal, pre.cmd { 130 | background: #F0EFFC; 131 | border: 1px solid #D0CBFB; 132 | border-left: 5px solid #D0CBFB; 133 | } 134 | 135 | /* Don't reduce the font size of // elements inside
136 |    blocks. */
137 | pre code, pre kbd, pre samp { font-size: 100%; }
138 | 
139 | /* Used to denote text that shouldn't be selectable, such as line numbers or
140 |    shell prompts. Guess which browser this doesn't work in. */
141 | .noselect {
142 |     -moz-user-select: -moz-none;
143 |     -khtml-user-select: none;
144 |     -webkit-user-select: none;
145 |     -o-user-select: none;
146 |     user-select: none;
147 | }
148 | 
149 | /* -- Lists ----------------------------------------------------------------- */
150 | dd { margin: 0.2em 0 0.7em 1em; }
151 | dl { margin: 1em 0; }
152 | dt { font-weight: bold; }
153 | 
154 | /* -- Tables ---------------------------------------------------------------- */
155 | caption, th { text-align: left; }
156 | 
157 | table {
158 |     border-collapse: collapse;
159 |     width: 100%;
160 | }
161 | 
162 | td, th {
163 |     border: 1px solid #fff;
164 |     padding: 5px 12px;
165 |     vertical-align: top;
166 | }
167 | 
168 | td { background: #E6E9F5; }
169 | td dl { margin: 0; }
170 | td dl dl { margin: 1em 0; }
171 | td pre:first-child { margin-top: 0; }
172 | 
173 | th {
174 |     background: #D2D7E6;/*#97A0BF*/
175 |     border-bottom: none;
176 |     border-top: none;
177 |     color: #000;/*#FFF1D5*/
178 |     font-family: 'Trebuchet MS', sans-serif;
179 |     font-weight: bold;
180 |     line-height: 1.3;
181 |     white-space: nowrap;
182 | }
183 | 
184 | 
185 | /* -- Layout and Content ---------------------------------------------------- */
186 | #doc {
187 |     margin: auto;
188 |     min-width: 1024px;
189 | }
190 | 
191 | .content { padding: 0 20px 0 25px; }
192 | 
193 | .sidebar {
194 |     padding: 0 15px 0 10px;
195 | }
196 | #bd {
197 |     padding: 7px 0 130px;
198 |     position: relative;
199 |     width: 99%;
200 | }
201 | 
202 | /* -- Table of Contents ----------------------------------------------------- */
203 | 
204 | /* The #toc id refers to the single global table of contents, while the .toc
205 |    class refers to generic TOC lists that could be used throughout the page. */
206 | 
207 | .toc code, .toc kbd, .toc samp { font-size: 100%; }
208 | .toc li { font-weight: bold; }
209 | .toc li li { font-weight: normal; }
210 | 
211 | /* -- Intro and Example Boxes ----------------------------------------------- */
212 | /*
213 | .intro, .example { margin-bottom: 2em; }
214 | .example {
215 |     -moz-border-radius: 4px;
216 |     -webkit-border-radius: 4px;
217 |     border-radius: 4px;
218 |     -moz-box-shadow: 0 0 5px #bfbfbf;
219 |     -webkit-box-shadow: 0 0 5px #bfbfbf;
220 |     box-shadow: 0 0 5px #bfbfbf;
221 |     padding: 1em;
222 | }
223 | .intro {
224 |     background: none repeat scroll 0 0 #F0F1F8; border: 1px solid #D4D8EB; padding: 0 1em;
225 | }
226 | */
227 | 
228 | /* -- Other Styles ---------------------------------------------------------- */
229 | 
230 | /* These are probably YUI-specific, and should be moved out of Selleck's default
231 |    theme. */
232 | 
233 | .button {
234 |     border: 1px solid #dadada;
235 |     -moz-border-radius: 3px;
236 |     -webkit-border-radius: 3px;
237 |     border-radius: 3px;
238 |     color: #444;
239 |     display: inline-block;
240 |     font-family: Helvetica, Arial, sans-serif;
241 |     font-size: 92.308%;
242 |     font-weight: bold;
243 |     padding: 4px 13px 3px;
244 |     -moz-text-shadow: 1px 1px 0 #fff;
245 |     -webkit-text-shadow: 1px 1px 0 #fff;
246 |     text-shadow: 1px 1px 0 #fff;
247 |     white-space: nowrap;
248 | 
249 |     background: #EFEFEF; /* old browsers */
250 |     background: -moz-linear-gradient(top, #f5f5f5 0%, #efefef 50%, #e5e5e5 51%, #dfdfdf 100%); /* firefox */
251 |     background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f5f5f5), color-stop(50%,#efefef), color-stop(51%,#e5e5e5), color-stop(100%,#dfdfdf)); /* webkit */
252 |     filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f5f5f5', endColorstr='#dfdfdf',GradientType=0 ); /* ie */
253 | }
254 | 
255 | .button:hover {
256 |     border-color: #466899;
257 |     color: #fff;
258 |     text-decoration: none;
259 |     -moz-text-shadow: 1px 1px 0 #222;
260 |     -webkit-text-shadow: 1px 1px 0 #222;
261 |     text-shadow: 1px 1px 0 #222;
262 | 
263 |     background: #6396D8; /* old browsers */
264 |     background: -moz-linear-gradient(top, #6396D8 0%, #5A83BC 50%, #547AB7 51%, #466899 100%); /* firefox */
265 |     background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#6396D8), color-stop(50%,#5A83BC), color-stop(51%,#547AB7), color-stop(100%,#466899)); /* webkit */
266 |     filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#6396D8', endColorstr='#466899',GradientType=0 ); /* ie */
267 | }
268 | 
269 | .newwindow { text-align: center; }
270 | 
271 | .header .version em {
272 |     display: block;
273 |     text-align: right;
274 | }
275 | 
276 | 
277 | #classdocs .item {
278 |     border-bottom: 1px solid #466899;
279 |     margin: 1em 0;
280 |     padding: 1.5em;
281 | }
282 | 
283 | #classdocs .item .params p,
284 |     #classdocs .item .returns p,{
285 |     display: inline;
286 | }
287 | 
288 | #classdocs .item em code, #classdocs .item em.comment {
289 |     color: green;
290 | }
291 | 
292 | #classdocs .item em.comment a {
293 |     color: green;
294 |     text-decoration: underline;
295 | }
296 | 
297 | #classdocs .foundat {
298 |     font-size: 11px;
299 |     font-style: normal;
300 | }
301 | 
302 | .attrs .emits {
303 |     margin-left: 2em;
304 |     padding: .5em;
305 |     border-left: 1px dashed #ccc;
306 | }
307 | 
308 | abbr {
309 |     border-bottom: 1px dashed #ccc;
310 |     font-size: 80%;
311 |     cursor: help;
312 | }
313 | 
314 | .prettyprint li.L0, 
315 | .prettyprint li.L1, 
316 | .prettyprint li.L2, 
317 | .prettyprint li.L3, 
318 | .prettyprint li.L5, 
319 | .prettyprint li.L6, 
320 | .prettyprint li.L7, 
321 | .prettyprint li.L8 {
322 |     list-style: decimal;
323 | }
324 | 
325 | ul li p {
326 |     margin-top: 0;
327 | }
328 | 
329 | .method .name {
330 |     font-size: 110%;
331 | }
332 | 
333 | .apidocs .methods .extends .method,
334 | .apidocs .properties .extends .property,
335 | .apidocs .attrs .extends .attr,
336 | .apidocs .events .extends .event {
337 |     font-weight: bold;
338 | }
339 | 
340 | .apidocs .methods .extends .inherited,
341 | .apidocs .properties .extends .inherited,
342 | .apidocs .attrs .extends .inherited,
343 | .apidocs .events .extends .inherited {
344 |     font-weight: normal;
345 | }
346 | 
347 | #hd {
348 |     background: whiteSmoke;
349 |     background: -moz-linear-gradient(top,#DCDBD9 0,#F6F5F3 100%);
350 |     background: -webkit-gradient(linear,left top,left bottom,color-stop(0%,#DCDBD9),color-stop(100%,#F6F5F3));
351 |     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#dcdbd9',endColorstr='#F6F5F3',GradientType=0);
352 |     border-bottom: 1px solid #DFDFDF;
353 |     padding: 0 15px 1px 20px;
354 |     margin-bottom: 15px;
355 | }
356 | 
357 | #hd img {
358 |     margin-right: 10px;
359 |     vertical-align: middle;
360 | }
361 | 
362 | 
363 | /* -- API Docs CSS ---------------------------------------------------------- */
364 | 
365 | /*
366 | This file is organized so that more generic styles are nearer the top, and more
367 | specific styles are nearer the bottom of the file. This allows us to take full
368 | advantage of the cascade to avoid redundant style rules. Please respect this
369 | convention when making changes.
370 | */
371 | 
372 | /* -- Generic TabView styles ------------------------------------------------ */
373 | 
374 | /*
375 | These styles apply to all API doc tabviews. To change styles only for a
376 | specific tabview, see the other sections below.
377 | */
378 | 
379 | .yui3-js-enabled .apidocs .tabview {
380 |     visibility: hidden; /* Hide until the TabView finishes rendering. */
381 |     _visibility: visible;
382 | }
383 | 
384 | .apidocs .tabview.yui3-tabview-content { visibility: visible; }
385 | .apidocs .tabview .yui3-tabview-panel { background: #fff; }
386 | 
387 | /* -- Generic Content Styles ------------------------------------------------ */
388 | 
389 | /* Headings */
390 | h2, h3, h4, h5, h6 {
391 |     border: none;
392 |     color: #30418C;
393 |     font-weight: bold;
394 |     text-decoration: none;
395 | }
396 | 
397 | .link-docs {
398 |     float: right;
399 |     font-size: 15px;
400 |     margin: 4px 4px 6px;
401 |     padding: 6px 30px 5px;
402 | }
403 | 
404 | .apidocs { zoom: 1; }
405 | 
406 | /* Generic box styles. */
407 | .apidocs .box {
408 |     border: 1px solid;
409 |     border-radius: 3px;
410 |     margin: 1em 0;
411 |     padding: 0 1em;
412 | }
413 | 
414 | /* A flag is a compact, capsule-like indicator of some kind. It's used to
415 |    indicate private and protected items, item return types, etc. in an
416 |    attractive and unobtrusive way. */
417 | .apidocs .flag {
418 |     background: #bababa;
419 |     border-radius: 3px;
420 |     color: #fff;
421 |     font-size: 11px;
422 |     margin: 0 0.5em;
423 |     padding: 2px 4px 1px;
424 | }
425 | 
426 | /* Class/module metadata such as "Uses", "Extends", "Defined in", etc. */
427 | .apidocs .meta {
428 |     background: #f9f9f9;
429 |     border-color: #efefef;
430 |     color: #555;
431 |     font-size: 11px;
432 |     padding: 3px 6px;
433 | }
434 | 
435 | .apidocs .meta p { margin: 0; }
436 | 
437 | /* Deprecation warning. */
438 | .apidocs .box.deprecated,
439 | .apidocs .flag.deprecated {
440 |     background: #fdac9f;
441 |     border: 1px solid #fd7775;
442 | }
443 | 
444 | .apidocs .box.deprecated p { margin: 0.5em 0; }
445 | .apidocs .flag.deprecated { color: #333; }
446 | 
447 | /* Module/Class intro description. */
448 | .apidocs .intro {
449 |     background: #f0f1f8;
450 |     border-color: #d4d8eb;
451 | }
452 | 
453 | /* Loading spinners. */
454 | #bd.loading .apidocs,
455 | #api-list.loading .yui3-tabview-panel {
456 |     background: #fff url(../img/spinner.gif) no-repeat center 70px;
457 |     min-height: 150px;
458 | }
459 | 
460 | #bd.loading .apidocs .content,
461 | #api-list.loading .yui3-tabview-panel .apis {
462 |     display: none;
463 | }
464 | 
465 | .apidocs .no-visible-items { color: #666; }
466 | 
467 | /* Generic inline list. */
468 | .apidocs ul.inline {
469 |     display: inline;
470 |     list-style: none;
471 |     margin: 0;
472 |     padding: 0;
473 | }
474 | 
475 | .apidocs ul.inline li { display: inline; }
476 | 
477 | /* Comma-separated list. */
478 | .apidocs ul.commas li:after { content: ','; }
479 | .apidocs ul.commas li:last-child:after { content: ''; }
480 | 
481 | /* Keyboard shortcuts. */
482 | kbd .cmd { font-family: Monaco, Helvetica; }
483 | 
484 | /* -- Generic Access Level styles ------------------------------------------- */
485 | .apidocs .item.protected,
486 | .apidocs .item.private,
487 | .apidocs .index-item.protected,
488 | .apidocs .index-item.deprecated,
489 | .apidocs .index-item.private {
490 |     display: none;
491 | }
492 | 
493 | .show-deprecated .item.deprecated,
494 | .show-deprecated .index-item.deprecated,
495 | .show-protected .item.protected,
496 | .show-protected .index-item.protected,
497 | .show-private .item.private,
498 | .show-private .index-item.private {
499 |     display: block;
500 | }
501 | 
502 | .hide-inherited .item.inherited,
503 | .hide-inherited .index-item.inherited {
504 |     display: none;
505 | }
506 | 
507 | /* -- Generic Item Index styles --------------------------------------------- */
508 | .apidocs .index { margin: 1.5em 0 3em; }
509 | 
510 | .apidocs .index h3 {
511 |     border-bottom: 1px solid #efefef;
512 |     color: #333;
513 |     font-size: 13px;
514 |     margin: 2em 0 0.6em;
515 |     padding-bottom: 2px;
516 | }
517 | 
518 | .apidocs .index .no-visible-items { margin-top: 2em; }
519 | 
520 | .apidocs .index-list {
521 |     border-color: #efefef;
522 |     font-size: 12px;
523 |     list-style: none;
524 |     margin: 0;
525 |     padding: 0;
526 |     -moz-column-count: 4;
527 |     -moz-column-gap: 10px;
528 |     -moz-column-width: 170px;
529 |     -ms-column-count: 4;
530 |     -ms-column-gap: 10px;
531 |     -ms-column-width: 170px;
532 |     -o-column-count: 4;
533 |     -o-column-gap: 10px;
534 |     -o-column-width: 170px;
535 |     -webkit-column-count: 4;
536 |     -webkit-column-gap: 10px;
537 |     -webkit-column-width: 170px;
538 |     column-count: 4;
539 |     column-gap: 10px;
540 |     column-width: 170px;
541 | }
542 | 
543 | .apidocs .no-columns .index-list {
544 |     -moz-column-count: 1;
545 |     -ms-column-count: 1;
546 |     -o-column-count: 1;
547 |     -webkit-column-count: 1;
548 |     column-count: 1;
549 | }
550 | 
551 | .apidocs .index-item { white-space: nowrap; }
552 | 
553 | .apidocs .index-item .flag {
554 |     background: none;
555 |     border: none;
556 |     color: #afafaf;
557 |     display: inline;
558 |     margin: 0 0 0 0.2em;
559 |     padding: 0;
560 | }
561 | 
562 | /* -- Generic API item styles ----------------------------------------------- */
563 | .apidocs .args {
564 |     display: inline;
565 |     margin: 0 0.5em;
566 | }
567 | 
568 | .apidocs .flag.chainable { background: #46ca3b; }
569 | .apidocs .flag.protected { background: #9b86fc; }
570 | .apidocs .flag.private { background: #fd6b1b; }
571 | .apidocs .flag.async { background: #356de4; }
572 | .apidocs .flag.required { background: #e60923; }
573 | 
574 | .apidocs .item {
575 |     border-bottom: 1px solid #efefef;
576 |     margin: 1.5em 0 2em;
577 |     padding-bottom: 2em;
578 | }
579 | 
580 | .apidocs .item h4,
581 | .apidocs .item h5,
582 | .apidocs .item h6 {
583 |     color: #333;
584 |     font-family: inherit;
585 |     font-size: 100%;
586 | }
587 | 
588 | .apidocs .item .description p,
589 | .apidocs .item pre.code {
590 |     margin: 1em 0 0;
591 | }
592 | 
593 | .apidocs .item .meta {
594 |     background: none;
595 |     border: none;
596 |     padding: 0;
597 | }
598 | 
599 | .apidocs .item .name {
600 |     display: inline;
601 |     font-size: 14px;
602 | }
603 | 
604 | .apidocs .item .type,
605 | .apidocs .item .type a,
606 | .apidocs .returns-inline {
607 |     color: #555;
608 | }
609 | 
610 | .apidocs .item .type,
611 | .apidocs .returns-inline {
612 |     font-size: 11px;
613 |     margin: 0 0 0 0;
614 | }
615 | 
616 | .apidocs .item .type a { border-bottom: 1px dotted #afafaf; }
617 | .apidocs .item .type a:hover { border: none; }
618 | 
619 | /* -- Item Parameter List --------------------------------------------------- */
620 | .apidocs .params-list {
621 |     list-style: square;
622 |     margin: 1em 0 0 2em;
623 |     padding: 0;
624 | }
625 | 
626 | .apidocs .param { margin-bottom: 1em; }
627 | 
628 | .apidocs .param .type,
629 | .apidocs .param .type a {
630 |     color: #666;
631 | }
632 | 
633 | .apidocs .param .type {
634 |     margin: 0 0 0 0.5em;
635 |     *margin-left: 0.5em;
636 | }
637 | 
638 | .apidocs .param-name { font-weight: bold; }
639 | 
640 | /* -- Item "Emits" block ---------------------------------------------------- */
641 | .apidocs .item .emits {
642 |     background: #f9f9f9;
643 |     border-color: #eaeaea;
644 | }
645 | 
646 | /* -- Item "Returns" block -------------------------------------------------- */
647 | .apidocs .item .returns .type,
648 | .apidocs .item .returns .type a {
649 |     font-size: 100%;
650 |     margin: 0;
651 | }
652 | 
653 | /* -- Class Constructor block ----------------------------------------------- */
654 | .apidocs .constructor .item {
655 |     border: none;
656 |     padding-bottom: 0;
657 | }
658 | 
659 | /* -- File Source View ------------------------------------------------------ */
660 | .apidocs .file pre.code,
661 | #doc .apidocs .file pre.prettyprint {
662 |     background: inherit;
663 |     border: none;
664 |     overflow: visible;
665 |     padding: 0;
666 | }
667 | 
668 | .apidocs .L0,
669 | .apidocs .L1,
670 | .apidocs .L2,
671 | .apidocs .L3,
672 | .apidocs .L4,
673 | .apidocs .L5,
674 | .apidocs .L6,
675 | .apidocs .L7,
676 | .apidocs .L8,
677 | .apidocs .L9 {
678 |     background: inherit;
679 | }
680 | 
681 | /* -- Submodule List -------------------------------------------------------- */
682 | .apidocs .module-submodule-description {
683 |     font-size: 12px;
684 |     margin: 0.3em 0 1em;
685 | }
686 | 
687 | .apidocs .module-submodule-description p:first-child { margin-top: 0; }
688 | 
689 | /* -- Sidebar TabView ------------------------------------------------------- */
690 | #api-tabview { margin-top: 0.6em; }
691 | 
692 | #api-tabview-filter,
693 | #api-tabview-panel {
694 |     border: 1px solid #dfdfdf;
695 | }
696 | 
697 | #api-tabview-filter {
698 |     border-bottom: none;
699 |     border-top: none;
700 |     padding: 0.6em 10px 0 10px;
701 | }
702 | 
703 | #api-tabview-panel { border-top: none; }
704 | #api-filter { width: 97%; }
705 | 
706 | /* -- Content TabView ------------------------------------------------------- */
707 | #classdocs .yui3-tabview-panel { border: none; }
708 | 
709 | /* -- Source File Contents -------------------------------------------------- */
710 | .prettyprint li.L0,
711 | .prettyprint li.L1,
712 | .prettyprint li.L2,
713 | .prettyprint li.L3,
714 | .prettyprint li.L5,
715 | .prettyprint li.L6,
716 | .prettyprint li.L7,
717 | .prettyprint li.L8 {
718 |     list-style: decimal;
719 | }
720 | 
721 | /* -- API options ----------------------------------------------------------- */
722 | #api-options {
723 |     font-size: 11px;
724 |     margin-top: 2.2em;
725 |     position: absolute;
726 |     right: 1.5em;
727 | }
728 | 
729 | /*#api-options label { margin-right: 0.6em; }*/
730 | 
731 | /* -- API list -------------------------------------------------------------- */
732 | #api-list {
733 |     margin-top: 1.5em;
734 |     *zoom: 1;
735 | }
736 | 
737 | .apis {
738 |     font-size: 12px;
739 |     line-height: 1.4;
740 |     list-style: none;
741 |     margin: 0;
742 |     padding: 0.5em 0 0.5em 0.4em;
743 | }
744 | 
745 | .apis a {
746 |     border: 1px solid transparent;
747 |     display: block;
748 |     margin: 0 0 0 -4px;
749 |     padding: 1px 4px 0;
750 |     text-decoration: none;
751 |     _border: none;
752 |     _display: inline;
753 | }
754 | 
755 | .apis a:hover,
756 | .apis a:focus {
757 |     background: #E8EDFC;
758 |     background: -moz-linear-gradient(top, #e8edfc 0%, #becef7 100%);
759 |     background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#E8EDFC), color-stop(100%,#BECEF7));
760 |     border-color: #AAC0FA;
761 |     border-radius: 3px;
762 |     color: #333;
763 |     outline: none;
764 | }
765 | 
766 | .api-list-item a:hover,
767 | .api-list-item a:focus {
768 |     font-weight: bold;
769 |     text-shadow: 1px 1px 1px #fff;
770 | }
771 | 
772 | .apis .message { color: #888; }
773 | .apis .result a { padding: 3px 5px 2px; }
774 | 
775 | .apis .result .type {
776 |     right: 4px;
777 |     top: 7px;
778 | }
779 | 
780 | .api-list-item .yui3-highlight {
781 |     font-weight: bold;
782 | }
783 | 
784 | 


--------------------------------------------------------------------------------
/AdHelper/docs/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateJS/html5ads/acc307901503f2ac61511d94ab96a6191d315904/AdHelper/docs/assets/favicon.png


--------------------------------------------------------------------------------
/AdHelper/docs/assets/img/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateJS/html5ads/acc307901503f2ac61511d94ab96a6191d315904/AdHelper/docs/assets/img/spinner.gif


--------------------------------------------------------------------------------
/AdHelper/docs/assets/index.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         Redirector
 5 |         
 6 |     
 7 |     
 8 |         Click here to redirect
 9 |     
10 | 
11 | 


--------------------------------------------------------------------------------
/AdHelper/docs/assets/js/api-filter.js:
--------------------------------------------------------------------------------
 1 | YUI.add('api-filter', function (Y) {
 2 | 
 3 | Y.APIFilter = Y.Base.create('apiFilter', Y.Base, [Y.AutoCompleteBase], {
 4 |     // -- Initializer ----------------------------------------------------------
 5 |     initializer: function () {
 6 |         this._bindUIACBase();
 7 |         this._syncUIACBase();
 8 |     },
 9 |     getDisplayName: function(name) {
10 | 
11 |         Y.each(Y.YUIDoc.meta.allModules, function(i) {
12 |             if (i.name === name && i.displayName) {
13 |                 name = i.displayName;
14 |             }
15 |         });
16 | 
17 |         return name;
18 |     }
19 | 
20 | }, {
21 |     // -- Attributes -----------------------------------------------------------
22 |     ATTRS: {
23 |         resultHighlighter: {
24 |             value: 'phraseMatch'
25 |         },
26 | 
27 |         // May be set to "classes" or "modules".
28 |         queryType: {
29 |             value: 'classes'
30 |         },
31 | 
32 |         source: {
33 |             valueFn: function() {
34 |                 var self = this;
35 |                 return function(q) {
36 |                     var data = Y.YUIDoc.meta[self.get('queryType')],
37 |                         out = [];
38 |                     Y.each(data, function(v) {
39 |                         if (v.toLowerCase().indexOf(q.toLowerCase()) > -1) {
40 |                             out.push(v);
41 |                         }
42 |                     });
43 |                     return out;
44 |                 };
45 |             }
46 |         }
47 |     }
48 | });
49 | 
50 | }, '3.4.0', {requires: [
51 |     'autocomplete-base', 'autocomplete-highlighters', 'autocomplete-sources'
52 | ]});
53 | 


--------------------------------------------------------------------------------
/AdHelper/docs/assets/js/api-list.js:
--------------------------------------------------------------------------------
  1 | YUI.add('api-list', function (Y) {
  2 | 
  3 | var Lang   = Y.Lang,
  4 |     YArray = Y.Array,
  5 | 
  6 |     APIList = Y.namespace('APIList'),
  7 | 
  8 |     classesNode    = Y.one('#api-classes'),
  9 |     inputNode      = Y.one('#api-filter'),
 10 |     modulesNode    = Y.one('#api-modules'),
 11 |     tabviewNode    = Y.one('#api-tabview'),
 12 | 
 13 |     tabs = APIList.tabs = {},
 14 | 
 15 |     filter = APIList.filter = new Y.APIFilter({
 16 |         inputNode : inputNode,
 17 |         maxResults: 1000,
 18 | 
 19 |         on: {
 20 |             results: onFilterResults
 21 |         }
 22 |     }),
 23 | 
 24 |     search = APIList.search = new Y.APISearch({
 25 |         inputNode : inputNode,
 26 |         maxResults: 100,
 27 | 
 28 |         on: {
 29 |             clear  : onSearchClear,
 30 |             results: onSearchResults
 31 |         }
 32 |     }),
 33 | 
 34 |     tabview = APIList.tabview = new Y.TabView({
 35 |         srcNode  : tabviewNode,
 36 |         panelNode: '#api-tabview-panel',
 37 |         render   : true,
 38 | 
 39 |         on: {
 40 |             selectionChange: onTabSelectionChange
 41 |         }
 42 |     }),
 43 | 
 44 |     focusManager = APIList.focusManager = tabviewNode.plug(Y.Plugin.NodeFocusManager, {
 45 |         circular   : true,
 46 |         descendants: '#api-filter, .yui3-tab-panel-selected .api-list-item a, .yui3-tab-panel-selected .result a',
 47 |         keys       : {next: 'down:40', previous: 'down:38'}
 48 |     }).focusManager,
 49 | 
 50 |     LIST_ITEM_TEMPLATE =
 51 |         '
  • ' + 52 | '{displayName}' + 53 | '
  • '; 54 | 55 | // -- Init --------------------------------------------------------------------- 56 | 57 | // Duckpunch FocusManager's key event handling to prevent it from handling key 58 | // events when a modifier is pressed. 59 | Y.before(function (e, activeDescendant) { 60 | if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { 61 | return new Y.Do.Prevent(); 62 | } 63 | }, focusManager, '_focusPrevious', focusManager); 64 | 65 | Y.before(function (e, activeDescendant) { 66 | if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { 67 | return new Y.Do.Prevent(); 68 | } 69 | }, focusManager, '_focusNext', focusManager); 70 | 71 | // Create a mapping of tabs in the tabview so we can refer to them easily later. 72 | tabview.each(function (tab, index) { 73 | var name = tab.get('label').toLowerCase(); 74 | 75 | tabs[name] = { 76 | index: index, 77 | name : name, 78 | tab : tab 79 | }; 80 | }); 81 | 82 | // Switch tabs on Ctrl/Cmd-Left/Right arrows. 83 | tabviewNode.on('key', onTabSwitchKey, 'down:37,39'); 84 | 85 | // Focus the filter input when the `/` key is pressed. 86 | Y.one(Y.config.doc).on('key', onSearchKey, 'down:83'); 87 | 88 | // Keep the Focus Manager up to date. 89 | inputNode.on('focus', function () { 90 | focusManager.set('activeDescendant', inputNode); 91 | }); 92 | 93 | // Update all tabview links to resolved URLs. 94 | tabview.get('panelNode').all('a').each(function (link) { 95 | link.setAttribute('href', link.get('href')); 96 | }); 97 | 98 | // -- Private Functions -------------------------------------------------------- 99 | function getFilterResultNode() { 100 | return filter.get('queryType') === 'classes' ? classesNode : modulesNode; 101 | } 102 | 103 | // -- Event Handlers ----------------------------------------------------------- 104 | function onFilterResults(e) { 105 | var frag = Y.one(Y.config.doc.createDocumentFragment()), 106 | resultNode = getFilterResultNode(), 107 | typePlural = filter.get('queryType'), 108 | typeSingular = typePlural === 'classes' ? 'class' : 'module'; 109 | 110 | if (e.results.length) { 111 | YArray.each(e.results, function (result) { 112 | frag.append(Lang.sub(LIST_ITEM_TEMPLATE, { 113 | rootPath : APIList.rootPath, 114 | displayName : filter.getDisplayName(result.highlighted), 115 | name : result.text, 116 | typePlural : typePlural, 117 | typeSingular: typeSingular 118 | })); 119 | }); 120 | } else { 121 | frag.append( 122 | '
  • ' + 123 | 'No ' + typePlural + ' found.' + 124 | '
  • ' 125 | ); 126 | } 127 | 128 | resultNode.empty(true); 129 | resultNode.append(frag); 130 | 131 | focusManager.refresh(); 132 | } 133 | 134 | function onSearchClear(e) { 135 | 136 | focusManager.refresh(); 137 | } 138 | 139 | function onSearchKey(e) { 140 | var target = e.target; 141 | 142 | if (target.test('input,select,textarea') 143 | || target.get('isContentEditable')) { 144 | return; 145 | } 146 | 147 | e.preventDefault(); 148 | 149 | inputNode.focus(); 150 | focusManager.refresh(); 151 | } 152 | 153 | function onSearchResults(e) { 154 | var frag = Y.one(Y.config.doc.createDocumentFragment()); 155 | 156 | if (e.results.length) { 157 | YArray.each(e.results, function (result) { 158 | frag.append(result.display); 159 | }); 160 | } else { 161 | frag.append( 162 | '
  • ' + 163 | 'No results found. Maybe you\'ll have better luck with a ' + 164 | 'different query?' + 165 | '
  • ' 166 | ); 167 | } 168 | 169 | 170 | focusManager.refresh(); 171 | } 172 | 173 | function onTabSelectionChange(e) { 174 | var tab = e.newVal, 175 | name = tab.get('label').toLowerCase(); 176 | 177 | tabs.selected = { 178 | index: tab.get('index'), 179 | name : name, 180 | tab : tab 181 | }; 182 | 183 | switch (name) { 184 | case 'classes': // fallthru 185 | case 'modules': 186 | filter.setAttrs({ 187 | minQueryLength: 0, 188 | queryType : name 189 | }); 190 | 191 | search.set('minQueryLength', -1); 192 | 193 | // Only send a request if this isn't the initially-selected tab. 194 | if (e.prevVal) { 195 | filter.sendRequest(filter.get('value')); 196 | } 197 | break; 198 | 199 | case 'everything': 200 | filter.set('minQueryLength', -1); 201 | search.set('minQueryLength', 1); 202 | 203 | if (search.get('value')) { 204 | search.sendRequest(search.get('value')); 205 | } else { 206 | inputNode.focus(); 207 | } 208 | break; 209 | 210 | default: 211 | // WTF? We shouldn't be here! 212 | filter.set('minQueryLength', -1); 213 | search.set('minQueryLength', -1); 214 | } 215 | 216 | if (focusManager) { 217 | setTimeout(function () { 218 | focusManager.refresh(); 219 | }, 1); 220 | } 221 | } 222 | 223 | function onTabSwitchKey(e) { 224 | var currentTabIndex = tabs.selected.index; 225 | 226 | if (!(e.ctrlKey || e.metaKey)) { 227 | return; 228 | } 229 | 230 | e.preventDefault(); 231 | 232 | switch (e.keyCode) { 233 | case 37: // left arrow 234 | if (currentTabIndex > 0) { 235 | tabview.selectChild(currentTabIndex - 1); 236 | inputNode.focus(); 237 | } 238 | break; 239 | 240 | case 39: // right arrow 241 | if (currentTabIndex < (Y.Object.size(tabs) - 2)) { 242 | tabview.selectChild(currentTabIndex + 1); 243 | inputNode.focus(); 244 | } 245 | break; 246 | } 247 | } 248 | 249 | }, '3.4.0', {requires: [ 250 | 'api-filter', 'api-search', 'event-key', 'node-focusmanager', 'tabview' 251 | ]}); 252 | -------------------------------------------------------------------------------- /AdHelper/docs/assets/js/api-search.js: -------------------------------------------------------------------------------- 1 | YUI.add('api-search', function (Y) { 2 | 3 | var Lang = Y.Lang, 4 | Node = Y.Node, 5 | YArray = Y.Array; 6 | 7 | Y.APISearch = Y.Base.create('apiSearch', Y.Base, [Y.AutoCompleteBase], { 8 | // -- Public Properties ---------------------------------------------------- 9 | RESULT_TEMPLATE: 10 | '
  • ' + 11 | '' + 12 | '

    {name}

    ' + 13 | '{resultType}' + 14 | '
    {description}
    ' + 15 | '{class}' + 16 | '
    ' + 17 | '
  • ', 18 | 19 | // -- Initializer ---------------------------------------------------------- 20 | initializer: function () { 21 | this._bindUIACBase(); 22 | this._syncUIACBase(); 23 | }, 24 | 25 | // -- Protected Methods ---------------------------------------------------- 26 | _apiResultFilter: function (query, results) { 27 | // Filter components out of the results. 28 | return YArray.filter(results, function (result) { 29 | return result.raw.resultType === 'component' ? false : result; 30 | }); 31 | }, 32 | 33 | _apiResultFormatter: function (query, results) { 34 | return YArray.map(results, function (result) { 35 | var raw = Y.merge(result.raw), // create a copy 36 | desc = raw.description || ''; 37 | 38 | // Convert description to text and truncate it if necessary. 39 | desc = Node.create('
    ' + desc + '
    ').get('text'); 40 | 41 | if (desc.length > 65) { 42 | desc = Y.Escape.html(desc.substr(0, 65)) + ' …'; 43 | } else { 44 | desc = Y.Escape.html(desc); 45 | } 46 | 47 | raw['class'] || (raw['class'] = ''); 48 | raw.description = desc; 49 | 50 | // Use the highlighted result name. 51 | raw.name = result.highlighted; 52 | 53 | return Lang.sub(this.RESULT_TEMPLATE, raw); 54 | }, this); 55 | }, 56 | 57 | _apiTextLocator: function (result) { 58 | return result.displayName || result.name; 59 | } 60 | }, { 61 | // -- Attributes ----------------------------------------------------------- 62 | ATTRS: { 63 | resultFormatter: { 64 | valueFn: function () { 65 | return this._apiResultFormatter; 66 | } 67 | }, 68 | 69 | resultFilters: { 70 | valueFn: function () { 71 | return this._apiResultFilter; 72 | } 73 | }, 74 | 75 | resultHighlighter: { 76 | value: 'phraseMatch' 77 | }, 78 | 79 | resultListLocator: { 80 | value: 'data.results' 81 | }, 82 | 83 | resultTextLocator: { 84 | valueFn: function () { 85 | return this._apiTextLocator; 86 | } 87 | }, 88 | 89 | source: { 90 | value: '/api/v1/search?q={query}&count={maxResults}' 91 | } 92 | } 93 | }); 94 | 95 | }, '3.4.0', {requires: [ 96 | 'autocomplete-base', 'autocomplete-highlighters', 'autocomplete-sources', 97 | 'escape' 98 | ]}); 99 | -------------------------------------------------------------------------------- /AdHelper/docs/assets/js/apidocs.js: -------------------------------------------------------------------------------- 1 | YUI().use( 2 | 'yuidoc-meta', 3 | 'api-list', 'history-hash', 'node-screen', 'node-style', 'pjax', 4 | function (Y) { 5 | 6 | var win = Y.config.win, 7 | localStorage = win.localStorage, 8 | 9 | bdNode = Y.one('#bd'), 10 | 11 | pjax, 12 | defaultRoute, 13 | 14 | classTabView, 15 | selectedTab; 16 | 17 | // Kill pjax functionality unless serving over HTTP. 18 | if (!Y.getLocation().protocol.match(/^https?\:/)) { 19 | Y.Router.html5 = false; 20 | } 21 | 22 | // Create the default route with middleware which enables syntax highlighting 23 | // on the loaded content. 24 | defaultRoute = Y.Pjax.defaultRoute.concat(function (req, res, next) { 25 | prettyPrint(); 26 | bdNode.removeClass('loading'); 27 | 28 | next(); 29 | }); 30 | 31 | pjax = new Y.Pjax({ 32 | container : '#docs-main', 33 | contentSelector: '#docs-main > .content', 34 | linkSelector : '#bd a', 35 | titleSelector : '#xhr-title', 36 | 37 | navigateOnHash: true, 38 | root : '/', 39 | routes : [ 40 | // -- / ---------------------------------------------------------------- 41 | { 42 | path : '/(index.html)?', 43 | callbacks: defaultRoute 44 | }, 45 | 46 | // -- /classes/* ------------------------------------------------------- 47 | { 48 | path : '/classes/:class.html*', 49 | callbacks: [defaultRoute, 'handleClasses'] 50 | }, 51 | 52 | // -- /files/* --------------------------------------------------------- 53 | { 54 | path : '/files/*file', 55 | callbacks: [defaultRoute, 'handleFiles'] 56 | }, 57 | 58 | // -- /modules/* ------------------------------------------------------- 59 | { 60 | path : '/modules/:module.html*', 61 | callbacks: defaultRoute 62 | } 63 | ] 64 | }); 65 | 66 | // -- Utility Functions -------------------------------------------------------- 67 | 68 | pjax.checkVisibility = function (tab) { 69 | tab || (tab = selectedTab); 70 | 71 | if (!tab) { return; } 72 | 73 | var panelNode = tab.get('panelNode'), 74 | visibleItems; 75 | 76 | // If no items are visible in the tab panel due to the current visibility 77 | // settings, display a message to that effect. 78 | visibleItems = panelNode.all('.item,.index-item').some(function (itemNode) { 79 | if (itemNode.getComputedStyle('display') !== 'none') { 80 | return true; 81 | } 82 | }); 83 | 84 | panelNode.all('.no-visible-items').remove(); 85 | 86 | if (!visibleItems) { 87 | if (Y.one('#index .index-item')) { 88 | panelNode.append( 89 | '
    ' + 90 | '

    ' + 91 | 'Some items are not shown due to the current visibility ' + 92 | 'settings. Use the checkboxes at the upper right of this ' + 93 | 'page to change the visibility settings.' + 94 | '

    ' + 95 | '
    ' 96 | ); 97 | } else { 98 | panelNode.append( 99 | '
    ' + 100 | '

    ' + 101 | 'This class doesn\'t provide any methods, properties, ' + 102 | 'attributes, or events.' + 103 | '

    ' + 104 | '
    ' 105 | ); 106 | } 107 | } 108 | 109 | // Hide index sections without any visible items. 110 | Y.all('.index-section').each(function (section) { 111 | var items = 0, 112 | visibleItems = 0; 113 | 114 | section.all('.index-item').each(function (itemNode) { 115 | items += 1; 116 | 117 | if (itemNode.getComputedStyle('display') !== 'none') { 118 | visibleItems += 1; 119 | } 120 | }); 121 | 122 | section.toggleClass('hidden', !visibleItems); 123 | section.toggleClass('no-columns', visibleItems < 4); 124 | }); 125 | }; 126 | 127 | pjax.initClassTabView = function () { 128 | if (!Y.all('#classdocs .api-class-tab').size()) { 129 | return; 130 | } 131 | 132 | if (classTabView) { 133 | classTabView.destroy(); 134 | selectedTab = null; 135 | } 136 | 137 | classTabView = new Y.TabView({ 138 | srcNode: '#classdocs', 139 | 140 | on: { 141 | selectionChange: pjax.onTabSelectionChange 142 | } 143 | }); 144 | 145 | pjax.updateTabState(); 146 | classTabView.render(); 147 | }; 148 | 149 | pjax.initLineNumbers = function () { 150 | var hash = win.location.hash.substring(1), 151 | container = pjax.get('container'), 152 | hasLines, node; 153 | 154 | // Add ids for each line number in the file source view. 155 | container.all('.linenums>li').each(function (lineNode, index) { 156 | lineNode.set('id', 'l' + (index + 1)); 157 | lineNode.addClass('file-line'); 158 | hasLines = true; 159 | }); 160 | 161 | // Scroll to the desired line. 162 | if (hasLines && /^l\d+$/.test(hash)) { 163 | if ((node = container.getById(hash))) { 164 | win.scroll(0, node.getY()); 165 | } 166 | } 167 | }; 168 | 169 | pjax.initRoot = function () { 170 | var terminators = /^(?:classes|files|modules)$/, 171 | parts = pjax._getPathRoot().split('/'), 172 | root = [], 173 | i, len, part; 174 | 175 | for (i = 0, len = parts.length; i < len; i += 1) { 176 | part = parts[i]; 177 | 178 | if (part.match(terminators)) { 179 | // Makes sure the path will end with a "/". 180 | root.push(''); 181 | break; 182 | } 183 | 184 | root.push(part); 185 | } 186 | 187 | pjax.set('root', root.join('/')); 188 | }; 189 | 190 | pjax.updateTabState = function (src) { 191 | var hash = win.location.hash.substring(1), 192 | defaultTab, node, tab, tabPanel; 193 | 194 | function scrollToNode() { 195 | if (node.hasClass('protected')) { 196 | Y.one('#api-show-protected').set('checked', true); 197 | pjax.updateVisibility(); 198 | } 199 | 200 | if (node.hasClass('private')) { 201 | Y.one('#api-show-private').set('checked', true); 202 | pjax.updateVisibility(); 203 | } 204 | 205 | setTimeout(function () { 206 | // For some reason, unless we re-get the node instance here, 207 | // getY() always returns 0. 208 | var node = Y.one('#classdocs').getById(hash); 209 | win.scrollTo(0, node.getY() - 70); 210 | }, 1); 211 | } 212 | 213 | if (!classTabView) { 214 | return; 215 | } 216 | 217 | if (src === 'hashchange' && !hash) { 218 | defaultTab = 'index'; 219 | } else { 220 | if (localStorage) { 221 | defaultTab = localStorage.getItem('tab_' + pjax.getPath()) || 222 | 'index'; 223 | } else { 224 | defaultTab = 'index'; 225 | } 226 | } 227 | 228 | if (hash && (node = Y.one('#classdocs').getById(hash))) { 229 | if ((tabPanel = node.ancestor('.api-class-tabpanel', true))) { 230 | if ((tab = Y.one('#classdocs .api-class-tab.' + tabPanel.get('id')))) { 231 | if (classTabView.get('rendered')) { 232 | Y.Widget.getByNode(tab).set('selected', 1); 233 | } else { 234 | tab.addClass('yui3-tab-selected'); 235 | } 236 | } 237 | } 238 | 239 | // Scroll to the desired element if this is a hash URL. 240 | if (node) { 241 | if (classTabView.get('rendered')) { 242 | scrollToNode(); 243 | } else { 244 | classTabView.once('renderedChange', scrollToNode); 245 | } 246 | } 247 | } else { 248 | tab = Y.one('#classdocs .api-class-tab.' + defaultTab); 249 | 250 | // When the `defaultTab` node isn't found, `localStorage` is stale. 251 | if (!tab && defaultTab !== 'index') { 252 | tab = Y.one('#classdocs .api-class-tab.index'); 253 | } 254 | 255 | if (classTabView.get('rendered')) { 256 | Y.Widget.getByNode(tab).set('selected', 1); 257 | } else { 258 | tab.addClass('yui3-tab-selected'); 259 | } 260 | } 261 | }; 262 | 263 | pjax.updateVisibility = function () { 264 | var container = pjax.get('container'); 265 | 266 | container.toggleClass('hide-inherited', 267 | !Y.one('#api-show-inherited').get('checked')); 268 | 269 | container.toggleClass('show-deprecated', 270 | Y.one('#api-show-deprecated').get('checked')); 271 | 272 | container.toggleClass('show-protected', 273 | Y.one('#api-show-protected').get('checked')); 274 | 275 | container.toggleClass('show-private', 276 | Y.one('#api-show-private').get('checked')); 277 | 278 | pjax.checkVisibility(); 279 | }; 280 | 281 | // -- Route Handlers ----------------------------------------------------------- 282 | 283 | pjax.handleClasses = function (req, res, next) { 284 | var status = res.ioResponse.status; 285 | 286 | // Handles success and local filesystem XHRs. 287 | if (res.ioResponse.readyState === 4 && (!status || (status >= 200 && status < 300))) { 288 | pjax.initClassTabView(); 289 | } 290 | 291 | next(); 292 | }; 293 | 294 | pjax.handleFiles = function (req, res, next) { 295 | var status = res.ioResponse.status; 296 | 297 | // Handles success and local filesystem XHRs. 298 | if (res.ioResponse.readyState === 4 && (!status || (status >= 200 && status < 300))) { 299 | pjax.initLineNumbers(); 300 | } 301 | 302 | next(); 303 | }; 304 | 305 | // -- Event Handlers ----------------------------------------------------------- 306 | 307 | pjax.onNavigate = function (e) { 308 | var hash = e.hash, 309 | originTarget = e.originEvent && e.originEvent.target, 310 | tab; 311 | 312 | if (hash) { 313 | tab = originTarget && originTarget.ancestor('.yui3-tab', true); 314 | 315 | if (hash === win.location.hash) { 316 | pjax.updateTabState('hashchange'); 317 | } else if (!tab) { 318 | win.location.hash = hash; 319 | } 320 | 321 | e.preventDefault(); 322 | return; 323 | } 324 | 325 | // Only scroll to the top of the page when the URL doesn't have a hash. 326 | this.set('scrollToTop', !e.url.match(/#.+$/)); 327 | 328 | bdNode.addClass('loading'); 329 | }; 330 | 331 | pjax.onOptionClick = function (e) { 332 | pjax.updateVisibility(); 333 | }; 334 | 335 | pjax.onTabSelectionChange = function (e) { 336 | var tab = e.newVal, 337 | tabId = tab.get('contentBox').getAttribute('href').substring(1); 338 | 339 | selectedTab = tab; 340 | 341 | // If switching from a previous tab (i.e., this is not the default tab), 342 | // replace the history entry with a hash URL that will cause this tab to 343 | // be selected if the user navigates away and then returns using the back 344 | // or forward buttons. 345 | if (e.prevVal && localStorage) { 346 | localStorage.setItem('tab_' + pjax.getPath(), tabId); 347 | } 348 | 349 | pjax.checkVisibility(tab); 350 | }; 351 | 352 | // -- Init --------------------------------------------------------------------- 353 | 354 | pjax.on('navigate', pjax.onNavigate); 355 | 356 | pjax.initRoot(); 357 | pjax.upgrade(); 358 | pjax.initClassTabView(); 359 | pjax.initLineNumbers(); 360 | pjax.updateVisibility(); 361 | 362 | Y.APIList.rootPath = pjax.get('root'); 363 | 364 | Y.one('#api-options').delegate('click', pjax.onOptionClick, 'input'); 365 | 366 | Y.on('hashchange', function (e) { 367 | pjax.updateTabState('hashchange'); 368 | }, win); 369 | 370 | }); 371 | -------------------------------------------------------------------------------- /AdHelper/docs/assets/js/yui-prettify.js: -------------------------------------------------------------------------------- 1 | YUI().use('node', function(Y) { 2 | var code = Y.all('.prettyprint.linenums'); 3 | if (code.size()) { 4 | code.each(function(c) { 5 | var lis = c.all('ol li'), 6 | l = 1; 7 | lis.each(function(n) { 8 | n.prepend(''); 9 | l++; 10 | }); 11 | }); 12 | var h = location.hash; 13 | location.hash = ''; 14 | h = h.replace('LINE_', 'LINENUM_'); 15 | location.hash = h; 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /AdHelper/docs/assets/vendor/prettify/CHANGES.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Change Log 5 | 6 | 7 | README 8 | 9 |

    Known Issues

    10 | 22 | 23 |

    Change Log

    24 |

    29 March 2007

    25 | 56 |

    4 Jul 2008

    57 | 63 |

    5 Jul 2008

    64 |
    67 |

    14 Jul 2008

    68 | 76 |

    6 Jan 2009

    77 | 93 |

    21 May 2009

    94 | 101 |

    14 August 2009

    102 | 105 |

    3 October 2009

    106 | 109 |

    19 July 2010

    110 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /AdHelper/docs/assets/vendor/prettify/COPYING: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /AdHelper/docs/assets/vendor/prettify/README.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Javascript code prettifier 7 | 8 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 19 | Languages : CH 20 |

    Javascript code prettifier

    21 | 22 |

    Setup

    23 |
      24 |
    1. Download a distribution 25 |
    2. Include the script and stylesheets in your document 26 | (you will need to make sure the css and js file are on your server, and 27 | adjust the paths in the script and link tag) 28 |
       29 | <link href="prettify.css" type="text/css" rel="stylesheet" />
       30 | <script type="text/javascript" src="prettify.js"></script>
      31 |
    3. Add onload="prettyPrint()" to your 32 | document's body tag. 33 |
    4. Modify the stylesheet to get the coloring you prefer
    5. 34 |
    35 | 36 |

    Usage

    37 |

    Put code snippets in 38 | <pre class="prettyprint">...</pre> 39 | or <code class="prettyprint">...</code> 40 | and it will automatically be pretty printed. 41 | 42 | 43 | 44 | 47 |
    The original 45 | Prettier 46 |
    class Voila {
     49 | public:
     50 |   // Voila
     51 |   static const string VOILA = "Voila";
     52 | 
     53 |   // will not interfere with embedded tags.
     54 | }
    55 | 56 |
    class Voila {
     57 | public:
     58 |   // Voila
     59 |   static const string VOILA = "Voila";
     60 | 
     61 |   // will not interfere with embedded tags.
     62 | }
    63 |
    64 | 65 |

    FAQ

    66 |

    Which languages does it work for?

    67 |

    The comments in prettify.js are authoritative but the lexer 68 | should work on a number of languages including C and friends, 69 | Java, Python, Bash, SQL, HTML, XML, CSS, Javascript, and Makefiles. 70 | It works passably on Ruby, PHP, VB, and Awk and a decent subset of Perl 71 | and Ruby, but, because of commenting conventions, doesn't work on 72 | Smalltalk, or CAML-like languages.

    73 | 74 |

    LISPy languages are supported via an extension: 75 | lang-lisp.js.

    77 |

    And similarly for 78 | CSS, 80 | Haskell, 82 | Lua, 84 | OCAML, SML, F#, 86 | Visual Basic, 88 | SQL, 90 | Protocol Buffers, and 92 | WikiText.. 94 | 95 |

    If you'd like to add an extension for your favorite language, please 96 | look at src/lang-lisp.js and file an 97 | issue including your language extension, and a testcase.

    99 | 100 |

    How do I specify which language my code is in?

    101 |

    You don't need to specify the language since prettyprint() 102 | will guess. You can specify a language by specifying the language extension 103 | along with the prettyprint class like so:

    104 |
    <pre class="prettyprint lang-html">
    106 |   The lang-* class specifies the language file extensions.
    107 |   File extensions supported by default include
    108 |     "bsh", "c", "cc", "cpp", "cs", "csh", "cyc", "cv", "htm", "html",
    109 |     "java", "js", "m", "mxml", "perl", "pl", "pm", "py", "rb", "sh",
    110 |     "xhtml", "xml", "xsl".
    111 | </pre>
    112 | 113 |

    It doesn't work on <obfuscated code sample>?

    114 |

    Yes. Prettifying obfuscated code is like putting lipstick on a pig 115 | — i.e. outside the scope of this tool.

    116 | 117 |

    Which browsers does it work with?

    118 |

    It's been tested with IE 6, Firefox 1.5 & 2, and Safari 2.0.4. 119 | Look at the test page to see if it 120 | works in your browser.

    121 | 122 |

    What's changed?

    123 |

    See the change log

    124 | 125 |

    Why doesn't Prettyprinting of strings work on WordPress?

    126 |

    Apparently wordpress does "smart quoting" which changes close quotes. 127 | This causes end quotes to not match up with open quotes. 128 |

    This breaks prettifying as well as copying and pasting of code samples. 129 | See 130 | WordPress's help center for info on how to stop smart quoting of code 132 | snippets.

    133 | 134 |

    How do I put line numbers in my code?

    135 |

    You can use the linenums class to turn on line 136 | numbering. If your code doesn't start at line number 1, you can 137 | add a colon and a line number to the end of that class as in 138 | linenums:52. 139 | 140 |

    For example 141 |

    <pre class="prettyprint linenums:4"
    142 | >// This is line 4.
    143 | foo();
    144 | bar();
    145 | baz();
    146 | boo();
    147 | far();
    148 | faz();
    149 | <pre>
    150 | produces 151 |
    // This is line 4.
    153 | foo();
    154 | bar();
    155 | baz();
    156 | boo();
    157 | far();
    158 | faz();
    159 | 
    160 | 161 |

    How do I prevent a portion of markup from being marked as code?

    162 |

    You can use the nocode class to identify a span of markup 163 | that is not code. 164 |

    <pre class=prettyprint>
    165 | int x = foo();  /* This is a comment  <span class="nocode">This is not code</span>
    166 |   Continuation of comment */
    167 | int y = bar();
    168 | </pre>
    169 | produces 170 |
    171 | int x = foo();  /* This is a comment  This is not code
    172 |   Continuation of comment */
    173 | int y = bar();
    174 | 
    175 | 176 |

    For a more complete example see the issue22 177 | testcase.

    178 | 179 |

    I get an error message "a is not a function" or "opt_whenDone is not a function"

    180 |

    If you are calling prettyPrint via an event handler, wrap it in a function. 181 | Instead of doing 182 |

    183 | addEventListener('load', prettyPrint, false); 185 |
    186 | wrap it in a closure like 187 |
    188 | addEventListener('load', function (event) { prettyPrint() }, false); 190 |
    191 | so that the browser does not pass an event object to prettyPrint which 192 | will confuse it. 193 | 194 |


    195 | 196 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /AdHelper/docs/assets/vendor/prettify/prettify-min.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} -------------------------------------------------------------------------------- /AdHelper/docs/assets/vendor/prettify/prettify-min.js: -------------------------------------------------------------------------------- 1 | window.PR_SHOULD_USE_CONTINUATION=true;var prettyPrintOne;var prettyPrint;(function(){var O=window;var j=["break,continue,do,else,for,if,return,while"];var v=[j,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var q=[v,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var m=[q,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var y=[q,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var T=[y,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"];var s="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes";var x=[q,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var t="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var J=[j,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var g=[j,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var I=[j,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var B=[m,T,x,t+J,g,I];var f=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/;var D="str";var A="kwd";var k="com";var Q="typ";var H="lit";var M="pun";var G="pln";var n="tag";var F="dec";var K="src";var R="atn";var o="atv";var P="nocode";var N="(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function l(ab){var af=0;var U=false;var ae=false;for(var X=0,W=ab.length;X122)){if(!(am<65||ai>90)){ah.push([Math.max(65,ai)|32,Math.min(am,90)|32])}if(!(am<97||ai>122)){ah.push([Math.max(97,ai)&~32,Math.min(am,122)&~32])}}}}ah.sort(function(aw,av){return(aw[0]-av[0])||(av[1]-aw[1])});var ak=[];var aq=[];for(var at=0;atau[0]){if(au[1]+1>au[0]){ao.push("-")}ao.push(V(au[1]))}}ao.push("]");return ao.join("")}function Y(an){var al=an.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var aj=al.length;var ap=[];for(var am=0,ao=0;am=2&&ak==="["){al[am]=Z(ai)}else{if(ak!=="\\"){al[am]=ai.replace(/[a-zA-Z]/g,function(aq){var ar=aq.charCodeAt(0);return"["+String.fromCharCode(ar&~32,ar|32)+"]"})}}}}return al.join("")}var ac=[];for(var X=0,W=ab.length;X=0;){U[ae.charAt(ag)]=aa}}var ah=aa[1];var ac=""+ah;if(!ai.hasOwnProperty(ac)){aj.push(ah);ai[ac]=null}}aj.push(/[\0-\uffff]/);X=l(aj)})();var Z=V.length;var Y=function(aj){var ab=aj.sourceCode,aa=aj.basePos;var af=[aa,G];var ah=0;var ap=ab.match(X)||[];var al={};for(var ag=0,at=ap.length;ag=5&&"lang-"===ar.substring(0,5);if(ao&&!(ak&&typeof ak[1]==="string")){ao=false;ar=K}if(!ao){al[ai]=ar}}var ad=ah;ah+=ai.length;if(!ao){af.push(aa+ad,ar)}else{var an=ak[1];var am=ai.indexOf(an);var ae=am+an.length;if(ak[2]){ae=ai.length-ak[2].length;am=ae-an.length}var au=ar.substring(5);C(aa+ad,ai.substring(0,am),Y,af);C(aa+ad+am,an,r(au,an),af);C(aa+ad+ae,ai.substring(ae),Y,af)}}aj.decorations=af};return Y}function i(V){var Y=[],U=[];if(V.tripleQuotedStrings){Y.push([D,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(V.multiLineStrings){Y.push([D,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{Y.push([D,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(V.verbatimStrings){U.push([D,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var ab=V.hashComments;if(ab){if(V.cStyleComments){if(ab>1){Y.push([k,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{Y.push([k,/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}U.push([D,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,null])}else{Y.push([k,/^#[^\r\n]*/,null,"#"])}}if(V.cStyleComments){U.push([k,/^\/\/[^\r\n]*/,null]);U.push([k,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(V.regexLiterals){var aa=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");U.push(["lang-regex",new RegExp("^"+N+"("+aa+")")])}var X=V.types;if(X){U.push([Q,X])}var W=(""+V.keywords).replace(/^ | $/g,"");if(W.length){U.push([A,new RegExp("^(?:"+W.replace(/[\s,]+/g,"|")+")\\b"),null])}Y.push([G,/^\s+/,null," \r\n\t\xA0"]);var Z=/^.[^\s\w\.$@\'\"\`\/\\]*/;U.push([H,/^@[a-z_$][a-z_$@0-9]*/i,null],[Q,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[G,/^[a-z_$][a-z_$@0-9]*/i,null],[H,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[G,/^\\[\s\S]?/,null],[M,Z,null]);return h(Y,U)}var L=i({keywords:B,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function S(W,ah,aa){var V=/(?:^|\s)nocode(?:\s|$)/;var ac=/\r\n?|\n/;var ad=W.ownerDocument;var ag=ad.createElement("li");while(W.firstChild){ag.appendChild(W.firstChild)}var X=[ag];function af(am){switch(am.nodeType){case 1:if(V.test(am.className)){break}if("br"===am.nodeName){ae(am);if(am.parentNode){am.parentNode.removeChild(am)}}else{for(var ao=am.firstChild;ao;ao=ao.nextSibling){af(ao)}}break;case 3:case 4:if(aa){var an=am.nodeValue;var ak=an.match(ac);if(ak){var aj=an.substring(0,ak.index);am.nodeValue=aj;var ai=an.substring(ak.index+ak[0].length);if(ai){var al=am.parentNode;al.insertBefore(ad.createTextNode(ai),am.nextSibling)}ae(am);if(!aj){am.parentNode.removeChild(am)}}}break}}function ae(al){while(!al.nextSibling){al=al.parentNode;if(!al){return}}function aj(am,at){var ar=at?am.cloneNode(false):am;var ap=am.parentNode;if(ap){var aq=aj(ap,1);var ao=am.nextSibling;aq.appendChild(ar);for(var an=ao;an;an=ao){ao=an.nextSibling;aq.appendChild(an)}}return ar}var ai=aj(al.nextSibling,0);for(var ak;(ak=ai.parentNode)&&ak.nodeType===1;){ai=ak}X.push(ai)}for(var Z=0;Z=U){aj+=2}if(Y>=ar){ac+=2}}}finally{if(au){au.style.display=ak}}}var u={};function d(W,X){for(var U=X.length;--U>=0;){var V=X[U];if(!u.hasOwnProperty(V)){u[V]=W}else{if(O.console){console.warn("cannot override language handler %s",V)}}}}function r(V,U){if(!(V&&u.hasOwnProperty(V))){V=/^\s*]*(?:>|$)/],[k,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[M,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);d(h([[G,/^[\s]+/,null," \t\r\n"],[o,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[n,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[R,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[M,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);d(h([],[[o,/^[\s\S]+/]]),["uq.val"]);d(i({keywords:m,hashComments:true,cStyleComments:true,types:f}),["c","cc","cpp","cxx","cyc","m"]);d(i({keywords:"null,true,false"}),["json"]);d(i({keywords:T,hashComments:true,cStyleComments:true,verbatimStrings:true,types:f}),["cs"]);d(i({keywords:y,cStyleComments:true}),["java"]);d(i({keywords:I,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);d(i({keywords:J,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);d(i({keywords:t,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);d(i({keywords:g,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);d(i({keywords:x,cStyleComments:true,regexLiterals:true}),["js"]);d(i({keywords:s,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);d(h([],[[D,/^[\s\S]+/]]),["regex"]);function e(X){var W=X.langExtension;try{var U=b(X.sourceNode,X.pre);var V=U.sourceCode;X.sourceCode=V;X.spans=U.spans;X.basePos=0;r(W,V)(X);E(X)}catch(Y){if(O.console){console.log(Y&&Y.stack?Y.stack:Y)}}}function z(Y,X,W){var U=document.createElement("pre");U.innerHTML=Y;if(W){S(U,W,true)}var V={langExtension:X,numberLines:W,sourceNode:U,pre:1};e(V);return U.innerHTML}function c(aj){function ab(al){return document.getElementsByTagName(al)}var ah=[ab("pre"),ab("code"),ab("xmp")];var V=[];for(var ae=0;ae]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); -------------------------------------------------------------------------------- /AdHelper/docs/files/_Users_grant_Documents_JS_CreateJS_html5ads_AdHelper_AdHelper.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | /Users/grant/Documents/JS/CreateJS_html5ads/AdHelper/AdHelper.js 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 |
    16 |
    17 | 18 |

    19 | 20 |
    21 |
    22 | API Docs for: 23 |
    24 |
    25 |
    26 | 27 |
    28 | 56 |
    57 |
    58 |
    59 | Show: 60 | 64 | 65 | 69 | 70 | 74 | 78 | 79 |
    80 | 81 | 82 |
    83 |
    84 |
    85 |

    File: /Users/grant/Documents/JS/CreateJS_html5ads/AdHelper/AdHelper.js

    86 | 87 |
    88 |
     89 | /*
     90 |  * AdHelper
     91 |  * Visit http://createjs.com/ for documentation, updates and examples.
     92 |  *
     93 |  *
     94 |  * Copyright (c) 2015 gskinner.com, inc.
     95 |  *
     96 |  * Permission is hereby granted, free of charge, to any person
     97 |  * obtaining a copy of this software and associated documentation
     98 |  * files (the "Software"), to deal in the Software without
     99 |  * restriction, including without limitation the rights to use,
    100 |  * copy, modify, merge, publish, distribute, sublicense, and/or sell
    101 |  * copies of the Software, and to permit persons to whom the
    102 |  * Software is furnished to do so, subject to the following
    103 |  * conditions:
    104 |  *
    105 |  * The above copyright notice and this permission notice shall be
    106 |  * included in all copies or substantial portions of the Software.
    107 |  *
    108 |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    109 |  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    110 |  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    111 |  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    112 |  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    113 |  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    114 |  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    115 |  * OTHER DEALINGS IN THE SOFTWARE.
    116 |  */
    117 | 
    118 | // namespace:
    119 | this.createjs = this.createjs || {};
    120 | 
    121 | (function(){
    122 | "use strict";
    123 | 	
    124 | // constructor
    125 | 	/**
    126 | 	 * <strong>NOTE: This class is specifically designed to work in an advertising environment, where the ad is isolated
    127 | 	 * to its own iframe. It can cause problems if there are multiple CreateJS experiences in the same document.</strong>
    128 | 	 * 
    129 | 	 * Class that provides a number of helpful capabilities for online advertisements such as:<ul>
    130 | 	 * <li> detect if CreateJS is supported in the current browser
    131 | 	 * <li> display alternate content
    132 | 	 * <li> sleep/pause and mute the ad while it's in a background tab
    133 | 	 * <li> sleep/pause after a delay & wake on interaction
    134 | 	 * <li> watch framerate and sleep the ad if it is running slowly
    135 | 	 * <li> time-sync playback to maintain duration even when framerate is slow
    136 | 	 * <li> ensure full resolution graphics on high DPI screens
    137 | 	 * </ul>
    138 | 	 * These features work together. For example, sleep time will be deferred and performance
    139 | 	 * measurements will be halted when an ad is paused due to being in a background tab.
    140 | 	 * 
    141 | 	 * Background tab detection is enabled automatically, and works in all browsers that support the page visibility API. This includes all
    142 | 	 * modern browsers except IE <10, Opera Mini, and the Android Browser <4.4. Note that audio is currently muted, not
    143 | 	 * paused, which can cause audio to become desynched. Use the "sleep" and "wake" events to pause/resume your audio
    144 | 	 * if this is a problem.
    145 | 	 * 
    146 | 	 * Most methods can be chained to allow single line initialization. For example, this would
    147 | 	 * create an ad helper that sleeps after 15s, and has alt content:
    148 | 	 * 
    149 | 	 * 	var ad = new AdHelper(myStage).setSleep(15).highDPI();
    150 | 	 * 	ad.on("sleep", handleSleep, this);
    151 | 	 * 
    152 | 	 * @class AdHelper
    153 | 	 * @param {Stage} stage The target Stage object.
    154 | 	 * @extends EventDispatcher
    155 | 	 */
    156 | 	function AdHelper(stage) {
    157 | 		this._stage = stage; // up here because its used by pixelRatio.
    158 | 		
    159 | 	// public properties:
    160 | 		/**
    161 | 		 * This listener will be removed from the Ticker when the ad sleeps, and added back when it wakes.
    162 | 		 * By default this will be the stage, to stop updates when sleeping, however if you define your own tick
    163 | 		 * handler that subsequently calls `stage.update` you should specify it instead.
    164 | 		 * 
    165 | 		 * Your listener can alternatively check the `paused` property on tick events, which will be true when the
    166 | 		 * ad is asleep.
    167 | 		 * 
    168 | 		 * <strong>NOTE: if using `on` to add your tick listener, make sure to use the generated listener object as
    169 | 		 * the tickListener. Example:</strong>
    170 | 		 * 
    171 | 		 * 	var listener = createjs.Ticker.on("tick", myTickFunction, scope);
    172 | 		 * 	myAdHelper.setSleep(15, 3, 0, listener);
    173 | 		 * 
    174 | 		 * @property tickListener
    175 | 		 * @type {Function|Object}
    176 | 		 */
    177 | 		this.tickListener = null;
    178 | 		
    179 | 		/**
    180 | 		 * True when awake, false when sleeping.
    181 | 		 * @property awake
    182 | 		 * @type {Boolean}
    183 | 		 * @readonly
    184 | 		 */
    185 | 		this.awake = true;
    186 | 		
    187 | 		/**
    188 | 		 * Disables sleep if false. Set to true automatically when `setSleep()` is called.
    189 | 		 * @property sleepEnabled
    190 | 		 * @type {Boolean}
    191 | 		 * @default false
    192 | 		 */
    193 | 		this.sleepEnabled = false;
    194 | 		
    195 | 		/**
    196 | 		 * True when the ad is hidden (ex. in a background tab).
    197 | 		 * @property hidden
    198 | 		 * @type {Boolean}
    199 | 		 * @readonly
    200 | 		 */
    201 | 		this.hidden = false;
    202 | 		
    203 | 		/**
    204 | 		 * Returns the pixel ratio that is being used to draw the canvas on a high dpi device. On browsers that
    205 | 		 * automatically utilize high dpi backing stores (like Safari), this returns the backingStorePixelRatio. For
    206 | 		 * other browsers, this returns 1 by default. This is also affected by the `nominalScale` passed to `highDPI()`.
    207 | 		 * 
    208 | 		 * If you call the `highDPI()` method, then `pixelRatio` will be set to the resulting scale.
    209 | 		 * 
    210 | 		 * This value is primarily useful for loading appropriately sized bitmap images.
    211 | 		 * 
    212 | 		 * 	myAdHelper.highDPI();
    213 | 		 * 	if (myAdHelper.pixelRatio > 1.5) {
    214 | 		 * 		// load high res images.
    215 | 		 * 	} else {
    216 | 		 * 		// load low res images.
    217 | 		 * 	}
    218 | 		 * @property pixelRatio
    219 | 		 * @type {Number}
    220 | 		 * @readonly
    221 | 		 */
    222 | 		this.pixelRatio = this._getBackingRatio();
    223 | 		
    224 | 	// private properties:
    225 | 		this._time = 0;
    226 | 		
    227 | 		this._awake = true; // whether the ad should be awake ignoring tab visibility
    228 | 		this._sleepy = false; // indicates it should sleep on the next tick
    229 | 		this._sleepT = 0; // time to go to sleep
    230 | 		this._sleepMousedownT = null; // time before sleep if user clicks on the stage
    231 | 		this._sleepInBoundsT = null; // time before sleep if the mouse is in bounds
    232 | 		this._sleepUseTicks = false; // must be set in props if using startDelay
    233 | 		this._mouseInDoc = false; // iframes can break stage.mouseInBounds
    234 | 		
    235 | 		this._perfDelay = 0; // wait a few ticks before measuring performance
    236 | 		this._perfCount = 0;
    237 | 		this._perfThreshold = 0;
    238 | 		this._perfFPS = 0;
    239 | 		
    240 | 		this._width = stage.canvas.width; // for use with highDPI in case of multiple calls.
    241 | 		this._height = stage.canvas.height;
    242 | 		
    243 | 		createjs.Ticker.on("tick", this);
    244 | 	}
    245 | 	var p = AdHelper.prototype;
    246 | 	if (createjs.EventDispatcher) { p = AdHelper.prototype = new createjs.EventDispatcher(); }
    247 | 	
    248 | 	
    249 | // public static methods:
    250 | 	/**
    251 | 	 * Returns true if CreateJS is supported on this browser. For example, this can be used in conjunction with the
    252 | 	 * `showAlt` methods to display alternate content when the CreateJS banner is not supported. You should run this
    253 | 	 * check before initializing the ad. For example:
    254 | 	 * 
    255 | 	 * 	function init() {
    256 | 	 * 		if (!createjs.AdHelper.isSupported()) {
    257 | 	 * 			// not supported, show alt content, and skip everything else.
    258 | 	 * 			createjs.AdHelper.showAltImage("myImage.jpg", "url");
    259 | 	 * 			return;
    260 | 	 * 		}
    261 | 	 * 		// supported, so continue with normal init...
    262 | 	 * 	}
    263 | 	 * 
    264 | 	 * @method isSupported
    265 | 	 * @static
    266 | 	 * @return {Boolean} True if CreateJS is supported on this browser.
    267 | 	 */
    268 | 	AdHelper.isSupported = function() {
    269 | 		return !!window.CanvasRenderingContext2D;
    270 | 	};
    271 | 	
    272 | 	/**
    273 | 	 * Helper method that generates HTML and passes it to `showAltHTML` to replace the specified canvas.
    274 | 	 * You can set a link href/url, an image, and alt text. If you require more control over the content
    275 | 	 * use `setAltHTML` directly.
    276 | 	 * @method setAltImage
    277 | 	 * @static
    278 | 	 * @param {String|HTMLCanvasElement} canvas The canvas element to replace, or its id.
    279 | 	 * @param {String} src The URL for the image to display.
    280 | 	 * @param {String} [href] The URL to link.
    281 | 	 * @param {String} [alt=""] Text to use as alt text for the image.
    282 | 	 * @param {String} [target="_blank"] The link target to use (ex. _blank, _parent). Default is _blank.
    283 | 	 * @return {HTMLElement} The div that was created by showAltHTML and swapped with the canvas.
    284 | 	 */
    285 | 	AdHelper.showAltImage = function(canvas, src, href, alt, target) {
    286 | 		return AdHelper.showAltHTML(canvas,
    287 | 			(href?"<a target='"+(target||"_blank")+"' href='"+href+"'>":"")+ 
    288 | 			"<img src='"+src+"' border='0' alt='"+(alt||"")+"'>"+
    289 | 			(href?"</a>":""));
    290 | 	};
    291 | 	
    292 | 	/**
    293 | 	 * Replaces the specified canvas with a new div containing the specified HTML content. The created div is assigned
    294 | 	 * an id of "adAlt" for referencing in code or styling with CSS.
    295 | 	 * @method showAltHTML
    296 | 	 * @static
    297 | 	 * @param {String|HTMLCanvasElement} canvas The canvas element to replace, or its id.
    298 | 	 * @param {String} html The HTML content to display.
    299 | 	 * @return {HTMLElement} The div that was created and swapped with the canvas.
    300 | 	 */
    301 | 	AdHelper.showAltHTML = function(canvas, html) {
    302 | 		var div = document.createElement("div");
    303 | 		div.innerHTML = html || "";
    304 | 		div.id = "adAlt";
    305 | 		return AdHelper.showAlt(canvas, div);
    306 | 	};
    307 | 	
    308 | 	/**
    309 | 	 * Swaps the specified canvas with an HTML element as alternative content. The element will have its CSS `display`
    310 | 	 * value set to `block`. This allows you to set the element's CSS `display` value to `none` by default to
    311 | 	 * prevent it from displaying when the page loads.
    312 | 	 * 
    313 | 	 * Note that any images or scripts you have in your element will be loaded and run as usual, so using showAltHTML
    314 | 	 * may be preferable in some situations.
    315 | 	 * @method showAlt
    316 | 	 * @static
    317 | 	 * @param {String|HTMLCanvasElement} canvas The canvas element to replace, or its id.
    318 | 	 * @param {HTMLElement} element The HTML element to display.
    319 | 	 * @return {HTMLElement} The element that was passed in.
    320 | 	 */
    321 | 	AdHelper.showAlt = function(canvas, element) {
    322 | 		if (typeof canvas == "string") { canvas = document.getElementById(canvas); }
    323 | 		element.style.display = "block";
    324 | 		canvas.parentNode.replaceChild(element, canvas);
    325 | 		return element;
    326 | 	};
    327 | 	
    328 | 	
    329 | // events:
    330 | 	/**
    331 | 	 * Dispatched when the ad wakes, either via the `wake()` method or automatically due to user interaction or
    332 | 	 * the browser tab coming to the foreground.
    333 | 	 * @event wake
    334 | 	 */
    335 | 	 
    336 | 	/**
    337 | 	 * Dispatched when the ad sleeps, either via the `sleep()` method or automatically due to sleep scheduling or
    338 | 	 * the browser tab being hidden.
    339 | 	 * @event sleep
    340 | 	 */
    341 | 	 
    342 | 	/**
    343 | 	 * Dispatched if performance monitoring (via watchFPS) detects that the ad is running slowly.
    344 | 	 * @event slow
    345 | 	 */
    346 | 
    347 | // public methods
    348 | 	/**
    349 | 	 * Causes all MovieClip instances to run in time synched mode, so their duration remains consistent regardless of
    350 | 	 * real framerate (ex. if framerate drops due to performance issues).
    351 | 	 * 
    352 | 	 * NOTE: If a `framerate` value is not specified, it will use `lib.properties.fps` if available, and finally fall back to `Ticker.getFPS()`.
    353 | 	 * If the latter occurs, and the `Ticker` framerate has not been correctly set yet, you may see unexpected playback speed.
    354 | 	 * 
    355 | 	 * This feature works by injecting code into EaselJS that causes all MovieClip instances to use a master frame rate as
    356 | 	 * their `framerate` property value. See `MovieClip.framerate` for more information.
    357 | 	 * @method timeSync
    358 | 	 * @param {Number} [framerate] The target framerate. Usually the framerate your ad was authored at.
    359 | 	 * @return {AdHelper} The AdHelper instance the method is called on (useful for chaining calls.)
    360 | 	 * @chainable
    361 | 	 */
    362 | 	p.timeSync = function(framerate) {
    363 | 		var futureVersion = (this._stage.masterFrameRate !== undefined);
    364 | 		this._stage.masterFrameRate = framerate || (lib&&lib.properties&&lib.properties.fps) || this._getTickerFPS();
    365 | 		
    366 | 		// try to be forwards compatible:
    367 | 		if (futureVersion) { return this; }
    368 | 		
    369 | 		var stage_p = createjs.Stage.prototype, mc_p = createjs.MovieClip.prototype;
    370 | 		stage_p.__tick = stage_p._tick;
    371 | 		stage_p._tick = function(evt) {
    372 | 			evt.stage = this;
    373 | 			this.__tick(evt);
    374 | 		}
    375 | 		
    376 | 		mc_p.__tick = mc_p._tick;
    377 | 		mc_p._tick = function(evt) {
    378 | 			if (!this.ignoreMasterFrameRate && evt.stage) {
    379 | 				this.framerate = evt.stage.masterFrameRate || null;
    380 | 			}
    381 | 			this.__tick(evt);
    382 | 		}
    383 | 		return this;
    384 | 	};
    385 | 	
    386 | 	
    387 | 	/**
    388 | 	 * Watches the real framerate for the ad, and applies a simple heuristic to determine when the ad has been
    389 | 	 * running too slowly for too long. When this happens a `slow` event is dispatched, which you can use to modify
    390 | 	 * your content, for example by displaying alternative content:
    391 | 	 * 
    392 | 	 * 	myAdHelper.watchFPS().on("slow", function(evt) {
    393 | 	 * 		createjs.AdHelper.showAltImage(myStage.canvas, "myImage.jpg", "myURL");
    394 | 	 * 	});
    395 | 	 * 
    396 | 	 * By default, when the slow event fires, AdHelper will call `sleep()` and set `sleepEnabled=true`. You can prevent
    397 | 	 * this behaviour by calling `preventDefault()` on the slow event object. You can also restart the framerate watcher
    398 | 	 * after making adjustments:
    399 | 	 * 
    400 | 	 * 	myAdHelper.on("slow", function(evt) {
    401 | 	 * 		if (particleCount > 0) {
    402 | 	 * 			// if we can speed things up by removing particles, try that first.
    403 | 	 * 			evt.preventDefault(); // the ad will not be put to sleep.
    404 | 	 * 			particleCount -= 100; // or whatever will make it run faster.
    405 | 	 * 			this.watchFPS(); // restart the framerate watcher
    406 | 	 * 		} else {
    407 | 	 * 			// no more particles to remove, so let the default sleep happen
    408 | 	 * 			// and swap in some alt content:
    409 | 	 * 			createjs.AdHelper.showAltImage(myStage.canvas, "myImage.jpg", "myURL");
    410 | 	 * 		}
    411 | 	 * 	});
    412 | 	 * 
    413 | 	 * @method watchFPS
    414 | 	 * @param {Number} [minFPS] The minimum framerate considered acceptable. Calculated automatically if null.
    415 | 	 * @param {Number} [tolerance=1] The tolerance of the system. A higher value (ex. 2) allows more slow frames before acting than a lower number (ex. 0.5).
    416 | 	 * @return {AdHelper} The AdHelper instance the method is called on (useful for chaining calls.)
    417 | 	 * @chainable
    418 | 	 */
    419 | 	p.watchFPS = function(minFPS, tolerance) {
    420 | 		this._perfFPS = minFPS || (this._getTickerFPS()*0.9-1|0);
    421 | 		this._perfThreshold = tolerance || 1;
    422 | 		this._perfCount = 0;
    423 | 		this._perfDelay = 5;
    424 | 		return this;
    425 | 	};
    426 | 	
    427 | 	
    428 | 	/**
    429 | 	 * Scales the canvas and content as appropriate to display full resolution graphics on high dpi devices and updates 
    430 | 	 * the `pixelRatio` property accordingly.
    431 | 	 * 
    432 | 	 * If `false` is passed to the `enabled` parameter, then high DPI rendering will be disabled, including downscaling
    433 | 	 * the canvas on devices that automatically render at high DPI. This can be useful for reducing render cost on slower
    434 | 	 * devices.
    435 | 	 * 
    436 | 	 * The `nominalScale` param allows you to author content at higher resolution, and have AdHelper scale it appropriately
    437 | 	 * for the device. For example, you may find it easier to author a 728x90 banner at 1456x180 (2x scale) so that
    438 | 	 * bitmaps and cacheAsBitmap are high resolution, then specify a `nominalScale` of 2 to display it at the intended
    439 | 	 * size of 728x90.
    440 | 	 * 
    441 | 	 * It will change the canvas width/height attributes, the canvas's CSS width/height, and the stage's scaleX/Y as
    442 | 	 * necessary.
    443 | 	 * @method highDPI
    444 | 	 * @param {Boolean} [enabled=true] If false, disables high DPI rendering.
    445 | 	 * @param {Number} [nominalScale=1] The scale the content was authored at. The ad will be downscaled by this value.
    446 | 	 * @return {AdHelper} The AdHelper instance the method is called on (useful for chaining calls.)
    447 | 	 * @chainable
    448 | 	 */
    449 | 	p.highDPI = function(enabled, nominalScale) {
    450 | 		nominalScale = nominalScale || 1;
    451 | 		var backingRatio = this._getBackingRatio();
    452 | 		var scale = Math.max(1, (window.devicePixelRatio || 1) / backingRatio);
    453 | 		var stage = this._stage, canvas = stage.canvas, style = canvas.style;
    454 | 		var w = this._width / nominalScale, h = this._height / nominalScale;
    455 | 		
    456 | 		// downscale if highDPI is explicitly disabled:
    457 | 		if (enabled === false) { scale = 1/backingRatio; }
    458 | 		
    459 | 		canvas.width = w * scale;
    460 | 		canvas.height = h * scale;
    461 | 		style.width = w+"px";
    462 | 		style.height = h+"px";
    463 | 		stage.scaleX = stage.scaleY = scale/nominalScale;
    464 | 		
    465 | 		this.pixelRatio = (backingRatio === 1 ? scale : enabled === false ? 1 : backingRatio) / nominalScale;
    466 | 		return this;
    467 | 	};
    468 | 	
    469 | 	
    470 | 	/**
    471 | 	 * Sets the sleep schedule for the ad. The system will always use the latest sleep time. For example, if you called:
    472 | 	 * `setSleep(15, 3)` and the user clicked the ad after 4 seconds, the ad would still sleep after 15 seconds (15 > 3+4).
    473 | 	 * @method setSleep
    474 | 	 * @param {Number} start The delay in seconds after this call to wait before sleeping. Set to null to ignore this behaviour.
    475 | 	 * @param {Number} [mousedown=null] The delay after the user clicks the banner to wait before sleeping. Set to null to ignore this behaviour.
    476 | 	 * @param {Number} [inBounds=null] The delay after the user's mouse leaves the banner to wait before sleeping. Set to null to ignore this behaviour. For example, set to 0 to wake when the mouse enters, and sleep immediately when it leaves.
    477 | 	 * @param {Boolean} [useTicks=false] If true, the sleep times are specified in ticks instead of in seconds.
    478 | 	 * @param {Function|Object} [listener] Defaults to the stage. The listener to add/remove from Ticker when waking/sleeping. See `tickListener` for more details.
    479 | 	 * @return {AdHelper} The AdHelper instance the method is called on (useful for chaining calls.)
    480 | 	 * @chainable
    481 | 	 */
    482 | 	p.setSleep = function(start, mousedown, inBounds, useTicks, listener) {
    483 | 		if (mousedown != null) { stage.addEventListener("stagemousedown", this); }
    484 | 		if (inBounds != null) {
    485 | 			document.addEventListener("mouseout", this, true);
    486 | 			document.addEventListener("mousemove", this, true);
    487 | 		}
    488 | 		this.tickListener = listener || this._stage;
    489 | 		this._sleepMousedownT = mousedown;
    490 | 		this._sleepInBoundsT = inBounds;
    491 | 		this._sleepUseTicks = !!useTicks;
    492 | 		this.sleepEnabled = true;
    493 | 		
    494 | 		this._sleepy = false; // indicates it should sleep on the next tick
    495 | 		this._sleepT = (start != null) ? this._getTime() + start*1000 : 0;
    496 | 		return this;
    497 | 	};
    498 | 	
    499 | 	/**
    500 | 	 * Sleeps the ad after the specified delay. This pauses the ticker, unsubscribes the `tickListener`,
    501 | 	 * and pauses GreenSock TweenLite/TweenMax tweens.
    502 | 	 * @method sleep
    503 | 	 * @param {Number} [delay=0] The delay before sleeping, or 0 to sleep immediately.
    504 | 	 */
    505 | 	p.sleep = function(delay) {
    506 | 		// TODO: switch to seconds.
    507 | 		if (delay) { this._sleepT = this._getTime()+(delay||0); return; }
    508 | 		this._sleepy = false;
    509 | 		this._sleepT = 0;
    510 | 		this._awake = false;
    511 | 		this._sleep();
    512 | 	};
    513 | 	
    514 | 	/**
    515 | 	 * Wakes the ad for a specified amount of time.
    516 | 	 * @method wake
    517 | 	 * @param {Number} [time=null] The amount of time to wake for, or null to wake permanently.
    518 | 	 */
    519 | 	p.wake = function(time) {
    520 | 		// TODO: switch to seconds.
    521 | 		this._sleepy = false;
    522 | 		if (time != null) { this._sleepT = Math.max(this._sleepT, this._getTime()+(time||0)); }
    523 | 		else { this._sleepT = 0; }
    524 | 		this._awake = true;
    525 | 		this._wake();
    526 | 	};
    527 | 	
    528 | 	p.handleEvent = function(evt) {
    529 | 		if (evt.type === "tick") {
    530 | 			this._tick(evt);
    531 | 		} else if (evt.type === "stagemousedown") {
    532 | 			var d = this._sleepMousedownT;
    533 | 			if (this.sleepEnabled && d != null) { this.wake(d*1000); }
    534 | 		} else if (evt.type === "mousemove") {
    535 | 			this._mouseInDoc = true;
    536 | 		} else if (evt.type === "mouseout") {
    537 | 			this._mouseInDoc = false;
    538 | 		}
    539 | 	};
    540 | 
    541 | 	
    542 | // private methods:
    543 | 	p._getTickerFPS = function() {
    544 | 		return (createjs.Ticker.timingMode == createjs.Ticker.RAF ? 60 : createjs.Ticker.framerate);
    545 | 	};
    546 | 	
    547 | 	p._sleep = function() {
    548 | 		if (!this.awake) { return; }
    549 | 		createjs.Ticker.paused = true;
    550 | 		if (this.tickListener) { createjs.Ticker.removeEventListener("tick", this.tickListener); }
    551 | 		window.TweenLite && TweenLite.ticker && TweenLite.ticker.sleep();
    552 | 		this.dispatchEvent("sleep");
    553 | 		this.awake = false;
    554 | 	};
    555 | 	
    556 | 	p._wake = function() {
    557 | 		if (this.awake) { return; }
    558 | 		createjs.Ticker.paused = false;
    559 | 		if (this.tickListener) { createjs.Ticker.addEventListener("tick", this.tickListener); }
    560 | 		
    561 | 		if (window.TweenLite) {
    562 | 			var ticker = TweenLite.ticker, originalFrame = ticker.frame; //record the original frame temporarily so we can revert
    563 | 			ticker.frame = 1; //hack to make legacy versions of GSAP apply lag smoothing upon wake
    564 | 			ticker.wake(true);
    565 | 			ticker.frame = originalFrame;
    566 | 		}
    567 | 		
    568 | 		this.dispatchEvent("wake");
    569 | 		this.awake = true;
    570 | 	};
    571 | 
    572 | 	p._tick = function(evt) {
    573 | 		/* tab visibility */
    574 | 		if (document.hidden || document.webkitHidden || document.mozHidden) {
    575 | 			this.hidden = true;
    576 | 			this._sleep();
    577 | 			if (createjs.Sound) { createjs.Sound.muted = true; }
    578 | 			return;
    579 | 		} else if (this.hidden) {
    580 | 			this.hidden = false;
    581 | 			if (this._awake) { this._wake(); }
    582 | 			this._perfDelay = 3;
    583 | 			if (createjs.Sound) { createjs.Sound.muted = false; }
    584 | 		}
    585 | 		this._time += this._sleepUseTicks ? 1 : evt.delta;
    586 | 		
    587 | 		/* perf */
    588 | 		var fps;
    589 | 		if (this._perfFPS && (--this._perfDelay <= 0) && (fps = createjs.Ticker.getMeasuredFPS(1)) > -1) {
    590 | 			var val = 1-Math.max(0, Math.min(1, fps / this._perfFPS));
    591 | 			this._perfCount = Math.max(0, this._perfCount + (val === 0 ? -0.2 : val*val*0.5+0.1));
    592 | 			if (this._perfCount > this._perfThreshold) {
    593 | 				this._perfFPS = 0;
    594 | 				if (this.dispatchEvent(new createjs.Event("slow", false, true))) {
    595 | 					this.sleep();
    596 | 					this.sleepEnabled = false;
    597 | 				}
    598 | 			}
    599 | 		}
    600 | 		
    601 | 		/* sleep */
    602 | 		if (this.sleepEnabled) {
    603 | 			if (this._sleepInBoundsT != null && this._stage.mouseInBounds && this._mouseInDoc) { this.wake(this._sleepInBoundsT*1000); }
    604 | 			if (this._sleepy) { this.sleep(); }
    605 | 			else if (this._sleepT && (this._getTime() >= this._sleepT)) { this._sleepy = true; } // delay 1 tick.
    606 | 		}
    607 | 	};
    608 | 	
    609 | 	p._getTime = function() {
    610 | 		return this._time;
    611 | 	};
    612 | 	
    613 | 	p._getBackingRatio = function() {
    614 | 		var ctx = this._stage.canvas.getContext("2d");
    615 | 		return ctx.backingStorePixelRatio || ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || 1;
    616 | 	};
    617 | 
    618 | 	createjs.AdHelper = AdHelper;
    619 | })();
    620 |     
    621 |
    622 | 623 |
    624 |
    625 |
    626 |
    627 |
    628 |
    629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | -------------------------------------------------------------------------------- /AdHelper/docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 |
    16 |
    17 | 18 |

    19 | 20 |
    21 |
    22 | API Docs for: 23 |
    24 |
    25 |
    26 | 27 |
    28 | 56 |
    57 |
    58 |
    59 | Show: 60 | 64 | 65 | 69 | 70 | 74 | 78 | 79 |
    80 | 81 | 82 |
    83 |
    84 |
    85 |
    86 |
    87 |

    88 | Browse to a module or class using the sidebar to view its API documentation. 89 |

    90 | 91 |

    Keyboard Shortcuts

    92 | 93 |
      94 |
    • Press s to focus the API search box.

    • 95 | 96 |
    • Use Up and Down to select classes, modules, and search results.

    • 97 | 98 |
    • With the API search box or sidebar focused, use -Left or -Right to switch sidebar tabs.

    • 99 | 100 |
    • With the API search box or sidebar focused, use Ctrl+Left and Ctrl+Right to switch sidebar tabs.

    • 101 |
    102 |
    103 |
    104 | 105 | 106 | 107 |
    108 |
    109 |
    110 |
    111 |
    112 |
    113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /AdHelper/garyad.fla: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CreateJS/html5ads/acc307901503f2ac61511d94ab96a6191d315904/AdHelper/garyad.fla -------------------------------------------------------------------------------- /AdHelper/garyad.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | garyad 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /AdHelper/garyad_deploy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | garyad 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /AdHelper/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 14 | 15 | 16 | This page simulates how ads are usually embedded in a host page via an iframe. It allows testing in a more realistic environment, as iframes can sometimes cause problems with interaction. 17 |

    18 | 19 | 20 | -------------------------------------------------------------------------------- /AdHelper/sounds/EnemyHit.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CreateJS/html5ads/acc307901503f2ac61511d94ab96a6191d315904/AdHelper/sounds/EnemyHit.mp3 -------------------------------------------------------------------------------- /AdHelper/sounds/LaserGunShot.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CreateJS/html5ads/acc307901503f2ac61511d94ab96a6191d315904/AdHelper/sounds/LaserGunShot.mp3 -------------------------------------------------------------------------------- /AdHelper/tools/gulpfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by grant on 15-09-27. 3 | */ 4 | var gulp = require("gulp"); 5 | var yuidoc = require("gulp-yuidoc"); 6 | var uglify = require("gulp-uglify"); 7 | var rename = require("gulp-rename"); 8 | 9 | gulp.task("docs", function() { 10 | return gulp.src("../AdHelper.js") 11 | .pipe(yuidoc()) 12 | .pipe(gulp.dest("../docs")); 13 | }); 14 | 15 | gulp.task("minify", function() { 16 | return gulp.src("../AdHelper.js") 17 | .pipe(uglify()) 18 | .pipe(rename({suffix:".min"})) 19 | .pipe(gulp.dest("../")); 20 | }); -------------------------------------------------------------------------------- /AdHelper/tools/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "banner", 3 | "version": "0.8.0", 4 | "description": "CreateJS banner and AdHelper example", 5 | "main": "AdHelper.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Grant Skinner", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "gulp": "^3.9.0", 13 | "gulp-rename": "^1.2.2", 14 | "gulp-uglify": "^1.4.1", 15 | "gulp-yuidoc": "^0.1.2" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # White Paper: HTML5 Banner Ads With CreateJS 2 | An in-depth white paper on building HTML5 advertising with CreateJS and Flash Pro. Includes supporting materials, sample banner ad, and helper classes. 3 | 4 | The document can be read online at: 5 | [http://createjs.com/html5ads/](http://createjs.com/html5ads/) 6 | 7 | The AdHelper directory includes the AdHelper class, and an example banner ad created with Flash Professional CC. -------------------------------------------------------------------------------- /assets/TOC.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by grant skinner on 15-10-01. 3 | * Simple script to build a Table Of Contents from the document structure. 4 | */ 5 | (function() { 6 | if (document.readyState === "complete") { buildTOC(); } 7 | else { window.addEventListener("load", buildTOC); } 8 | 9 | function buildTOC() { 10 | var headers = document.querySelectorAll("h1, h2"); 11 | var toc = document.getElementById("toc"); 12 | var ul = document.createElement("ul"); 13 | ul.className = "toc"; 14 | toc.appendChild(ul); 15 | var anchors = {}; 16 | for (var i = 0; i < headers.length; i++) { 17 | var h = headers[i], j = 0; 18 | var level = parseInt(h.nodeName[1]); 19 | var name = (h.textContent || h.innerText).replace(/\W/g, ""), id = name; 20 | while (anchors[id]) { anchor = name + "_" + (j++); } 21 | var a = document.createElement("a"); 22 | a.setAttribute("name", id); 23 | a.setAttribute("id", id); 24 | h.parentNode.insertBefore(a, h); 25 | 26 | var li = document.createElement("li"); 27 | li.className = "toc" + level; 28 | a = document.createElement("a"); 29 | a.setAttribute("href", "#" + id); 30 | a.innerHTML = h.textContent; 31 | li.appendChild(a); 32 | ul.appendChild(li); 33 | } 34 | } 35 | })(); -------------------------------------------------------------------------------- /assets/styles.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Titillium+Web:400,600); 2 | @import url(https://fonts.googleapis.com/css?family=Source+Code+Pro:600); 3 | 4 | body { 5 | font-family: 'Titillium Web', Arial, sans-serif; 6 | font-size: 14pt; 7 | line-height: 1.5em; 8 | background: #f6f6f6; 9 | margin:0; 10 | } 11 | 12 | img { 13 | width: 100%; 14 | } 15 | 16 | article { 17 | padding: 4.5em; 18 | padding-top: 1em; 19 | max-width: 42em; 20 | background: #FFF; 21 | color: #222; 22 | margin: auto; 23 | box-shadow: 1px 1px 8px rgba(0,0,0,0.1); 24 | } 25 | 26 | strong { 27 | color: #111; 28 | } 29 | 30 | a { 31 | text-decoration: none; 32 | color: #25A; 33 | } 34 | 35 | a:hover { 36 | text-decoration: underline; 37 | } 38 | 39 | li { 40 | margin-bottom: 0.66em; 41 | } 42 | 43 | h1, h2, h3 { 44 | font-family: 'Titillium Web', Arial, sans-serif; 45 | font-weight: bold; 46 | margin-top: 1.5em; 47 | margin-bottom: 0.5em; 48 | color: #111; 49 | } 50 | 51 | h1 { 52 | font-weight: normal; 53 | font-size: 2em; 54 | background: #111; 55 | color: white; 56 | padding: 0.33em; 57 | margin-left: -0.33em; 58 | margin-right: -0.33em; 59 | line-height: 1.25em; 60 | } 61 | 62 | h2 { 63 | font-size: 1.5em; 64 | border-bottom: solid #111 2.5px; 65 | padding-bottom: 0.15em; 66 | } 67 | 68 | h3 { 69 | font-size: 1.2em; 70 | } 71 | 72 | code, pre { 73 | font-family: 'Source Code Pro', monospace; 74 | background: #f6f6f6; 75 | border: solid #e3e3e3 1px; 76 | padding-left: 0.33em; 77 | padding-right:0.33em; 78 | font-size: 0.85em; 79 | color: #000; 80 | } 81 | 82 | pre { 83 | padding: 1em; 84 | overflow: auto; 85 | line-height: 1.3em; 86 | tab-size: 4; 87 | } 88 | 89 | hr { 90 | border: none; 91 | border-bottom: dotted #222 4px; 92 | display: none; 93 | } 94 | 95 | .toc { 96 | list-style-type: none; 97 | margin: 0; 98 | padding: 0; 99 | margin-top: 1.5em; 100 | line-height: 1.4em; 101 | } 102 | 103 | .toc li { 104 | margin-bottom: 0; 105 | } 106 | 107 | .toc1 { 108 | font-weight: bold; 109 | margin-top: 0.33em; 110 | } 111 | 112 | .toc2 { 113 | margin-left: 2em; 114 | } 115 | 116 | .toc3 { 117 | margin-left: 4em; 118 | } 119 | 120 | @media print { 121 | body, article { 122 | font-size: 11pt; 123 | background: #fff; 124 | } 125 | 126 | h1 { 127 | background: #fff; 128 | color: #000; 129 | font-weight: bold; 130 | border-bottom: solid black 3px; 131 | } 132 | 133 | h2 { 134 | border: 0; 135 | } 136 | 137 | code, pre { 138 | background: #f3f3f3; 139 | border: solid #e9e9e9 1px; 140 | } 141 | } -------------------------------------------------------------------------------- /assets/workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CreateJS/html5ads/acc307901503f2ac61511d94ab96a6191d315904/assets/workflow.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | White Paper: HTML5 Banner Ads With CreateJS 6 | 7 | 8 | 9 | 10 |
    11 | 12 | 13 |

    HTML5 Banner Ads With CreateJS

    14 | 15 |
    16 | 17 |

    Preamble

    18 | 19 |

    This is a living document. It will be updated as standards and best practices evolve. See Appendix: Document History for a list of changes. The source, along with supporting materials, examples, and helper classes is available at github.com/createjs/html5ads/, and contributions are welcome.

    20 | 21 |

    The content of this document is copyrighted, and is licensed under the Creative Commons Attribution license.

    22 | 23 |

    Introduction

    24 | 25 |

    The online advertising industry has been subject to numerous disruptive changes recently. Traditionally, most ads were built with Flash Pro and dependent on the Flash plugin. The rise of mobile browsing on platforms that do not support plugins has provided an increasingly compelling reason to find alternative workflows, but Google's recent move to block Flash ads in Chrome, and Amazon no longer accepting these ads make finding new solutions imperative.

    26 | 27 |

    This article explores how the CreateJS suite of libraries allows ad creators to transition easily to HTML5/JS, examines how the libraries fit into emerging IAB (Interactive Advertising Bureau) standards, and provides guidance for creators making the transition. Workflows using the new HTML5 Canvas publish target for Flash Pro will also be discussed, including how it boosts productivity and allows ad creators to leverage prior experience or even convert existing ads.

    28 | 29 |

    Appendixes provide more in-depth information on technical topics.

    30 | 31 |

    Authors

    32 | 33 |

    This document was authored by:

    34 | 35 |

    Grant Skinner, CEO gskinner, inc.

    36 | 37 |

    Grant and his team at gskinner conceptualize, design, and build world-class interactive experiences for smart clients such as Microsoft, Google, Mozilla, and EA. He has spoken at hundreds of events on five continents about interactive design and development. He heads the development of CreateJS, and partnered closely with Adobe to lead the development of the HTML5 Canvas publishing for Flash Professional.

    38 | 39 |

    Cory Hudson, Sr. Director, Creative Technology, AOL

    40 | 41 |

    Cory leads a large team of interactive designers and front-end developers who are entirely focused on building feature-rich, cross-screen advertising experiences. His team is directly responsible for developing highly engaging creative solutions and driving technical R&D initiatives in order to effectively evaluate and leverage emerging technologies within AOL's digital advertising formats and platforms. Cory also serves as Chair of the IAB's HTML5 Working Group, where he leads an industry-wide group of experts who are collaboratively working to establish standardized best practices and guidelines for HTML5 based digital advertising.

    42 | 43 |

    Emerging IAB Standards

    44 | 45 |

    The Interactive Advertising Bureau (IAB) recognizes that the industry's long established digital advertising specs tailored to the SWF file format are no longer viable for HTML5-based advertising. With HTML5 there is no longer a convenient dependency upon a single, optimized creative asset package, but rather a compilation of separate assets that must be created, optimized, measured and evaluated individually, while collectively adhering to standardized specs.

    46 | 47 |

    This introduces several new obstacles that must be adequately accounted for in order to successfully deliver a compliant advertising experience. The challenges that HTML5 faces when compared to Flash are mainly the required overall file size and number of HTTP server requests associated with an ad unit.

    48 | 49 |

    File Size

    50 | 51 |

    Client bandwidth has increased significantly since the 40kB file size limitation was first introduced. Additionally, the realities of building HTML5-based ad units make it more challenging to adhere to this limit.

    52 | 53 |

    Based on these factors, a desire to enable richer ad experiences, and in accordance with the results of recent IAB sponsored industry-wide performance testing, the IAB is proposing an increase in the file size standard for most HTML5 ad formats to 200kB.

    54 | 55 |

    Because most ad networks and browsers automatically gzip files crossing the network, file size will be calculated by combining the total gzipped, wire-weights of all utilized assets that are initially required in order for the ad to display in a local, standalone environment. This includes all local images, CSS, JS, HTML, etc.

    56 | 57 |

    Shared Libraries Exception

    58 | 59 |

    The sole exception to the file-size policy is CDN hosted JavaScript libraries that are granted an exception by the publisher or ad server, because these common libraries are leveraged across multiple campaigns and can be cached by users' browsers. A number of ad networks are already supporting this exception for CreateJS (ex. CoFactor/Pointroll, AOL).

    60 | 61 |

    CreateJS is on a shortlist of suitable libraries (widely used and distributed, professionally maintained, well documented, frequently updated, backwards compatible) that the IAB will publicly recommend through its soon-to-be-updated and republished HTML5 Best Practices documentation, located at http://www.iab.net/html5. This would ultimately allow ad creators to exclude the file size of the library from the overall 200kB file size calculation.

    62 | 63 |

    CreateJS

    64 | 65 |

    Developed by widely-recognized interactive shop gskinner to facilitate the creation of Flash-like experiences using open web standards (ex. HTML5), CreateJS is a suite of four libraries that accelerate the production of rich interactive experiences such as games, ads, data visualizations, and micro-sites.

    66 | 67 |

    The four libraries in the suite can be used together or completely independently, and are focused on specific areas of functionality.

    68 | 69 |

    EaselJS

    70 | 71 |

    High performance 2D graphics and interaction, with a Flash-inspired display list and feature-rich API.

    72 | 73 |

    SoundJS

    74 | 75 |

    Audio playback and management, with transparent support for WebAudio, Audio elements, and optional Flash plugin fallback.

    76 | 77 |

    PreloadJS

    78 | 79 |

    Robust asset loading and management, with granular progress reports, and nested dependencies.

    80 | 81 |

    TweenJS

    82 | 83 |

    Simple but powerful animation engine with multi-step tweens, synced tweens, non-numeric property support, and motion paths.

    84 | 85 |

    CreateJS has no external dependencies, imposes no specific architectural requirements on your code, and is designed to work seamlessly with almost every other JS library, including favorites like GSAP (aka TweenLite), Three.js, AngularJS, and jQuery.

    86 | 87 |

    It is free and open source, licensed under the permissive MIT license. This means it can be easily incorporated into commercial projects, and the project welcomes contributions and feedback from the community.

    88 | 89 |

    CreateJS is robust and mature. The suite was created and is maintained by a highly experienced team of interactive developers and designers, who have been building rich content for over 15 years using Flash and HTML5. It is over 5 years old, has grown through 8 major releases, and has been sponsored by Adobe, Microsoft, Mozilla, and AOL. CreateJS is used by tens of thousands of developers, with over one third of FWA Site of the Day winners using it, and content built with CreateJS is viewed by hundreds of millions of users every day.

    90 | 91 |

    Flash Professional: HTML5 Canvas

    92 | 93 |

    Great experiences require both code and design. While it's entirely possible to code amazing content with CreateJS, Flash Pro CC empowers designers to engage fully, and boosts productivity by accelerating the creation of art and animation.

    94 | 95 |

    With Flash Pro, you can create an "HTML5 Canvas" document, which will be output as human-readable JavaScript code leveraging the CreateJS libraries when published.

    96 | 97 |

    As is the case for traditional Flash development, it is possible to create interactive banners entirely in Flash with timeline scripting. For more complex projects though, you may realize considerable benefits from using Flash Pro to prepare an asset library of art and animation, then write business logic in your code editor of choice that utilizes those assets.

    98 | 99 |

    This approach provides a clear delineation of roles and asset ownership between developer and designer. Designers own the FLA, and hand off the published assets to a developer, who can integrate them into a larger project, and manage them via version control. The designer never has to worry about the code, and the developer never has to open the FLA or modify the published assets.

    100 | 101 |

    See "Appendix: Designer / Developer Workflow" for more information on this topic.

    102 | 103 |

    Considerations

    104 | 105 |

    While CreateJS and Flash Pro provide a highly productive workflow, and allow you to leverage prior experience with Flash, there are important considerations to keep in mind when getting started.

    106 | 107 |

    Code & API Differences

    108 | 109 |

    CreateJS content is developed using JavaScript, which is very similar to ActionScript, however there are some notable differences that you should be aware of when converting common functionality within Flash Pro CC.

    110 | 111 |

    The most immediate difference is scope, which must be defined explicitly. For example, on the timeline, rather than calling stop(), you must use this.stop().

    112 | 113 |

    While the CreateJS API will be very familiar to ActionScript developers, there are significant differences. As examples, only Container and MovieClip can have child objects, and only Shape can draw vector graphics. Timelines are zero based: this.gotoAndStop(0) will take you to the first frame.

    114 | 115 |

    More detail on this topic can be found in "Appendix: Code & API Differences".

    116 | 117 |

    Browser Compatibility

    118 | 119 |

    CreateJS is reliably supported by all modern browsers. The only unsupported browser with notable market share is IE8 (<2% market share and dropping) due to its lack of Canvas or Audio support. We recommend providing a fallback static image with a link for unsupported browsers. This can be done with code similar to the following, which prevents the fallback image from loading unless it is needed.

    120 | 121 |
    122 | <canvas><script>
    123 | if (!window.CanvasRenderingContext2D) {
    124 | document.write("<a href='url'><img src='image.jpg' alt='text'></a>");
    125 | }
    126 | </script></canvas>
    127 | 
    128 | 129 |

    The CreateJS AdHelper class described in "Appendix: AdHelper" simplifies setting up fallback content, and makes the code above unnecessary.

    130 | 131 |

    Load Optimization

    132 | 133 |

    There are a number of strategies and techniques you can employ to reduce the size of the assets used in your ad and ensure it adheres to the 200kB limit specified by the IAB. Minimizing the number of HTTP requests required to display your ad is also important to decrease load times.

    134 | 135 |

    Reducing HTTP Requests

    136 | 137 |

    Recent IAB-sponsored performance testing has indicated that the number of HTTP requests can have a significant impact on the perceived loading performance of the visual ad unit, especially on mobile devices. Minimizing the number of requests allows the browser to optimize and parallelize loads, and reduces the overall time cost for establishing http connections.

    138 | 139 |

    The emerging HTTP2 standard will mitigate this concern by allowing browsers and servers to transfer multiple assets over a single connection.

    140 | 141 |

    Ideally, the number of initial HTTP requests should be kept below 8. This would include all creative assets, CDN hosted and cached support files, and necessary 3rd party impression or click tracking calls.

    142 | 143 |

    Using sprite sheets, code minification / concatenation, and data URIs (for embedded web fonts or SVGs) can all help reduce HTTP connections.

    144 | 145 |

    CreateJS's PreloadJS library provides capabilities for loading assets, including progress events, maintaining dependencies, loading subsequent assets on interaction, and specifying a maximum number of parallel http connections (via queue.maxConnections). EaselJS supports sprite sheets and audio sprites, and Flash Pro allows for the automatic creation of sprite sheets during publishing.

    146 | 147 |

    Graphics

    148 | 149 |

    The bulk of file size for most ads is in graphical assets. There are a number of techniques you can use to reduce this cost.

    150 | 151 |

    Vector Graphics

    152 | 153 |

    Vector graphics represent art as a collection of resolution-independent drawing commands. They are especially suited to illustrations and other non-photographic art. Unlike bitmap images, they can be scaled indefinitely and retain full fidelity, which makes them ideal for responsive designs targeting multiple display sizes or densities. When used with appropriate content, vectors can also be much smaller than the equivalent bitmap image.

    154 | 155 |

    The primary disadvantage to using vectors is that rendering performance scales directly with the complexity (ex. number of curves and points) in the graphic. This is especially true on mobile devices where CPUs are slower and less powerful.

    156 | 157 |

    Coding vector graphics manually is possible, but not pragmatic. Luckily, there are several tools that can make working with vector graphics very intuitive. You can create graphics within Flash Pro, or use other software programs such as Adobe Illustrator and then import the result directly into Flash Pro.

    158 | 159 |

    See "Bitmap Caching" below for a technique to reduce the ongoing cost of drawing complex vector graphics.

    160 | 161 |

    Bitmaps

    162 | 163 |

    Bitmaps graphics define the color of every pixel in an image. It is very inexpensive for the GPU to manipulate bitmap images, so leveraging bitmaps within your animations rather than vectors can often provide tremendous performance gains.

    164 | 165 |

    Bitmaps are ideal for photographic images as well as imagery that requires soft-edges and transparency. Using vectors for these types of graphics would require a gratuitous amount of complexity to represent the image detail, resulting in increased file size as well as visual results that don't appear as natural.

    166 | 167 |

    The main disadvantages to using bitmaps is that they come at the expense of increased memory overhead and lack of scalability when compared to vectors. Bitmaps can consume a great deal of both RAM and graphics memory and overuse can cause performance problems on mobile devices. This is especially true with the need to support high DPI screens, which can require you to double the size of images, effectively quadrupling their memory footprint.

    168 | 169 |

    Bitmap Caching

    170 | 171 |

    Similar to Flash Player, EaselJS supports bitmap caching, which allows you to pre-render complex graphics to an off-screen bitmap, so it does not have to be rendered each frame. This can provide significant performance benefits when used appropriately with static art.

    172 | 173 |

    The rules for using bitmap caching are similar to using it with Flash Player: use it only on static content, and only when the complexity of the graphics are sufficient to warrant its use. This is because bitmap caching creates new bitmaps, which use both RAM and graphics memory. The latter is limited on mobile devices and overuse can cause performance problems.

    174 | 175 |

    Bitmap caching can be applied from within Flash Pro via the "cache as bitmap" option, or with code using the cache() method of display objects.

    176 | 177 |

    High DPI Screen Support

    178 | 179 |

    In order to ensure that bitmaps are displayed crisply on high DPI screens, they should be created at double the display size and then scaled down accordingly within Flash Pro. For example an image that is intended to display at 300x250, should actually be created at 600x500 and then scaled down to 300x250 within Flash Pro. Alternatively, you could author your FLA at double resolution, and scale it to the appropriate size at runtime.

    180 | 181 |

    This should be approached in a strategic manner in order to avoid the unnecessary bloating of the overall file size associated with your image assets. You can sometimes avoid having to double the dimensions of photographic images that are not the focal point of the ad experience (e.g. photographic background image).

    182 | 183 |

    Conversely, photographic imagery that is the focal point of the ad experience or graphical elements that have sharp, crisp edges such as logos, line artwork and text will most likely always need to be doubled in dimensions because the difference in visual quality is very apparent and noticeable.

    184 | 185 |

    Testing your ad on high DPI devices will allow you to determine which graphics will need to be double-sized or not. With experience you will be able to identify these scenarios readily.

    186 | 187 |

    The CreateJS AdHelper class described in "Appendix: AdHelper" makes it easier to work with high DPI screens, including support for content authored at double scale.

    188 | 189 |

    Compression

    190 | 191 |

    Unfortunately, Flash Pro's default bitmap compression is not very aggressive. You should leverage other image optimization tools such as ImageOptim or ImageAlpha to more fully compress your images. In some cases, these tools can reduce image size by 50-75% without any visible loss in quality. These tools can also be integrated into automated build processes.

    192 | 193 |

    Sprite Sheets

    194 | 195 |

    Sprite sheets combine multiple images or frames of animation onto one larger image, and can dramatically reduce your overall file size and number of server requests.

    196 | 197 |

    It is suggested that you combine similar images into sprite sheets, a single JPG sprite sheet for photographic images with opaque backgrounds and another separate PNG sprite sheet for crisp graphics and imagery that requires transparency. There should generally be no need for more than 2 sprite sheets.

    198 | 199 |

    You can create sprite sheets manually in Photoshop or using standalone tools such as Zoë or TexturePacker. However the easiest way to create sprite sheets when creating ads with Flash Pro is to use its built-in features:

    200 | 201 |
    • Generate Sprite Sheet. Available via the Flash Pro library panel and requires manual placement and masking for each displayed image.
    • 202 | 203 |
    • Export All Bitmaps As Sprite Sheets. Available via the Flash Pro publish settings which automatically handles sprite sheet creation for you however currently outputs a single sprite sheet for all asset types. "Appendix: Code & API Differences" has additional information on leveraging this new feature.
    204 | 205 |

    Audio

    206 | 207 |

    When used, audio can also contribute significantly to file size. As with images, you should consider compressing your audio using a dedicated tool that will provide better results than Flash Pro. This is particularly true because as of the time of writing, Flash Pro does not compress audio below 128kbps.

    208 | 209 |

    When compressing play, with settings and get a feel for what provides adequate quality for your needs. For example, you might be able to use 48kbps mono for voice or some sound effects, but may not want to drop below 128 kbps for music.

    210 | 211 |

    Code

    212 | 213 |

    Traveling over the wire, your code will be gzipped, which will vastly reduce its file size automatically. However, you can further decrease the file size via minification, and reduce the number of HTTP requests via concatenation.

    214 | 215 |

    Concatenation involves combining multiple source files into a single file. Ideally, all of your source files (HTML, CSS, JS) are combined into a single HTML file prior to deployment.

    216 | 217 |

    Minification is the process of removing all unnecessary characters from the source code, such as whitespace and comments. More aggressive minification will also refactor your code to use shorter variable names and more compact syntax.

    218 | 219 |

    These processes make your code vastly harder to work with, and as such should be used to build a copy of the code for deployment. They are easily integrated into an automated build process using Grunt or Gulp. The functionality of the code should remain intact, but it's important to always test after concatenation and minification.

    220 | 221 |

    Performance

    222 | 223 |

    Building your ads with performance in mind is critical, especially when they will be viewed on mobile devices. Not only do you want your ads to play back smoothly, but you also want to be respectful of users' experience of the site they are visiting, and the battery life of their device.

    224 | 225 |

    There are a number of factors that can have a significant impact on the performance of CreateJS content. It's good to be aware of them, and avoid or use them sparingly.

    226 | 227 |
    • drop shadows and glows can be expensive to render, especially on mobile devices
    • 228 | 229 |
    • filters are very performance intensive, and it is recommended to consider alternatives to animating them directly. For example, rather than animate a ColorMatrixFilter to fade a Bitmap from grayscale to color, consider desaturating a copy of the Bitmap by applying the filter once, and fade it over top of the colored version. Similar approaches can be used for blurs and color transforms (which are filters in EaselJS).
    • 230 | 231 |
    • complex vector graphics with lots of curves or points (or large numbers of simpler vectors graphics). Consider using bitmap caching to pre-render complex vectors.
    • 232 | 233 |
    • large or complex gradients (especially circular gradients).
    • 234 | 235 |
    • vector masks are costly in some browsers, consider using compositeOperation in combination with bitmap caching to attain similar results.
    236 | 237 |

    You should always profile your content's performance using browser developer tools prior to deployment. Be sure to consider the relative performance of the device you use to profile versus the devices your users may be using. Testing on actual devices is always ideal when possible.

    238 | 239 |

    Performance monitoring

    240 | 241 |

    Some devices are just slow. It doesn't matter how well you author your ad, it will likely never run well on a 5 year old phone intended for a third-world market. Given that, it's a good idea to monitor the performance of your ad, and fall back to alternate content (ex. an image) if it's performing poorly.

    242 | 243 |

    The EaselJS Ticker can help with this via its getMeasuredFPS() and getMeasuredTickTime() methods. The former returns the actual framerate that the Ticker is running at, and the latter reports the time actually spent executing each tick. For example, if an ad that was authored to play at 20fps reported 19.8fps, that would mean it's playing right around where we'd expect. However, if it was using 48ms each tick on a desktop PC, that would indicate that it was using almost all of the time available per frame (48ms of 50ms), which could lead to problems when running on less powerful devices.

    244 | 245 |

    The CreateJS AdHelper class described in "Appendix: AdHelper" provides a configurable method for monitoring performance and showing fallback content or providing actionable events. It also correctly avoids false positives when running in a background tab.

    246 | 247 |

    Duration

    248 | 249 |

    Ads are often required to run for a set amount of time before sleeping (pausing). It's reasonably easy to set a timer to do this in JavaScript, however it's important to consider the elastic nature of frame timing in EaselJS.

    250 | 251 |

    When you set a framerate, this doesn't guarantee that your content will play back at that speed. If the device becomes overburdened, frames may take longer to render, slowing the playback of your content. This can cause problems when your ad fails to reach the expected keyframe in the allotted time.

    252 | 253 |

    EaselJS allows you to set a target framerate on MovieClip and Sprite instances, placing them in a time-synced mode. If the real-world framerate drops, the MovieClip will adjust its playback rate to accommodate it. For example, if you set a target framerate of 20 on a MovieClip, and the real-world framerate drops to 10fps, it will play 2 frames per second to remain synchronized.

    254 | 255 |
    256 | myMovieClip.framerate = 20;
    257 | 
    258 | 259 |

    Note that the timing may still vary slightly, but this is easily resolved by shortening your animation by a small amount. For example, if you have a 15s maximum duration, you may want to author your ad to be 14.8s long to ensure it reaches the last frame before sleeping.

    260 | 261 |

    The CreateJS AdHelper class described in "Appendix: AdHelper" provides tools for scheduling sleep and wake for ads, as well as propagating a target framerate to all MovieClip instances in the display list.

    262 | 263 |

    Summary

    264 | 265 |

    Authoring ads using CreateJS and Flash Pro allows you to leverage your existing skills and workflows to develop rich interactive content built on open web standards, that can play on any device, and adhere fully to the emerging IAB standards.

    266 | 267 |

    There are a number of differences from SWF and AS3 production, and as with any new platform, it will take a bit of adjustment to fully develop your expertise. However, a lot of effort has been put into both CreateJS and Flash Pro's HTML5 Canvas publishing to make it comfortable and familiar to developers coming from a SWF background.

    268 | 269 |

    To get started, check out the demos and documentation on the CreateJS site or download the latest source and examples from the CreateJS GitHub repo. Then, install the latest version of Flash Professional, and check out the AdHelper example.

    270 | 271 |


    272 | 273 |

    Appendix: Links

    274 | 275 |

    HTML5 Ads

    276 | 277 | 280 | 281 |

    CreateJS

    282 | 283 | 290 | 291 |

    You can access tutorials and examples for each CreateJS library by cloning its GitHub repository (or simply downloading the latest as a zip file), and looking in the /tutorials and /examples directories.

    292 | 293 |

    Tools

    294 | 295 | 304 | 305 |

    JavaScript / Web

    306 | 307 | 316 | 317 |


    318 | 319 |

    Appendix: AdHelper

    320 | 321 |

    AdHelper is a helper class that makes it easier to build and deploy ads using CreateJS. It serves a number of functions, and is very easy to set up.

    322 | 323 |
    324 | var ad = new createjs.AdHelper(myStage);
    325 | 
    326 | 327 |

    AdHelper can be found in the CreateJS Sandbox repository on GitHub:

    328 | 329 |

    http://github.com/createjs/sandbox/

    330 | 331 |

    Method Chaining

    332 | 333 |

    Most methods can be chained for simpler setup. For example, the following code creates a new AdHelper instance and enables time sync, performance monitoring, and high dpi support using default settings.

    334 | 335 |
    336 | new createjs.AdHelper(myStage).timeSync().watchFPS().highDPI();
    337 | 
    338 | 339 |

    Sleep / Wake

    340 | 341 |

    Puts the ad to sleep according to a configurable schedule, and wakes it for the specified amount of time when the mouse is within the ad, or the user clicks in the ad. When an ad is put to sleep, its Ticker is paused, its tick listener is unsubscribed, any GreenSock tweens are paused, and a sleep event is dispatched to allow custom handling. On wake, this is reversed, and a wake event is generated.

    342 | 343 |
    344 | ad.setSleep(start, mousedown, inBounds, useTicks, listener);
    345 | 
    346 | 347 |

    Ads can also be put to sleep directly via the "sleep" and wake" methods:

    348 | 349 |
    350 | ad.wake(time);
    351 | ad.sleep(delay);
    352 | 
    353 | 354 |

    Visibility

    355 | 356 |

    Detects when the ad is not visible (ex. in a background browser tab), and sleeps the ad and mutes all sound. Resumes / unmutes the ad when it is visible. The "hidden" property is set accordingly and the sleep and wake events are dispatched as normal.

    357 | 358 |

    This feature is enabled automatically when using AdHelper.

    359 | 360 |

    CreateJS Support

    361 | 362 |

    Test to see if CreateJS is supported on the current browser. For example, this can be used to display alternative content.

    363 | 364 |
    365 | if (!createjs.AdHelper.isSupported()) {
    366 | 	createjs.AdHelper.showAltImage(myCanvas, "myImage.jpg", "url");
    367 | }
    368 | 
    369 | 370 |

    Alternative Content

    371 | 372 |

    Static methods to replace your ad canvas with alternative content. This can be useful when CreateJS is not supported, or if performance monitoring determines the ad is running too slowly. There are three methods, that give different levels of control.

    373 | 374 |
    375 | createjs.AdHelper.showAltImage(canvas, imgSrc, href, alt, target);
    376 | createjs.AdHelper.showAltHTML(canvas, html);
    377 | createjs.AdHelper.showAlt(canvas, element);
    378 | 
    379 | 380 |

    Time Sync

    381 | 382 |

    Force all MovieClips in the ad to operate in time-synced mode (ie. by setting framerate on all MovieClip instances). This allows the ad to play back with a predictable duration even if the real framerate fluctuates.

    383 | 384 |
    385 | ad.timeSync(framerate);
    386 | 
    387 | 388 |

    High DPI Support

    389 | 390 |

    Enable full resolution rendering on high DPI screens. Can also be used to disable full resolution rendering on high DPI screens to improve performance. Also allows for authoring the ad at a different scale.

    391 | 392 |
    393 | ad.highDPI(enabled, nominalScale);
    394 | 
    395 | 396 |

    Performance Monitoring

    397 | 398 |

    Monitors playback framerate, and uses a simple heuristic to determine when the ad fails to satisfy configurable performance minimums. Dispatches a slow event and sleeps the ad by default. Works with visibility features to avoid failing while in a background tab due to throttling.

    399 | 400 |
    401 | ad.watchFPS(minFPS, tolerance);
    402 | 
    403 | 404 |


    405 | 406 |

    Appendix: Designer / Developer Workflow

    407 | 408 |

    As with traditional SWF development, there are many valid workflows for developing HTML5 Canvas content using Flash Pro.

    409 | 410 |

    For simpler projects owned by a single designer, building everything on the timeline, including simple frame scripts is often perfectly acceptable.

    411 | 412 |

    As projects grow in complexity, it is generally wise to create a separation between the creation of visual assets (presentation), and the code that drives functionality (logic). In many cases these areas are divided between a designer(s) and developer(s) respectively. Even when a single creator is producing the full project there are usually significant benefits to productivity, quality control, reuse, and robustness that can be realized by separating presentation and logic.

    413 | 414 |

    One common approach to this separation when building CreateJS content is to have the FLA owned entirely by the designer, who passes the published JS library to the developer (via email, version control, etc), who consumes it into a larger project with additional HTML and JS files. It winds up looking something like this:

    415 | 416 | 417 | 418 |

    Using this approach, the developer should almost never need to touch the published JS. They can simply treat it as an asset library, instantiating elements from it using new. For example, if the FLA has a symbol named (or with the linkage) "FunnyCat", a developer could add an instance to the stage, position it, and play its "run" animation using:

    419 | 420 |
    421 | var myCat = new lib.FunnyCat();
    422 | stage.addChild(myCat);
    423 | myCat.x = 100;
    424 | myCat.gotoAndPlay("run");
    425 | 
    426 | 427 |

    The JS file also includes a properties object that includes information on the original FLA (dimensions, background color, framerate), and a manifest of external media assets that can be passed directly to a PreloadJS LoadQueue.

    428 | 429 |
    430 | var props = lib.properties;
    431 | createjs.Ticker.setFPS(props.fps);
    432 | var queue = new createjs.LoadQueue();
    433 | queue.on("complete", handleComplete, this);
    434 | queue.loadManifest(props.manifest);
    435 | 
    436 | 437 |

    It's often critical for a project's business logic to know when an animation finishes or reaches a particular point. For example, you may want to change the position of the cat in the example above each time it finishes the "run" animation. This is easily achieved. In addition to the presentation code to loop the animation, the designer could also add an event trigger at the end of the animation:

    438 | 439 |
    440 | // timeline code on the last frame of the run animation:
    441 | this.gotoAndPlay("run"); // loop
    442 | this.dispatchEvent("runend"); // the name can be anything
    443 | 
    444 | 445 |

    Once this is in place, the developer can easily subscribe and react to this event:

    446 | 447 |
    448 | myCat.on("runend", function(evt) {
    449 | 	// with on() "this" defaults to the dispatcher.
    450 | this.x += 100;
    451 | });
    452 | 
    453 | 454 |

    This supports a loosely coupled interaction between the timeline and the business logic. The designer only needs to worry about a single simple command to communicate events, and can move the event freely as the animation is revised. The developer can subscribe to events as needed. Events dispatched without subscribers do not generate errors, and have very low cost (no event object is created).

    455 | 456 |


    457 | 458 |

    Appendix: Code & API Differences

    459 | 460 |

    The following are common tasks that you are likely to encounter when building HTML5 ads with Flash Pro.

    461 | 462 |

    Text

    463 | 464 |

    Flash Pro currently only supports the usage of dynamic text fields with a single style which can be very limiting when it comes to controlling the appearance and presentation of type. When Flash Pro converts existing static text fields to dynamic text fields the text is converted to a single style and overrides any specific styling that was previously applied, such as leading, weight, etc., and also visually removes line-wrapping even though the hidden text actually exists and will properly wrap to a new line when published.

    465 | 466 |

    Most advertisers have very specific requirements when it comes to font styling and branding, so these limitations can be challenging and make the design process unnecessarily cumbersome when working within the Flash Pro Canvas project environment. In order to maintain the visual integrity of your styled text you may want to take one of the following approaches:

    467 | 468 |
    • Start your banner ad project as a Flash ActionScript 3 document type (not an HTML5 Canvas FLA) and then break apart all static text before converting the file over to HTML5 Canvas. This will convert all text into vector shapes, maintaining both appearance and scalability.
    • 469 | 470 |
    • Maintain a separate AS3 FLA for the styling of all text and then paste the text into your working HTML5 Canvas document after it has been converted to vector outlines.
    • 471 | 472 |
    • Design all of your text in Photoshop or Flash Pro and then integrate the text as bitmaps. This approach is not recommended as it removes the benefits of vector based text which would be small file size and scalability.
    473 | 474 |

    Regardless of which approach you prefer it is suggested that you adhere to the following best practices when working with vector text inside of Flash Pro CC:

    475 | 476 |

    477 | 478 |
    • Create a movieclip of your broken apart text and set it to cache as bitmap. This will improve performance as the vector drawing calculations won't have to be repeatedly processed on every stage tick.
    • 479 | 480 |
    • Be sure to maintain an editable version of your text by creating a "guided out" backup layer containing a static text field. This ensures that edits can be easily made in the future.
    481 | 482 |

    483 | 484 |

    Filters and Color Effects

    485 | 486 |

    Flash Pro CC supports most filters and color effects. These effects fall into one of two categories: shadow effects, and filter effects. All effects are expensive to render, particularly on mobile devices, and should be tested thoroughly.

    487 | 488 |

    Shadow Effects

    489 | 490 |

    Drop shadows and glows (which are essentially shadows with no offset) are rendered in EaselJS using canvas's built in shadow features. They render reasonably fast on desktop, but can cause performance issues on mobile, and can be applied to animated content.

    491 | 492 |

    At this time, shadow effects cannot be animated on the timeline, though this is primarily an authoring limitation that may be removed in the future.

    493 | 494 |

    Filter Effects

    495 | 496 |

    Blurs, color transforms (excluding alpha), and color adjustments are treated as filters in EaselJS. These effects work by manipulating pixel data, can be quite expensive to render, and require bitmap caching to be enabled to work (this is done automatically when you apply these filters in Flash Pro).

    497 | 498 |

    This bitmap caching "freezes" the movieclip on its first frame, which stops it from animating. Similarly, the filter cannot be animated on the timeline. This is an intentional limitation, because updating filters is very expensive, and it would be very easy to unintentionally create content with very poor performance.

    499 | 500 |

    It is possible to animate content with a filter by re-rendering the filter each tick (or frame) via myDisplayObject.updateCache(), but in almost all cases it is better to consider alternative approaches. For example, to transition an image from grayscale to color, you could simply duplicate the image, apply a grayscale color adjustment to the top copy, and fade down its alpha over the color copy. Similar approaches can be used for blur and color transforms.

    501 | 502 |

    Another option is to create a sprite sheet animation of the filter effect and use that in your ad instead.

    503 | 504 |

    Logging

    505 | 506 |

    It's likely that you've previously used ActionScript's trace()statement to debug your code. In JavaScript, you can use console.log() instead:

    507 | 508 |

    509 | 510 |
    511 | console.log("This is the same as a trace statement." );
    512 | 
    513 | 514 |

    To view console.log()statements when previewing your HTML file, you will need to open up the JavaScript Console in Chrome Dev Tools, or the Console tab in Firebug if you are testing using Firefox. Be aware that in IE9 the console must be open to function correctly or it will generate errors. Make sure you remove any console.log() calls prior to deployment.

    515 | 516 |

    517 | 518 |

    Scope

    519 | 520 |

    JavaScript does not use this as an implicit scope as is the case with ActionScript 3. You must explicitly specify scope in timeline scripts. For example:

    521 | 522 |

    523 | 524 |
    525 | // "this" in a timeline script refers to the MovieClip or stage that it's defined in.
    526 | this.stop();						
    527 | // access a child MovieClip instance:
    528 | this.myChildMC.gotoAndPlay("end");
    529 | 
    530 | 531 |

    532 | 533 |

    Defining Global Variables and Functions

    534 | 535 |

    Variables are defined with the scope of their frame code, so if you define a variable in the first frame, you will not be able to access that variable in the final frame. For example:

    536 | 537 |
    538 | // first frame
    539 | var foo = 20;
    540 | // second frame
    541 | console.log(foo); // undefined
    542 | 
    543 | 544 |

    Scope your variables using this to make them accessible across all frames. Please note that variables are not strictly typed in JavaScript as they were previously in AS3. 545 |

    546 | 547 |
    548 | // first frame
    549 | this.foo = 20;
    550 | // second frame
    551 | console.log(this.foo); // 20
    552 | 
    553 | 554 |

    The same approach should be taken for defining any functions on your timeline that will need to be called later in the animation or by a parent MovieClip:

    555 | 556 |
    557 | this.startOver = function(){
    558 | 	this.score = 0;
    559 | 	this.gotoAndPlay("start");
    560 | };
    561 | 
    562 | 563 |

    Stage, Root, and exportRoot

    564 | 565 |

    When published from Flash Pro, the main timeline of the FLA is exported as a MovieClip and assigned a global reference named exportRoot, which can be used to access it from nested MovieClips. By default exportRoot is the only child of the EaselJS Stage.

    566 | 567 |

    EaselJS also exposes a stage property on all DisplayObject instances, which points to the Stage that contains the instance. As such, by default you can access your FLA's root timeline from a nested MovieClip using this.stage.getChildAt(0).

    568 | 569 |

    You can also append global variables to the window object to make them accessible anywhere. This is generally frowned on in JS for the same reasons as using global or root in AS3 (scalability and polluting the global space), but should be fine for most ad development scenarios.

    570 | 571 |
    572 | // on the root timeline:
    573 | window.root = this; // create a global reference
    574 | // in another MovieClip's frame action:
    575 | root.doSomething(); // can use the global variable without a scope
    576 | 
    577 | 578 |

    Events

    579 | 580 |

    The event model in CreateJS is similar to AS3's but has a few variations you should be aware of. Firstly, there are no onevent handlers. For example you can't use:

    581 | 582 |
    583 | myBtn.onClick = function(){...};
    584 | 
    585 | 586 |

    Instead you can use addEventListener() or on(). The former is very similar to addEventListener() in AS3, and nearly identical to its namesake in JS.

    587 | 588 |
    589 | // named function:
    590 | myBtn.addEventListener("click", handleClick);
    591 | // anonymous function:
    592 | myBtn.addEventListener("click", function() { … });
    593 | 
    594 | 595 |

    As in vanilla JS, these callbacks are not scoped, so in the examples above, "this" will not point to the local scope. You must either use bind() or create a scope in the activation object.

    596 | 597 |
    598 | // bind:
    599 | myBtn.addEventListener("click", handleClick.bind(this));
    600 | // activation object:
    601 | var _this = this;
    602 | myBtn.addEventListener("click", function() { _this.doStuff(); });
    603 | 
    604 | 605 |

    The on() method provides an easy way to scope your methods (and offers some other handy features). By default, on() sets the scope to the dispatching object, but you can include a third parameter to specify your own scope.

    606 | 607 |
    608 | // will execute in myBtn:
    609 | myBtn.on("click", function() {...});
    610 | // will execute in the local scope:
    611 | myBtn.on("click", function() {...}), this);
    612 | // also works with named functions:
    613 | myBtn.on("click", handleClick, this);
    614 | 
    615 | 616 |

    It's important to note that this scoping works by wrapping your handler in an anonymous function and subscribing it as the listener. This listener is returned by on() and must be used if you want to remove the listener later. There is also an off() method which is just a shortcut to removeEventListener().

    617 | 618 |
    619 | var listener = myBtn.on("click", handleClick);
    620 | // this won't work:
    621 | myBtn.off("click", handleClick);
    622 | // because the actual listener, is the one returned by on():
    623 | myBtn.off("click", listener);
    624 | 
    625 | 626 |

    The on() method also provides the ability to create single use event listeners, and to pass data to the listener.

    627 | 628 |
    629 | // this event listener will automatically unsubscribe after it runs:
    630 | myBtn.on("click", handleClick, this, true, "some data");
    631 | function handleClick(evt, data) {
    632 | 	console.log(data); // "some data"
    633 | }
    634 | 
    635 | 636 |

    Mouse Interactions

    637 | 638 |

    EaselJS display objects dispatch most of the mouse events you would expect coming from AS3, including click, dblclick, and mousedown. To save costs when they are unneeded, you must explicitly enable mouseover, mouseout, rollover, and rollout events, via:

    639 | 640 |
    641 |  myStage.enableMouseOver()
    642 | 
    643 | 644 |

    This also enables support for the cursor property, and is included automatically in the HTML generated by Flash Pro if a button is included.

    645 | 646 |

    Similarly, untargeted mouse events such as mousemove and mouseup are not dispatched to every display object on stage to reduce unnecessary overhead. Instead, you can subscribe to stage level events stagemousemove and stagemouseup. The following shows a simple mouse follow behavior: 647 |

    648 | 649 |
    650 | this.stage.on("stagemousemove", moveTarget, this);
    651 | function moveTarget(evt){
    652 | 	var t = this.myTarget;
    653 | 	t.x = evt.stageX;
    654 | 	t.y = evt.stageY;
    655 | };
    656 | 
    657 | 658 |

    EaselJS also dispatches two events that make implementing drag interactions really simple. The pressmove event fires whenever the mouse moves after a press occurs on the target object. The pressup event is fired when the mouse is released after a press on the target, even if the mouse is no longer over the target (and in most browsers, even if it's outside the window). A drag interaction looks like this:

    659 | 660 |
    661 | this.foo.on("pressmove", function(evt) {
    662 | 	this.foo.x = evt.localX;
    663 | 	this.foo.y = evt.localY;
    664 | }, this);
    665 | this.foo.on("pressup", function(evt) {
    666 | 	console.log("final position:", this.foo.x, this.foo.y);
    667 | }, this);
    668 | 
    669 | 670 |

    When targeting touch-based devices, you should generally enable touch interactions. EaselJS will listen for touch events from both the touch and pointer JS APIs, and translate them into mouse events. This has no effect on devices without touch.

    671 | 672 |
    673 | createjs.Touch.enable(myStage);
    674 | 
    675 | 676 |

    Cursor

    677 | 678 |

    It is an ad-creation best practice to display a pointer icon anytime the user has moused over a clickable design element. This functionality is enabled by default on Button symbols (or when using ButtonHelper), but must be manually enabled on other clickable elements as follows:

    679 | 680 |
    681 | this.childMC.cursor = "pointer";
    682 | 
    683 | // and mouseover must be enabled for your stage (just once):
    684 | myStage.enableMouseOver();
    685 | 
    686 | 687 |

    DisplayObject Properties

    688 | 689 |

    Published movieclip symbols expose methods to control their timelines and properties to adjust their settings, similarly to AS3. Here are some common examples:

    690 | 691 |

    --- code 692 | mc.gotoAndPlay("yourFrameLabelName"); 693 | mc.gotoAndStop(10); 694 | mc.stop(); 695 | mc.play(); 696 | mc.scaleX = 1; 697 | mc.scaleY = .5; 698 | mc.x = 0; 699 | mc.y = 150; 700 | mc.alpha = .75; 701 | mc.visible = false;

    702 | 703 |

    Programmatic Animations

    704 | 705 |

    You can use tweening engines such as TweenJS, or GSAP TweenLite to create new animations (TweenJS powers the timeline animations published from Flash Pro), but it's also easy to write custom animation using the tick event, which is analogous to enterframe in AS3, and dispatched from all display objects within the display list each time the stage is updated, immediately before it redraws.

    706 | 707 |
    708 | this.on("tick", function() {
    709 | 	this.x ++; // move right each tick
    710 | });
    711 | 
    712 | 713 |

    You can also subscribe to the global tick event dispatched from Ticker.

    714 | 715 |
    716 | createjs.Ticker.on("tick", function() {
    717 | 	console.log("tick!");
    718 | });
    719 | 
    720 | 721 |

    The stage must have update() called each tick in order to propagate the tick event to child display objects and to redraw. By default, Flash Pro subscribes the stage as a listener to Ticker's tick event, which covers this requirement, but you may want to remove this and call your own tick handler in order to run logic before the update. It's very important to call stage.update() and pass the tick event object to it (this is needed for time syncing in EaselJS).

    722 | 723 |
    724 | createjs.Ticker.on("tick", handleTick);
    725 | function handleTick(evt) {
    726 | 	// do stuff
    727 | 	myStage.update(evt);
    728 | }
    729 | 
    730 | 731 |

    Setting the frequency of these events can be done as follows, which effectively sets the framerate of your ad. 732 |

    733 | 734 |
    735 | //the following are equivalent, 1000ms / 40fps = 25ms
    736 | createjs.Ticker.interval = 25;
    737 | createjs.Ticker.framerate = 40;
    738 | 
    739 | 740 |

    Frame Numbers & Labels

    741 | 742 |

    EaselJS uses zero-based frame numbering rather than Flash's (unusual) one-based indexing. This can cause confusion as it (currently) requires you to subtract 1 from the indexes displayed in Flash Pro.

    743 | 744 |

    To avoid this confusion, it is suggested that you label your animation frames with frame labels, and reference those in your code rather than numbers.

    745 | 746 |
    747 | this.childMC.gotoAndPlay(0); // first frame, may be confusing
    748 | this.childMC.gotoAndPlay("start"); // less ambiguous, and easier to update
    749 | 
    750 | 751 |

    752 | 753 |

    Links

    754 | 755 |

    Successfully navigating to a clickthrough URL can be achieved in a number of ways, however the following method is the closest to what was previously done in ActionScript and should function properly in all browser scenarios:

    756 | 757 |
    758 | this.myBtn.on("click", function(evt){
    759 | 	window.open("URL", "_blank");
    760 | });
    761 | 
    762 | 763 |

    Note that you need to be careful where this code is placed. If it is on a frame in a looping MovieClip, it will be called repeatedly, and set up multiple listeners for the click. Ensure it only runs once, either by placing the code on a frame that won't loop, or by setting an initialization variable.

    764 | 765 |
    766 | if (!this.inited) {
    767 | 	this.myBtn.on("click", ... );
    768 | 	this.inited = true;
    769 | }
    770 | 
    771 | 772 |

    Flash Pro Publish Settings

    773 | 774 |

    There are several Publish Settings available within Flash Pro that are very important to understand and configure properly.

    775 | 776 |

    Overwrite Images

    777 | 778 |

    Under the "Asset Export Options" publish setting in Flash Pro CC, you can uncheck "Images", so that Flash Pro will no longer replace your images with each republish. This allows you to replace images with optimized versions. Just remember that if you add new images to the FLA, they will not be exported until you re-enable this option.

    779 | 780 |

    Overwrite HTML

    781 | 782 |

    Under the "Output File" options you can uncheck this setting, and the contents of the HTML file will not be overwritten on subsequent publishes. This can be useful since you'll need to customize the HTML file for tracking implementation, meta tags, CSS, backup image logic, linking to externally referenced JavaScript helper files and libraries, etc.

    783 | 784 |

    Alternatively, you can duplicate the HTML file and modify the copy. You can then inject a line of code into the first frame of your main timeline to load the copy automatically. This is ideal when working with a developer, since it allows the developer to provide a deploy HTML file to test with. Ensure you remove the redirect for deployment.

    785 | 786 |
    787 | // redirect to deploy.html if we aren't already there:
    788 | if (window.location.pathname.indexOf("deploy.html") == -1) {
    789 | window.location = "./deploy.html";
    790 | }
    791 | 
    792 | 793 |

    Export All Bitmaps As Sprite Sheets

    794 | 795 |

    By checking this setting under "Asset Export Options/Images" Flash Pro CC will automatically combine all of the utilized images within your Flash library into a single, PNG32 sprite sheet along with a JSON file defining all of the coordinates of the separate image regions that comprise the sprite sheet.

    796 | 797 |

    This is a significant time-saver, versus the manual process previously required. It is important to test and evaluate the outputted sprite sheet when using this new and evolving feature. Because Flash is outputting the sprite sheet to a single PNG32 sprite sheet, server requests are successfully reduced, however the overall file size is increased when compared to leveraging separate sprite sheets for PNG32 and JPEG image assets. Because of this, you should definitely compress the sprite sheet with ImageOptim or a comparable image optimization tool in order to maximize the file size compression.

    798 | 799 |


    800 | 801 |

    Appendix: Document History

    802 | 803 |

    October 5, 2015

    804 | 805 |

    Initial release.

    806 | 807 |

    October 26, 2015

    808 | 809 |

    Minor edits, and changes to reflect AdHelper updates.

    810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 |
    822 | 823 | --------------------------------------------------------------------------------