flashobject.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. // Copyright 2009 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Wrapper on a Flash object embedded in the HTML page.
  16. * This class contains routines for writing the HTML to create the Flash object
  17. * using a goog.ui.Component approach. Tested on Firefox 1.5, 2 and 3, IE6, 7,
  18. * Konqueror, Chrome and Safari.
  19. *
  20. * Based on http://go/flashobject.js
  21. *
  22. * Based on the following compatibility test suite:
  23. * http://www.bobbyvandersluis.com/flashembed/testsuite/
  24. *
  25. * TODO(user): take a look at swfobject, and maybe use it instead of the current
  26. * flash embedding method.
  27. *
  28. * Examples of usage:
  29. *
  30. * <pre>
  31. * var url = goog.html.TrustedResourceUrl.fromConstant(
  32. * goog.string.Const.from('https://hostname/flash.swf'))
  33. * var flash = new goog.ui.media.FlashObject(url);
  34. * flash.setFlashVar('myvar', 'foo');
  35. * flash.render(goog.dom.getElement('parent'));
  36. * </pre>
  37. *
  38. * TODO(user, jessan): create a goog.ui.media.BrowserInterfaceFlashObject that
  39. * subclasses goog.ui.media.FlashObject to provide all the goodness of
  40. * http://go/browserinterface.as
  41. *
  42. */
  43. goog.provide('goog.ui.media.FlashObject');
  44. goog.provide('goog.ui.media.FlashObject.ScriptAccessLevel');
  45. goog.provide('goog.ui.media.FlashObject.Wmodes');
  46. goog.require('goog.asserts');
  47. goog.require('goog.dom.TagName');
  48. goog.require('goog.dom.safe');
  49. goog.require('goog.events.Event');
  50. goog.require('goog.events.EventHandler');
  51. goog.require('goog.events.EventType');
  52. goog.require('goog.html.TrustedResourceUrl');
  53. goog.require('goog.html.flash');
  54. goog.require('goog.log');
  55. goog.require('goog.object');
  56. goog.require('goog.string');
  57. goog.require('goog.structs.Map');
  58. goog.require('goog.style');
  59. goog.require('goog.ui.Component');
  60. goog.require('goog.userAgent');
  61. goog.require('goog.userAgent.flash');
  62. /**
  63. * A very simple flash wrapper, that allows you to create flash object
  64. * programmatically, instead of embedding your own HTML. It extends
  65. * {@link goog.ui.Component}, which makes it very easy to be embedded on the
  66. * page.
  67. *
  68. * @param {!goog.html.TrustedResourceUrl} flashUrl The Flash SWF URL.
  69. * @param {goog.dom.DomHelper=} opt_domHelper An optional DomHelper.
  70. * @extends {goog.ui.Component}
  71. * @constructor
  72. */
  73. goog.ui.media.FlashObject = function(flashUrl, opt_domHelper) {
  74. goog.ui.Component.call(this, opt_domHelper);
  75. /**
  76. * The URL of the flash movie to be embedded.
  77. *
  78. * @type {!goog.html.TrustedResourceUrl}
  79. * @private
  80. */
  81. this.flashUrl_ = flashUrl;
  82. /**
  83. * An event handler used to handle events consistently between browsers.
  84. * @type {goog.events.EventHandler<!goog.ui.media.FlashObject>}
  85. * @private
  86. */
  87. this.eventHandler_ = new goog.events.EventHandler(this);
  88. /**
  89. * A map of variables to be passed to the flash movie.
  90. *
  91. * @type {goog.structs.Map}
  92. * @private
  93. */
  94. this.flashVars_ = new goog.structs.Map();
  95. };
  96. goog.inherits(goog.ui.media.FlashObject, goog.ui.Component);
  97. /**
  98. * Different states of loaded-ness in which the SWF itself can be
  99. *
  100. * Talked about at:
  101. * http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_12059&sliceId=1
  102. *
  103. * @enum {number}
  104. * @private
  105. */
  106. goog.ui.media.FlashObject.SwfReadyStates_ = {
  107. LOADING: 0,
  108. UNINITIALIZED: 1,
  109. LOADED: 2,
  110. INTERACTIVE: 3,
  111. COMPLETE: 4
  112. };
  113. /**
  114. * IE specific ready states.
  115. *
  116. * @see https://msdn.microsoft.com/en-us/library/ms534359(v=vs.85).aspx
  117. * @enum {string}
  118. * @private
  119. */
  120. goog.ui.media.FlashObject.IeSwfReadyStates_ = {
  121. LOADING: 'loading',
  122. UNINITIALIZED: 'uninitialized',
  123. LOADED: 'loaded',
  124. INTERACTIVE: 'interactive',
  125. COMPLETE: 'complete'
  126. };
  127. /**
  128. * The different modes for displaying a SWF. Note that different wmodes
  129. * can result in different bugs in different browsers and also that
  130. * both OPAQUE and TRANSPARENT will result in a performance hit.
  131. *
  132. * @enum {string}
  133. */
  134. goog.ui.media.FlashObject.Wmodes = {
  135. /**
  136. * Allows for z-ordering of the SWF.
  137. */
  138. OPAQUE: 'opaque',
  139. /**
  140. * Allows for z-ordering of the SWF and plays the SWF with a transparent BG.
  141. */
  142. TRANSPARENT: 'transparent',
  143. /**
  144. * The default wmode. Does not allow for z-ordering of the SWF.
  145. */
  146. WINDOW: 'window'
  147. };
  148. /**
  149. * The different levels of allowScriptAccess.
  150. *
  151. * Talked about at:
  152. * http://kb2.adobe.com/cps/164/tn_16494.html
  153. *
  154. * @enum {string}
  155. */
  156. goog.ui.media.FlashObject.ScriptAccessLevel = {
  157. /*
  158. * The flash object can always communicate with its container page.
  159. */
  160. ALWAYS: 'always',
  161. /*
  162. * The flash object can only communicate with its container page if they are
  163. * hosted in the same domain.
  164. */
  165. SAME_DOMAIN: 'sameDomain',
  166. /*
  167. * The flash can not communicate with its container page.
  168. */
  169. NEVER: 'never'
  170. };
  171. /**
  172. * The component CSS namespace.
  173. *
  174. * @type {string}
  175. */
  176. goog.ui.media.FlashObject.CSS_CLASS = goog.getCssName('goog-ui-media-flash');
  177. /**
  178. * The flash object CSS class.
  179. *
  180. * @type {string}
  181. */
  182. goog.ui.media.FlashObject.FLASH_CSS_CLASS =
  183. goog.getCssName('goog-ui-media-flash-object');
  184. /**
  185. * A logger used for debugging.
  186. *
  187. * @type {goog.log.Logger}
  188. * @private
  189. */
  190. goog.ui.media.FlashObject.prototype.logger_ =
  191. goog.log.getLogger('goog.ui.media.FlashObject');
  192. /**
  193. * The wmode for the SWF.
  194. *
  195. * @type {goog.ui.media.FlashObject.Wmodes}
  196. * @private
  197. */
  198. goog.ui.media.FlashObject.prototype.wmode_ =
  199. goog.ui.media.FlashObject.Wmodes.WINDOW;
  200. /**
  201. * The minimum required flash version.
  202. *
  203. * @type {?string}
  204. * @private
  205. */
  206. goog.ui.media.FlashObject.prototype.requiredVersion_;
  207. /**
  208. * The flash movie width.
  209. *
  210. * @type {string}
  211. * @private
  212. */
  213. goog.ui.media.FlashObject.prototype.width_;
  214. /**
  215. * The flash movie height.
  216. *
  217. * @type {string}
  218. * @private
  219. */
  220. goog.ui.media.FlashObject.prototype.height_;
  221. /**
  222. * The flash movie background color.
  223. *
  224. * @type {string}
  225. * @private
  226. */
  227. goog.ui.media.FlashObject.prototype.backgroundColor_ = '#000000';
  228. /**
  229. * The flash movie allowScriptAccess setting.
  230. *
  231. * @type {string}
  232. * @private
  233. */
  234. goog.ui.media.FlashObject.prototype.allowScriptAccess_ =
  235. goog.ui.media.FlashObject.ScriptAccessLevel.SAME_DOMAIN;
  236. /**
  237. * Sets the flash movie Wmode.
  238. *
  239. * @param {goog.ui.media.FlashObject.Wmodes} wmode the flash movie Wmode.
  240. * @return {!goog.ui.media.FlashObject} The flash object instance for chaining.
  241. */
  242. goog.ui.media.FlashObject.prototype.setWmode = function(wmode) {
  243. this.wmode_ = wmode;
  244. return this;
  245. };
  246. /**
  247. * @return {string} Returns the flash movie wmode.
  248. */
  249. goog.ui.media.FlashObject.prototype.getWmode = function() {
  250. return this.wmode_;
  251. };
  252. /**
  253. * Adds flash variables.
  254. *
  255. * @param {goog.structs.Map|Object} map A key-value map of variables.
  256. * @return {!goog.ui.media.FlashObject} The flash object instance for chaining.
  257. */
  258. goog.ui.media.FlashObject.prototype.addFlashVars = function(map) {
  259. this.flashVars_.addAll(map);
  260. return this;
  261. };
  262. /**
  263. * Sets a flash variable.
  264. *
  265. * @param {string} key The name of the flash variable.
  266. * @param {string} value The value of the flash variable.
  267. * @return {!goog.ui.media.FlashObject} The flash object instance for chaining.
  268. */
  269. goog.ui.media.FlashObject.prototype.setFlashVar = function(key, value) {
  270. this.flashVars_.set(key, value);
  271. return this;
  272. };
  273. /**
  274. * Sets flash variables. You can either pass a Map of key->value pairs or you
  275. * can pass a key, value pair to set a specific variable.
  276. *
  277. * TODO(user, martino): Get rid of this method.
  278. *
  279. * @deprecated Use {@link #addFlashVars} or {@link #setFlashVar} instead.
  280. * @param {goog.structs.Map|Object|string} flashVar A map of variables (given
  281. * as a goog.structs.Map or an Object literal) or a key to the optional
  282. * {@code opt_value}.
  283. * @param {string=} opt_value The optional value for the flashVar key.
  284. * @return {!goog.ui.media.FlashObject} The flash object instance for chaining.
  285. */
  286. goog.ui.media.FlashObject.prototype.setFlashVars = function(
  287. flashVar, opt_value) {
  288. if (flashVar instanceof goog.structs.Map ||
  289. goog.typeOf(flashVar) == 'object') {
  290. this.addFlashVars(/**@type {!goog.structs.Map|!Object}*/ (flashVar));
  291. } else {
  292. goog.asserts.assert(
  293. goog.isString(flashVar) && goog.isDef(opt_value),
  294. 'Invalid argument(s)');
  295. this.setFlashVar(
  296. /**@type {string}*/ (flashVar),
  297. /**@type {string}*/ (opt_value));
  298. }
  299. return this;
  300. };
  301. /**
  302. * @return {goog.structs.Map} The current flash variables.
  303. */
  304. goog.ui.media.FlashObject.prototype.getFlashVars = function() {
  305. return this.flashVars_;
  306. };
  307. /**
  308. * Sets the background color of the movie.
  309. *
  310. * @param {string} color The new color to be set.
  311. * @return {!goog.ui.media.FlashObject} The flash object instance for chaining.
  312. */
  313. goog.ui.media.FlashObject.prototype.setBackgroundColor = function(color) {
  314. this.backgroundColor_ = color;
  315. return this;
  316. };
  317. /**
  318. * @return {string} The background color of the movie.
  319. */
  320. goog.ui.media.FlashObject.prototype.getBackgroundColor = function() {
  321. return this.backgroundColor_;
  322. };
  323. /**
  324. * Sets the allowScriptAccess setting of the movie.
  325. *
  326. * @param {string} value The new value to be set.
  327. * @return {!goog.ui.media.FlashObject} The flash object instance for chaining.
  328. */
  329. goog.ui.media.FlashObject.prototype.setAllowScriptAccess = function(value) {
  330. this.allowScriptAccess_ = value;
  331. return this;
  332. };
  333. /**
  334. * @return {string} The allowScriptAccess setting color of the movie.
  335. */
  336. goog.ui.media.FlashObject.prototype.getAllowScriptAccess = function() {
  337. return this.allowScriptAccess_;
  338. };
  339. /**
  340. * Sets the width and height of the movie.
  341. *
  342. * @param {number|string} width The width of the movie.
  343. * @param {number|string} height The height of the movie.
  344. * @return {!goog.ui.media.FlashObject} The flash object instance for chaining.
  345. */
  346. goog.ui.media.FlashObject.prototype.setSize = function(width, height) {
  347. this.width_ = goog.isString(width) ? width : Math.round(width) + 'px';
  348. this.height_ = goog.isString(height) ? height : Math.round(height) + 'px';
  349. if (this.getElement()) {
  350. goog.style.setSize(this.getFlashElement(), this.width_, this.height_);
  351. }
  352. return this;
  353. };
  354. /**
  355. * @return {?string} The flash required version.
  356. */
  357. goog.ui.media.FlashObject.prototype.getRequiredVersion = function() {
  358. return this.requiredVersion_;
  359. };
  360. /**
  361. * Sets the minimum flash required version.
  362. *
  363. * @param {?string} version The minimum required version for this movie to work,
  364. * or null if you want to unset it.
  365. * @return {!goog.ui.media.FlashObject} The flash object instance for chaining.
  366. */
  367. goog.ui.media.FlashObject.prototype.setRequiredVersion = function(version) {
  368. this.requiredVersion_ = version;
  369. return this;
  370. };
  371. /**
  372. * Returns whether this SWF has a minimum required flash version.
  373. *
  374. * @return {boolean} Whether a required version was set or not.
  375. */
  376. goog.ui.media.FlashObject.prototype.hasRequiredVersion = function() {
  377. return this.requiredVersion_ != null;
  378. };
  379. /**
  380. * Writes the Flash embedding {@code HTMLObjectElement} to this components root
  381. * element and adds listeners for all events to handle them consistently.
  382. * @override
  383. */
  384. goog.ui.media.FlashObject.prototype.enterDocument = function() {
  385. goog.ui.media.FlashObject.superClass_.enterDocument.call(this);
  386. // The SWF tag must be written after this component's element is appended to
  387. // the DOM. Otherwise Flash's ExternalInterface is broken in IE.
  388. goog.dom.safe.setInnerHtml(
  389. /** @type {!Element} */ (this.getElement()), this.createSwfTag_());
  390. if (this.width_ && this.height_) {
  391. this.setSize(this.width_, this.height_);
  392. }
  393. // Sinks all the events on the bubble phase.
  394. //
  395. // Flash plugins propagates events from/to the plugin to the browser
  396. // inconsistently:
  397. //
  398. // 1) FF2 + linux: the flash plugin will stop the propagation of all events
  399. // from the plugin to the browser.
  400. // 2) FF3 + mac: the flash plugin will propagate events on the <embed> object
  401. // but that will get propagated to its parents.
  402. // 3) Safari 3.1.1 + mac: the flash plugin will propagate the event to the
  403. // <object> tag that event will propagate to its parents.
  404. // 4) IE7 + windows: the flash plugin will eat all events, not propagating
  405. // anything to the javascript.
  406. // 5) Chrome + windows: the flash plugin will eat all events, not propagating
  407. // anything to the javascript.
  408. //
  409. // To overcome this inconsistency, all events from/to the plugin are sinked,
  410. // since you can't assume that the events will be propagated.
  411. //
  412. // NOTE(user): we only sink events on the bubbling phase, since there are no
  413. // inexpensive/scalable way to stop events on the capturing phase unless we
  414. // added an event listener on the document for each flash object.
  415. this.eventHandler_.listen(
  416. this.getElement(), goog.object.getValues(goog.events.EventType),
  417. goog.events.Event.stopPropagation);
  418. };
  419. /**
  420. * Creates the DOM structure.
  421. *
  422. * @override
  423. */
  424. goog.ui.media.FlashObject.prototype.createDom = function() {
  425. if (this.hasRequiredVersion() &&
  426. !goog.userAgent.flash.isVersion(
  427. /** @type {string} */ (this.getRequiredVersion()))) {
  428. goog.log.warning(
  429. this.logger_,
  430. 'Required flash version not found:' + this.getRequiredVersion());
  431. throw Error(goog.ui.Component.Error.NOT_SUPPORTED);
  432. }
  433. var element = this.getDomHelper().createElement(goog.dom.TagName.DIV);
  434. element.className = goog.ui.media.FlashObject.CSS_CLASS;
  435. this.setElementInternal(element);
  436. };
  437. /**
  438. * Creates the HTML to embed the flash object.
  439. *
  440. * @return {!goog.html.SafeHtml} Browser appropriate HTML to add the SWF to the
  441. * DOM.
  442. * @private
  443. */
  444. goog.ui.media.FlashObject.prototype.createSwfTag_ = function() {
  445. var keys = this.flashVars_.getKeys();
  446. var values = this.flashVars_.getValues();
  447. var flashVars = [];
  448. for (var i = 0; i < keys.length; i++) {
  449. var key = goog.string.urlEncode(keys[i]);
  450. var value = goog.string.urlEncode(values[i]);
  451. flashVars.push(key + '=' + value);
  452. }
  453. var flashVarsString = flashVars.join('&');
  454. if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(11)) {
  455. return this.createSwfTagOldIe_(flashVarsString);
  456. } else {
  457. return this.createSwfTagModern_(flashVarsString);
  458. }
  459. };
  460. /**
  461. * Creates the HTML to embed the flash object for IE>=11 and other browsers.
  462. *
  463. * @param {string} flashVars The value of the FlashVars attribute.
  464. * @return {!goog.html.SafeHtml} Browser appropriate HTML to add the SWF to the
  465. * DOM.
  466. * @private
  467. */
  468. goog.ui.media.FlashObject.prototype.createSwfTagModern_ = function(flashVars) {
  469. return goog.html.flash.createEmbed(this.flashUrl_, {
  470. 'AllowScriptAccess': this.allowScriptAccess_,
  471. 'allowFullScreen': 'true',
  472. 'allowNetworking': 'all',
  473. 'bgcolor': this.backgroundColor_,
  474. 'class': goog.ui.media.FlashObject.FLASH_CSS_CLASS,
  475. 'FlashVars': flashVars,
  476. 'id': this.getId(),
  477. 'name': this.getId(),
  478. 'quality': 'high',
  479. 'SeamlessTabbing': 'false',
  480. 'wmode': this.wmode_
  481. });
  482. };
  483. /**
  484. * Creates the HTML to embed the flash object for IE<11.
  485. *
  486. * @param {string} flashVars The value of the FlashVars attribute.
  487. * @return {!goog.html.SafeHtml} Browser appropriate HTML to add the SWF to the
  488. * DOM.
  489. * @private
  490. */
  491. goog.ui.media.FlashObject.prototype.createSwfTagOldIe_ = function(flashVars) {
  492. return goog.html.flash.createObjectForOldIe(
  493. this.flashUrl_, {
  494. 'allowFullScreen': 'true',
  495. 'AllowScriptAccess': this.allowScriptAccess_,
  496. 'allowNetworking': 'all',
  497. 'bgcolor': this.backgroundColor_,
  498. 'FlashVars': flashVars,
  499. 'quality': 'high',
  500. 'SeamlessTabbing': 'false',
  501. 'wmode': this.wmode_
  502. },
  503. {
  504. 'class': goog.ui.media.FlashObject.FLASH_CSS_CLASS,
  505. 'id': this.getId(),
  506. 'name': this.getId()
  507. });
  508. };
  509. /**
  510. * @return {HTMLObjectElement} The flash element or null if the element can't
  511. * be found.
  512. */
  513. goog.ui.media.FlashObject.prototype.getFlashElement = function() {
  514. return /** @type {HTMLObjectElement} */ (
  515. this.getElement() ? this.getElement().firstChild : null);
  516. };
  517. /** @override */
  518. goog.ui.media.FlashObject.prototype.disposeInternal = function() {
  519. goog.ui.media.FlashObject.superClass_.disposeInternal.call(this);
  520. this.flashVars_ = null;
  521. this.eventHandler_.dispose();
  522. this.eventHandler_ = null;
  523. };
  524. /**
  525. * @return {boolean} whether the SWF has finished loading or not.
  526. */
  527. goog.ui.media.FlashObject.prototype.isLoaded = function() {
  528. if (!this.isInDocument() || !this.getElement()) {
  529. return false;
  530. }
  531. // IE has different readyState values for elements.
  532. if (goog.userAgent.EDGE_OR_IE && this.getFlashElement().readyState &&
  533. this.getFlashElement().readyState ==
  534. goog.ui.media.FlashObject.IeSwfReadyStates_.COMPLETE) {
  535. return true;
  536. }
  537. if (this.getFlashElement().readyState &&
  538. this.getFlashElement().readyState ==
  539. goog.ui.media.FlashObject.SwfReadyStates_.COMPLETE) {
  540. return true;
  541. }
  542. // Use "in" operator to check for PercentLoaded because IE8 throws when
  543. // accessing directly. See:
  544. // https://github.com/google/closure-library/pull/373.
  545. if ('PercentLoaded' in this.getFlashElement() &&
  546. this.getFlashElement().PercentLoaded() == 100) {
  547. return true;
  548. }
  549. return false;
  550. };