| // Copyright 2009 The Closure Library Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS-IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| /** |
| * @fileoverview Wrapper on a Flash object embedded in the HTML page. |
| * This class contains routines for writing the HTML to create the Flash object |
| * using a goog.ui.Component approach. Tested on Firefox 1.5, 2 and 3, IE6, 7, |
| * Konqueror, Chrome and Safari. |
| * |
| * Based on http://go/flashobject.js |
| * |
| * Based on the following compatibility test suite: |
| * http://www.bobbyvandersluis.com/flashembed/testsuite/ |
| * |
| * TODO(user): take a look at swfobject, and maybe use it instead of the current |
| * flash embedding method. |
| * |
| * Examples of usage: |
| * |
| * <pre> |
| * var url = goog.html.TrustedResourceUrl.fromConstant( |
| * goog.string.Const.from('https://hostname/flash.swf')) |
| * var flash = new goog.ui.media.FlashObject(url); |
| * flash.setFlashVar('myvar', 'foo'); |
| * flash.render(goog.dom.getElement('parent')); |
| * </pre> |
| * |
| * TODO(user, jessan): create a goog.ui.media.BrowserInterfaceFlashObject that |
| * subclasses goog.ui.media.FlashObject to provide all the goodness of |
| * http://go/browserinterface.as |
| * |
| */ |
| |
| goog.provide('goog.ui.media.FlashObject'); |
| goog.provide('goog.ui.media.FlashObject.ScriptAccessLevel'); |
| goog.provide('goog.ui.media.FlashObject.Wmodes'); |
| |
| goog.require('goog.asserts'); |
| goog.require('goog.dom.safe'); |
| goog.require('goog.events.Event'); |
| goog.require('goog.events.EventHandler'); |
| goog.require('goog.events.EventType'); |
| goog.require('goog.html.SafeUrl'); |
| goog.require('goog.html.TrustedResourceUrl'); |
| goog.require('goog.html.flash'); |
| goog.require('goog.html.legacyconversions'); |
| goog.require('goog.log'); |
| goog.require('goog.object'); |
| goog.require('goog.string'); |
| goog.require('goog.structs.Map'); |
| goog.require('goog.style'); |
| goog.require('goog.ui.Component'); |
| goog.require('goog.userAgent'); |
| goog.require('goog.userAgent.flash'); |
| |
| |
| |
| /** |
| * A very simple flash wrapper, that allows you to create flash object |
| * programmatically, instead of embedding your own HTML. It extends |
| * {@link goog.ui.Component}, which makes it very easy to be embedded on the |
| * page. |
| * |
| * @param {string|!goog.html.TrustedResourceUrl} flashUrl The Flash SWF URL. |
| * If possible pass a TrustedResourceUrl. string is supported |
| * for backwards-compatibility only, uses goog.html.legacyconversions, |
| * and will be sanitized with goog.html.SafeUrl.sanitize() before being |
| * used. |
| * @param {goog.dom.DomHelper=} opt_domHelper An optional DomHelper. |
| * @extends {goog.ui.Component} |
| * @constructor |
| */ |
| goog.ui.media.FlashObject = function(flashUrl, opt_domHelper) { |
| goog.ui.Component.call(this, opt_domHelper); |
| |
| var trustedResourceUrl; |
| if (flashUrl instanceof goog.html.TrustedResourceUrl) { |
| trustedResourceUrl = flashUrl; |
| } else { |
| var flashUrlSanitized = |
| goog.html.SafeUrl.unwrap(goog.html.SafeUrl.sanitize(flashUrl)); |
| trustedResourceUrl = goog.html.legacyconversions |
| .trustedResourceUrlFromString(flashUrlSanitized); |
| } |
| |
| /** |
| * The URL of the flash movie to be embedded. |
| * |
| * @type {!goog.html.TrustedResourceUrl} |
| * @private |
| */ |
| this.flashUrl_ = trustedResourceUrl; |
| |
| /** |
| * An event handler used to handle events consistently between browsers. |
| * @type {goog.events.EventHandler<!goog.ui.media.FlashObject>} |
| * @private |
| */ |
| this.eventHandler_ = new goog.events.EventHandler(this); |
| |
| /** |
| * A map of variables to be passed to the flash movie. |
| * |
| * @type {goog.structs.Map} |
| * @private |
| */ |
| this.flashVars_ = new goog.structs.Map(); |
| }; |
| goog.inherits(goog.ui.media.FlashObject, goog.ui.Component); |
| |
| |
| /** |
| * Different states of loaded-ness in which the SWF itself can be |
| * |
| * Talked about at: |
| * http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_12059&sliceId=1 |
| * |
| * @enum {number} |
| * @private |
| */ |
| goog.ui.media.FlashObject.SwfReadyStates_ = { |
| LOADING: 0, |
| UNINITIALIZED: 1, |
| LOADED: 2, |
| INTERACTIVE: 3, |
| COMPLETE: 4 |
| }; |
| |
| |
| /** |
| * The different modes for displaying a SWF. Note that different wmodes |
| * can result in different bugs in different browsers and also that |
| * both OPAQUE and TRANSPARENT will result in a performance hit. |
| * |
| * @enum {string} |
| */ |
| goog.ui.media.FlashObject.Wmodes = { |
| /** |
| * Allows for z-ordering of the SWF. |
| */ |
| OPAQUE: 'opaque', |
| |
| /** |
| * Allows for z-ordering of the SWF and plays the SWF with a transparent BG. |
| */ |
| TRANSPARENT: 'transparent', |
| |
| /** |
| * The default wmode. Does not allow for z-ordering of the SWF. |
| */ |
| WINDOW: 'window' |
| }; |
| |
| |
| /** |
| * The different levels of allowScriptAccess. |
| * |
| * Talked about at: |
| * http://kb2.adobe.com/cps/164/tn_16494.html |
| * |
| * @enum {string} |
| */ |
| goog.ui.media.FlashObject.ScriptAccessLevel = { |
| /* |
| * The flash object can always communicate with its container page. |
| */ |
| ALWAYS: 'always', |
| |
| /* |
| * The flash object can only communicate with its container page if they are |
| * hosted in the same domain. |
| */ |
| SAME_DOMAIN: 'sameDomain', |
| |
| /* |
| * The flash can not communicate with its container page. |
| */ |
| NEVER: 'never' |
| }; |
| |
| |
| /** |
| * The component CSS namespace. |
| * |
| * @type {string} |
| */ |
| goog.ui.media.FlashObject.CSS_CLASS = goog.getCssName('goog-ui-media-flash'); |
| |
| |
| /** |
| * The flash object CSS class. |
| * |
| * @type {string} |
| */ |
| goog.ui.media.FlashObject.FLASH_CSS_CLASS = |
| goog.getCssName('goog-ui-media-flash-object'); |
| |
| |
| /** |
| * A logger used for debugging. |
| * |
| * @type {goog.log.Logger} |
| * @private |
| */ |
| goog.ui.media.FlashObject.prototype.logger_ = |
| goog.log.getLogger('goog.ui.media.FlashObject'); |
| |
| |
| /** |
| * The wmode for the SWF. |
| * |
| * @type {goog.ui.media.FlashObject.Wmodes} |
| * @private |
| */ |
| goog.ui.media.FlashObject.prototype.wmode_ = |
| goog.ui.media.FlashObject.Wmodes.WINDOW; |
| |
| |
| /** |
| * The minimum required flash version. |
| * |
| * @type {?string} |
| * @private |
| */ |
| goog.ui.media.FlashObject.prototype.requiredVersion_; |
| |
| |
| /** |
| * The flash movie width. |
| * |
| * @type {string} |
| * @private |
| */ |
| goog.ui.media.FlashObject.prototype.width_; |
| |
| |
| /** |
| * The flash movie height. |
| * |
| * @type {string} |
| * @private |
| */ |
| goog.ui.media.FlashObject.prototype.height_; |
| |
| |
| /** |
| * The flash movie background color. |
| * |
| * @type {string} |
| * @private |
| */ |
| goog.ui.media.FlashObject.prototype.backgroundColor_ = '#000000'; |
| |
| |
| /** |
| * The flash movie allowScriptAccess setting. |
| * |
| * @type {string} |
| * @private |
| */ |
| goog.ui.media.FlashObject.prototype.allowScriptAccess_ = |
| goog.ui.media.FlashObject.ScriptAccessLevel.SAME_DOMAIN; |
| |
| |
| /** |
| * Sets the flash movie Wmode. |
| * |
| * @param {goog.ui.media.FlashObject.Wmodes} wmode the flash movie Wmode. |
| * @return {!goog.ui.media.FlashObject} The flash object instance for chaining. |
| */ |
| goog.ui.media.FlashObject.prototype.setWmode = function(wmode) { |
| this.wmode_ = wmode; |
| return this; |
| }; |
| |
| |
| /** |
| * @return {string} Returns the flash movie wmode. |
| */ |
| goog.ui.media.FlashObject.prototype.getWmode = function() { |
| return this.wmode_; |
| }; |
| |
| |
| /** |
| * Adds flash variables. |
| * |
| * @param {goog.structs.Map|Object} map A key-value map of variables. |
| * @return {!goog.ui.media.FlashObject} The flash object instance for chaining. |
| */ |
| goog.ui.media.FlashObject.prototype.addFlashVars = function(map) { |
| this.flashVars_.addAll(map); |
| return this; |
| }; |
| |
| |
| /** |
| * Sets a flash variable. |
| * |
| * @param {string} key The name of the flash variable. |
| * @param {string} value The value of the flash variable. |
| * @return {!goog.ui.media.FlashObject} The flash object instance for chaining. |
| */ |
| goog.ui.media.FlashObject.prototype.setFlashVar = function(key, value) { |
| this.flashVars_.set(key, value); |
| return this; |
| }; |
| |
| |
| /** |
| * Sets flash variables. You can either pass a Map of key->value pairs or you |
| * can pass a key, value pair to set a specific variable. |
| * |
| * TODO(user, martino): Get rid of this method. |
| * |
| * @deprecated Use {@link #addFlashVars} or {@link #setFlashVar} instead. |
| * @param {goog.structs.Map|Object|string} flashVar A map of variables (given |
| * as a goog.structs.Map or an Object literal) or a key to the optional |
| * {@code opt_value}. |
| * @param {string=} opt_value The optional value for the flashVar key. |
| * @return {!goog.ui.media.FlashObject} The flash object instance for chaining. |
| */ |
| goog.ui.media.FlashObject.prototype.setFlashVars = function(flashVar, |
| opt_value) { |
| if (flashVar instanceof goog.structs.Map || |
| goog.typeOf(flashVar) == 'object') { |
| this.addFlashVars(/**@type {!goog.structs.Map|!Object}*/(flashVar)); |
| } else { |
| goog.asserts.assert(goog.isString(flashVar) && goog.isDef(opt_value), |
| 'Invalid argument(s)'); |
| this.setFlashVar(/**@type {string}*/(flashVar), |
| /**@type {string}*/(opt_value)); |
| } |
| return this; |
| }; |
| |
| |
| /** |
| * @return {goog.structs.Map} The current flash variables. |
| */ |
| goog.ui.media.FlashObject.prototype.getFlashVars = function() { |
| return this.flashVars_; |
| }; |
| |
| |
| /** |
| * Sets the background color of the movie. |
| * |
| * @param {string} color The new color to be set. |
| * @return {!goog.ui.media.FlashObject} The flash object instance for chaining. |
| */ |
| goog.ui.media.FlashObject.prototype.setBackgroundColor = function(color) { |
| this.backgroundColor_ = color; |
| return this; |
| }; |
| |
| |
| /** |
| * @return {string} The background color of the movie. |
| */ |
| goog.ui.media.FlashObject.prototype.getBackgroundColor = function() { |
| return this.backgroundColor_; |
| }; |
| |
| |
| /** |
| * Sets the allowScriptAccess setting of the movie. |
| * |
| * @param {string} value The new value to be set. |
| * @return {!goog.ui.media.FlashObject} The flash object instance for chaining. |
| */ |
| goog.ui.media.FlashObject.prototype.setAllowScriptAccess = function(value) { |
| this.allowScriptAccess_ = value; |
| return this; |
| }; |
| |
| |
| /** |
| * @return {string} The allowScriptAccess setting color of the movie. |
| */ |
| goog.ui.media.FlashObject.prototype.getAllowScriptAccess = function() { |
| return this.allowScriptAccess_; |
| }; |
| |
| |
| /** |
| * Sets the width and height of the movie. |
| * |
| * @param {number|string} width The width of the movie. |
| * @param {number|string} height The height of the movie. |
| * @return {!goog.ui.media.FlashObject} The flash object instance for chaining. |
| */ |
| goog.ui.media.FlashObject.prototype.setSize = function(width, height) { |
| this.width_ = goog.isString(width) ? width : Math.round(width) + 'px'; |
| this.height_ = goog.isString(height) ? height : Math.round(height) + 'px'; |
| if (this.getElement()) { |
| goog.style.setSize(this.getFlashElement(), this.width_, this.height_); |
| } |
| return this; |
| }; |
| |
| |
| /** |
| * @return {?string} The flash required version. |
| */ |
| goog.ui.media.FlashObject.prototype.getRequiredVersion = function() { |
| return this.requiredVersion_; |
| }; |
| |
| |
| /** |
| * Sets the minimum flash required version. |
| * |
| * @param {?string} version The minimum required version for this movie to work, |
| * or null if you want to unset it. |
| * @return {!goog.ui.media.FlashObject} The flash object instance for chaining. |
| */ |
| goog.ui.media.FlashObject.prototype.setRequiredVersion = function(version) { |
| this.requiredVersion_ = version; |
| return this; |
| }; |
| |
| |
| /** |
| * Returns whether this SWF has a minimum required flash version. |
| * |
| * @return {boolean} Whether a required version was set or not. |
| */ |
| goog.ui.media.FlashObject.prototype.hasRequiredVersion = function() { |
| return this.requiredVersion_ != null; |
| }; |
| |
| |
| /** |
| * Writes the Flash embedding {@code HTMLObjectElement} to this components root |
| * element and adds listeners for all events to handle them consistently. |
| * @override |
| */ |
| goog.ui.media.FlashObject.prototype.enterDocument = function() { |
| goog.ui.media.FlashObject.superClass_.enterDocument.call(this); |
| |
| // The SWF tag must be written after this component's element is appended to |
| // the DOM. Otherwise Flash's ExternalInterface is broken in IE. |
| goog.dom.safe.setInnerHtml( |
| /** @type {!Element} */ (this.getElement()), this.createSwfTag_()); |
| if (this.width_ && this.height_) { |
| this.setSize(this.width_, this.height_); |
| } |
| |
| // Sinks all the events on the bubble phase. |
| // |
| // Flash plugins propagates events from/to the plugin to the browser |
| // inconsistently: |
| // |
| // 1) FF2 + linux: the flash plugin will stop the propagation of all events |
| // from the plugin to the browser. |
| // 2) FF3 + mac: the flash plugin will propagate events on the <embed> object |
| // but that will get propagated to its parents. |
| // 3) Safari 3.1.1 + mac: the flash plugin will propagate the event to the |
| // <object> tag that event will propagate to its parents. |
| // 4) IE7 + windows: the flash plugin will eat all events, not propagating |
| // anything to the javascript. |
| // 5) Chrome + windows: the flash plugin will eat all events, not propagating |
| // anything to the javascript. |
| // |
| // To overcome this inconsistency, all events from/to the plugin are sinked, |
| // since you can't assume that the events will be propagated. |
| // |
| // NOTE(user): we only sink events on the bubbling phase, since there are no |
| // inexpensive/scalable way to stop events on the capturing phase unless we |
| // added an event listener on the document for each flash object. |
| this.eventHandler_.listen( |
| this.getElement(), |
| goog.object.getValues(goog.events.EventType), |
| goog.events.Event.stopPropagation); |
| }; |
| |
| |
| /** |
| * Creates the DOM structure. |
| * |
| * @override |
| */ |
| goog.ui.media.FlashObject.prototype.createDom = function() { |
| if (this.hasRequiredVersion() && |
| !goog.userAgent.flash.isVersion( |
| /** @type {string} */ (this.getRequiredVersion()))) { |
| goog.log.warning(this.logger_, 'Required flash version not found:' + |
| this.getRequiredVersion()); |
| throw Error(goog.ui.Component.Error.NOT_SUPPORTED); |
| } |
| |
| var element = this.getDomHelper().createElement('div'); |
| element.className = goog.ui.media.FlashObject.CSS_CLASS; |
| this.setElementInternal(element); |
| }; |
| |
| |
| /** |
| * Creates the HTML to embed the flash object. |
| * |
| * @return {!goog.html.SafeHtml} Browser appropriate HTML to add the SWF to the |
| * DOM. |
| * @private |
| */ |
| goog.ui.media.FlashObject.prototype.createSwfTag_ = function() { |
| var keys = this.flashVars_.getKeys(); |
| var values = this.flashVars_.getValues(); |
| var flashVars = []; |
| for (var i = 0; i < keys.length; i++) { |
| var key = goog.string.urlEncode(keys[i]); |
| var value = goog.string.urlEncode(values[i]); |
| flashVars.push(key + '=' + value); |
| } |
| var flashVarsString = flashVars.join('&'); |
| if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(11)) { |
| return this.createSwfTagOldIe_(flashVarsString); |
| } else { |
| return this.createSwfTagModern_(flashVarsString); |
| } |
| }; |
| |
| |
| /** |
| * Creates the HTML to embed the flash object for IE>=11 and other browsers. |
| * |
| * @param {string} flashVars The value of the FlashVars attribute. |
| * @return {!goog.html.SafeHtml} Browser appropriate HTML to add the SWF to the |
| * DOM. |
| * @private |
| */ |
| goog.ui.media.FlashObject.prototype.createSwfTagModern_ = function(flashVars) { |
| return goog.html.flash.createEmbed( |
| this.flashUrl_, |
| { |
| 'AllowScriptAccess': this.allowScriptAccess_, |
| 'allowFullScreen': 'true', |
| 'allowNetworking': 'all', |
| 'bgcolor': this.backgroundColor_, |
| 'class': goog.ui.media.FlashObject.FLASH_CSS_CLASS, |
| 'FlashVars': flashVars, |
| 'id': this.getId(), |
| 'name': this.getId(), |
| 'quality': 'high', |
| 'SeamlessTabbing': 'false', |
| 'wmode': this.wmode_ |
| }); |
| }; |
| |
| |
| /** |
| * Creates the HTML to embed the flash object for IE<11. |
| * |
| * @param {string} flashVars The value of the FlashVars attribute. |
| * @return {!goog.html.SafeHtml} Browser appropriate HTML to add the SWF to the |
| * DOM. |
| * @private |
| */ |
| goog.ui.media.FlashObject.prototype.createSwfTagOldIe_ = function(flashVars) { |
| return goog.html.flash.createObjectForOldIe( |
| this.flashUrl_, |
| { |
| 'allowFullScreen': 'true', |
| 'AllowScriptAccess': this.allowScriptAccess_, |
| 'allowNetworking': 'all', |
| 'bgcolor': this.backgroundColor_, |
| 'FlashVars': flashVars, |
| 'quality': 'high', |
| 'SeamlessTabbing': 'false', |
| 'wmode': this.wmode_ |
| }, |
| { |
| 'class': goog.ui.media.FlashObject.FLASH_CSS_CLASS, |
| 'id': this.getId(), |
| 'name': this.getId() |
| }); |
| }; |
| |
| |
| /** |
| * @return {HTMLObjectElement} The flash element or null if the element can't |
| * be found. |
| */ |
| goog.ui.media.FlashObject.prototype.getFlashElement = function() { |
| return /** @type {HTMLObjectElement} */(this.getElement() ? |
| this.getElement().firstChild : null); |
| }; |
| |
| |
| /** @override */ |
| goog.ui.media.FlashObject.prototype.disposeInternal = function() { |
| goog.ui.media.FlashObject.superClass_.disposeInternal.call(this); |
| this.flashVars_ = null; |
| |
| this.eventHandler_.dispose(); |
| this.eventHandler_ = null; |
| }; |
| |
| |
| /** |
| * @return {boolean} whether the SWF has finished loading or not. |
| */ |
| goog.ui.media.FlashObject.prototype.isLoaded = function() { |
| if (!this.isInDocument() || !this.getElement()) { |
| return false; |
| } |
| |
| if (this.getFlashElement().readyState && |
| this.getFlashElement().readyState == |
| goog.ui.media.FlashObject.SwfReadyStates_.COMPLETE) { |
| return true; |
| } |
| |
| if (this.getFlashElement().PercentLoaded && |
| this.getFlashElement().PercentLoaded() == 100) { |
| return true; |
| } |
| |
| return false; |
| }; |