/lib/osmf/player/StrobeMediaPlayback/html-template/jquery.strobemediaplayback.js

https://github.com/tvcok/flash · JavaScript · 449 lines · 334 code · 60 blank · 55 comment · 77 complexity · 3aba29d7c5b0a87142887b1825420793 MD5 · raw file

  1. /*****************************************************
  2. *
  3. * Copyright 2010 Adobe Systems Incorporated. All Rights Reserved.
  4. *
  5. *****************************************************
  6. * The contents of this file are subject to the Berkeley Software Distribution (BSD) Licence
  7. * (the "License"); you may not use this file except in
  8. * compliance with the License.
  9. *
  10. * Software distributed under the License is distributed on an "AS IS"
  11. * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  12. * License for the specific language governing rights and limitations
  13. * under the License.
  14. *
  15. *
  16. * The Initial Developer of the Original Code is Adobe Systems Incorporated.
  17. * Portions created by Adobe Systems Incorporated are Copyright (C) 2010 Adobe Systems
  18. * Incorporated. All Rights Reserved.
  19. *
  20. *****************************************************/
  21. /**
  22. * jQuery plugin that generate the necessary video playback mark-up.
  23. * @param {Object} /iPad/i
  24. */
  25. (function($, undefined){
  26. /**
  27. * Adapts the options of the video player based on the device/browser capabilities.
  28. */
  29. var AdaptiveExperienceConfigurator = function(){
  30. };
  31. var adaptiveExperienceConfiguratorMethods = {
  32. initialize: function(){
  33. this.userAgent = navigator.userAgent;
  34. this.isiPad = this.userAgent.match(/iPad/i) != null;
  35. this.isiPhone = this.userAgent.match(/iPhone/i) != null;
  36. this.isAndroid = this.userAgent.match(/Android/i) != null;
  37. this.screenWidth = screen.width;
  38. this.screenHeight = screen.width;
  39. this.isPhone = this.screenHeight < 360;
  40. this.isTablet = this.screenHeight >= 360 && this.screenHeight <= 768;
  41. this.isDesktop = this.screenHeight > 768;
  42. this.hasHTML5VideoCapability = !!document.createElement('video').canPlayType;
  43. this.flashPlayerVersion = swfobject.getFlashPlayerVersion();
  44. this.hasFlashPlayerCapability = this.flashPlayerVersion.major >= 10;
  45. },
  46. adapt: function(options){
  47. if (!this.userAgent) {
  48. // Initialize lazily
  49. this.initialize();
  50. }
  51. // First, extend with default values
  52. options = $.extend({}, $.fn.strobemediaplayback.defaults, options);
  53. this.changed = true;
  54. var i = 0, n = this.rules.length;
  55. while (this.changed) {
  56. this.changed = false;
  57. for (i = 0; i < n; i++) {
  58. this.rules[i](this, options);
  59. }
  60. this.changed = false;
  61. }
  62. return options;
  63. },
  64. setOption: function(options, name, value){
  65. if (!options.hasOwnProperty(name) || options[name] != value) {
  66. options[name] = value;
  67. this.changed = true;
  68. }
  69. },
  70. rules: [
  71. //playerImplementation
  72. function(context, options){
  73. if (options.favorFlashOverHtml5Video && context.hasFlashPlayerCapability) {
  74. context.setOption(options, "useHTML5", false);
  75. }
  76. else {
  77. if (!options.favorFlashOverHtml5Video && context.hasHTML5VideoCapability) {
  78. context.setOption(options, "useHTML5", true);
  79. }
  80. else {
  81. if (options.favorFlashOverHtml5Video) {
  82. context.setOption(options, "useHTML5", !context.hasFlashPlayerCapability);
  83. }
  84. else {
  85. context.setOption(options, "useHTML5", context.hasHTML5VideoCapability);
  86. }
  87. }
  88. }
  89. },
  90. //neverUseJavaScriptControlsOnIPhone:
  91. function(context, options){
  92. if (context.isiPhone) {
  93. context.setOption(options, "javascriptControls", false);
  94. }
  95. },
  96. //hideVolumeControlOnIPad:
  97. function(context, options){
  98. if (context.isiPad) {
  99. context.setOption(options, "disabledControls", ".volume");
  100. }
  101. },
  102. // No Flash & No HTML5 Video
  103. function(context, options){
  104. if (!context.hasFlashPlayerCapability && !context.hasHTML5VideoCapability) {
  105. context.setOption(options, "javascriptControls", false);
  106. context.setOption(options, "displayAlternativeContent", true);
  107. }
  108. }
  109. ]
  110. };
  111. AdaptiveExperienceConfigurator.prototype = adaptiveExperienceConfiguratorMethods;
  112. $.fn.adaptiveexperienceconfigurator = new AdaptiveExperienceConfigurator();
  113. var StrobeMediaPlayback = function(element, options){
  114. this.element = element;
  115. this.$element = $(element);
  116. this.options = $.extend({}, $.fn.strobemediaplayback.defaults, options);
  117. };
  118. // HACK: keeps the reference to the context of the function which uses swfobject
  119. // - needed for the swfobject.js error callback handler.
  120. var onFlashEmbedCompleteThisReference = null;
  121. var strobeMediaPlaybackMethods = {
  122. initialize: function() {
  123. // Detect video playback capabilities and adapt the settings
  124. this.options = $.fn.adaptiveexperienceconfigurator.adapt(this.options);
  125. if (this.options.useHTML5) {
  126. var $video = $("<video></video>");
  127. $video.attr("id", this.options.id);
  128. $video.attr("class", "smp_video");
  129. $video.attr("preload", "none");
  130. $video.attr("width", this.options.width);
  131. $video.attr("height", this.options.height);
  132. $video.attr("src", this.options.src);
  133. if (this.options.loop)
  134. {
  135. $video.attr("loop", "loop");
  136. }
  137. if (this.options.autoPlay)
  138. {
  139. $video.attr("autoplay", "autoplay");
  140. }
  141. if (this.options.controlBarMode != "none")
  142. {
  143. $video.attr("controls", "controls");
  144. }
  145. if (this.options.poster != "")
  146. {
  147. $video.attr("poster", this.options.poster);
  148. }
  149. this.$element.replaceWith($video);
  150. this.$video = $video;
  151. this.video = $video[0];
  152. }
  153. else {
  154. this.options.queryString = $.fn.strobemediaplayback.generateQueryString(this.options);
  155. var flashvars = this.options;
  156. flashvars.javascriptCallbackFunction = "$.fn.strobemediaplayback.triggerHandler";
  157. var params = {
  158. allowFullScreen: "true",
  159. wmode: "direct"
  160. };
  161. var attributes = {
  162. id: this.options.id,
  163. name: this.options.id
  164. };
  165. onFlashEmbedCompleteThisReference = this;
  166. swfobject.embedSWF(this.options.swf,
  167. this.$element.attr("id"),
  168. this.options.width,
  169. this.options.height,
  170. this.options.minimumFlashPlayerVersion,
  171. this.options.expressInstallSwfUrl,
  172. flashvars, params, attributes,
  173. this.onFlashEmbedComplete);
  174. this.monitor = new VideoElementMonitor(null);
  175. this.$video = this.monitor.$videoElement;
  176. this.video = this.monitor.videoElement;
  177. proxyMediaElements[this.options.id] = this.monitor;
  178. }
  179. },
  180. onFlashEmbedComplete: function(event)
  181. {
  182. if (!event.success && $.fn.adaptiveexperienceconfigurator.hasHTML5VideoCapability)
  183. {
  184. onFlashEmbedCompleteThisReference.useHTML5 = true;
  185. onFlashEmbedCompleteThisReference.initialize();
  186. }
  187. else {
  188. // TODO: Error notification - failed to embed the video -> fallback to displaying a link?
  189. }
  190. }
  191. }
  192. StrobeMediaPlayback.prototype = strobeMediaPlaybackMethods;
  193. $.fn.strobemediaplayback = function(options){
  194. var instances = [], i;
  195. var result = null;
  196. this.each(function(){
  197. var strobeMediaPlayback = new StrobeMediaPlayback(this, options);
  198. instances.push(strobeMediaPlayback);
  199. });
  200. for (i = 0; i < instances.length; i++) {
  201. instances[i].initialize();
  202. if (result == null) {
  203. result = instances[i].$video;
  204. }
  205. else{
  206. result.push(instances[i].video);
  207. }
  208. }
  209. return result;
  210. };
  211. /**
  212. * Plug-in default values
  213. */
  214. $.fn.strobemediaplayback.defaults = {
  215. favorFlashOverHtml5Video: true,
  216. swf: "StrobeMediaPlayback.swf",
  217. //javascriptCallbackFunction: "org.strobemediaplayback.triggerHandler",
  218. javascriptCallbackFunction: "$.fn.strobemediaplayback.triggerHandler",
  219. minimumFlashPlayerVersion: "10.0.0",
  220. expressInstallSwfUrl: "expressInstall.swf",
  221. autoPlay: false,
  222. loop: false,
  223. controlBarMode: "docked",
  224. poster: ""
  225. };
  226. /**
  227. * Utitility method that will retrieve the page parameters from the Query String.
  228. */
  229. $.fn.strobemediaplayback.parseQueryString = function(queryString){
  230. var options = {};
  231. var queryPairs = queryString.split('&'), queryPair, n = queryPairs.length;
  232. for (var i = 0; i < n; i++) {
  233. queryPair = queryPairs[i].split('=');
  234. if (queryPair[1] == "true" || queryPair[1] == "false") {
  235. options[queryPair[0]] = (queryPair[1] == "true");
  236. }
  237. else {
  238. var number = parseFloat(queryPair[1]);
  239. if (!isNaN(number)) {
  240. options[queryPair[0]] = number;
  241. }
  242. else {
  243. options[queryPair[0]] = queryPair[1];
  244. }
  245. }
  246. }
  247. return options;
  248. }
  249. /**
  250. * Utitility method that will retrieve the page parameters from the Query String.
  251. */
  252. $.fn.strobemediaplayback.generateQueryString = function(options){
  253. var queryStrings = [];
  254. for (var key in options) {
  255. if (queryStrings.length > 0) {
  256. queryStrings.push("&");
  257. }
  258. queryStrings.push(encodeURIComponent(key));
  259. queryStrings.push("=");
  260. queryStrings.push((options[key]));
  261. }
  262. return queryStrings.join("");
  263. }
  264. var proxyMediaElements = {};
  265. var proxiedMediaElements = {};
  266. $.fn.strobemediaplayback.triggerHandler = function(id, eventName, updatedProperties){
  267. var proxyMediaElement = proxyMediaElements[id];
  268. if (typeof proxyMediaElement != 'undefined') {
  269. if (typeof proxiedMediaElements[id] == 'undefined') {
  270. strobeMediaPlayback = document.getElementById(id);
  271. proxiedMediaElements[id] = strobeMediaPlayback;
  272. proxyMediaElement.strobeMediaPlayback = strobeMediaPlayback;
  273. proxyMediaElement.videoElement.play = jQuery.proxy(strobeMediaPlayback.play2, proxyMediaElement.strobeMediaPlayback);
  274. proxyMediaElement.videoElement.pause = jQuery.proxy(strobeMediaPlayback.pause, proxyMediaElement.strobeMediaPlayback);
  275. proxyMediaElement.videoElement.load = jQuery.proxy(proxyMediaElement.load, proxyMediaElement);
  276. proxyMediaElement.videoElement.strobeMediaPlayback = strobeMediaPlayback;
  277. monitorChanges(proxyMediaElement);
  278. }
  279. proxyMediaElement.update(updatedProperties, [eventName], proxyMediaElement);
  280. }
  281. }
  282. /**
  283. * Custom video playback controls
  284. */
  285. var writableProperties = "src preload currentTime defaultPlaybackRate playbackRate autoplay loop controls volume muted".split(" ");
  286. var timeRangeProperties = "played seekable buffered".split(" ");
  287. var timeRangeMethods = {
  288. start: function(index){
  289. return this._start[index];
  290. },
  291. end: function(index){
  292. return this._end[index];
  293. }
  294. }
  295. var monitorChanges = function(monitor){
  296. var i = writableProperties.length;
  297. while (i--) {
  298. var propertyName = writableProperties[i];
  299. if (monitor.cc.hasOwnProperty(propertyName) &&
  300. monitor.videoElement.hasOwnProperty(propertyName) &&
  301. monitor.cc[propertyName] != monitor.videoElement[propertyName]) {
  302. var setter = "set" + propertyName.charAt(0).toUpperCase() + propertyName.substring(1);
  303. monitor.strobeMediaPlayback[setter](monitor.videoElement[propertyName]);
  304. monitor.cc[propertyName] = monitor.videoElement[propertyName];
  305. }
  306. }
  307. setTimeout(function(){
  308. monitorChanges(monitor)
  309. }, 500);
  310. };
  311. var VideoElementMonitor = function($strobeMediaPlayback) {
  312. this.videoElement = {
  313. duration: 0,
  314. currentTime: 0,
  315. paused: true,
  316. muted: false
  317. };
  318. this.cc = {
  319. duration: 0,
  320. currentTime: 0,
  321. paused: true,
  322. muted: false
  323. };
  324. this.$videoElement = $(this.videoElement);
  325. }
  326. var isPropertyChanged = function(object, cc, propertyName)
  327. {
  328. return !object.hasOwnProperty(propertyName) && object[propertyName] != cc[propertyName];
  329. }
  330. var videoElementMonitorMethods = {
  331. load: function(){
  332. this.strobeMediaPlayback.setSrc(this.videoElement.src);
  333. this.strobeMediaPlayback.load();
  334. },
  335. update: function(properties, events, monitor){
  336. var propertyName;
  337. for (propertyName in properties) {
  338. if (jQuery.inArray("emptied", events) < 0 &&
  339. monitor.cc.hasOwnProperty(propertyName) &&
  340. monitor.videoElement.hasOwnProperty(propertyName) &&
  341. (monitor.cc[propertyName] != monitor.videoElement[propertyName] &&
  342. !isNaN(monitor.cc[propertyName]) &&
  343. !isNaN(monitor.videoElement[propertyName]))) {
  344. // this value changed
  345. continue;
  346. }
  347. monitor.cc[propertyName] = properties[propertyName];
  348. monitor.videoElement[propertyName] = properties[propertyName];
  349. if (jQuery.inArray(propertyName, timeRangeProperties) >= 0) {
  350. monitor.videoElement[propertyName].start = timeRangeMethods.start;
  351. monitor.videoElement[propertyName].end = timeRangeMethods.end;
  352. }
  353. }
  354. if (events) {
  355. var i = events.length;
  356. while (i--) {
  357. monitor.$videoElement.triggerHandler(events[i]);
  358. }
  359. }
  360. }
  361. }
  362. VideoElementMonitor.prototype = videoElementMonitorMethods;
  363. })(jQuery);
  364. /*
  365. * Generate org.strobemediaplayback namespace - which will be used by the
  366. * Flash/Strobe Media Playback once it is ready
  367. */
  368. if (typeof org == 'undefined') {
  369. var org = {};
  370. }
  371. if (typeof org.strobemediaplayback == 'undefined') {
  372. org.strobemediaplayback = {};
  373. }
  374. if (typeof org.strobemediaplayback.proxied == 'undefined') {
  375. org.strobemediaplayback.proxied = {};
  376. }
  377. org.strobemediaplayback.triggerHandler = function(id, eventName, updatedProperties){
  378. alert("--org.strobemediaplayback.triggerHandler");
  379. if (eventName == "onJavaScriptBridgeCreated") {
  380. if (typeof onJavaScriptBridgeCreated == "function") {
  381. onJavaScriptBridgeCreated(id);
  382. }
  383. }
  384. else {
  385. if (typeof org.strobemediaplayback.proxied[id] != 'undefined') {
  386. org.strobemediaplayback.proxied[id].update(updatedProperties, [eventName], org.strobemediaplayback.proxied[id]);
  387. }
  388. }
  389. }