You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

535 lines
16 KiB

11 years ago
  1. /* ******************************
  2. Module - Video
  3. Author: Jack Lukic
  4. This is a video playlist and video embed plugin which helps
  5. provide helpers for adding embed code for vimeo and youtube and
  6. abstracting event handlers for each library
  7. ****************************** */
  8. ;(function ($, window, document, undefined) {
  9. $.fn.video = function(parameters) {
  10. var
  11. $allModules = $(this),
  12. moduleSelector = $allModules.selector || '',
  13. time = new Date().getTime(),
  14. performance = [],
  15. query = arguments[0],
  16. methodInvoked = (typeof query == 'string'),
  17. queryArguments = [].slice.call(arguments, 1),
  18. requestAnimationFrame = window.requestAnimationFrame
  19. || window.mozRequestAnimationFrame
  20. || window.webkitRequestAnimationFrame
  21. || window.msRequestAnimationFrame
  22. || function(callback) { setTimeout(callback, 0); },
  23. returnedValue
  24. ;
  25. $allModules
  26. .each(function() {
  27. var
  28. settings = ( $.isPlainObject(parameters) )
  29. ? $.extend(true, {}, $.fn.video.settings, parameters)
  30. : $.extend({}, $.fn.video.settings),
  31. selector = settings.selector,
  32. className = settings.className,
  33. error = settings.error,
  34. metadata = settings.metadata,
  35. namespace = settings.namespace,
  36. templates = settings.templates,
  37. eventNamespace = '.' + namespace,
  38. moduleNamespace = 'module-' + namespace,
  39. $window = $(window),
  40. $module = $(this),
  41. $placeholder = $module.find(selector.placeholder),
  42. $playButton = $module.find(selector.playButton),
  43. $embed = $module.find(selector.embed),
  44. element = this,
  45. instance = $module.data(moduleNamespace),
  46. module
  47. ;
  48. module = {
  49. initialize: function() {
  50. module.debug('Initializing video');
  51. module.create();
  52. $placeholder
  53. .on('click' + eventNamespace, module.play)
  54. ;
  55. $playButton
  56. .on('click' + eventNamespace, module.play)
  57. ;
  58. module.instantiate();
  59. },
  60. instantiate: function() {
  61. module.verbose('Storing instance of module', module);
  62. instance = module;
  63. $module
  64. .data(moduleNamespace, module)
  65. ;
  66. },
  67. create: function() {
  68. var
  69. image = $module.data(metadata.image),
  70. html = templates.video(image)
  71. ;
  72. $module.html(html);
  73. module.refresh();
  74. if(!image) {
  75. module.play();
  76. }
  77. module.debug('Creating html for video element', html);
  78. },
  79. destroy: function() {
  80. module.verbose('Destroying previous instance of video');
  81. $module
  82. .removeData(moduleNamespace)
  83. .off(eventNamespace)
  84. ;
  85. $placeholder
  86. .off(eventNamespace)
  87. ;
  88. $playButton
  89. .off(eventNamespace)
  90. ;
  91. },
  92. refresh: function() {
  93. module.verbose('Refreshing selector cache');
  94. $placeholder = $module.find(selector.placeholder);
  95. $playButton = $module.find(selector.playButton);
  96. $embed = $module.find(selector.embed);
  97. },
  98. // sets new video
  99. change: function(source, id, url) {
  100. module.debug('Changing video to ', source, id, url);
  101. $module
  102. .data(metadata.source, source)
  103. .data(metadata.id, id)
  104. .data(metadata.url, url)
  105. ;
  106. settings.onChange();
  107. },
  108. // clears video embed
  109. reset: function() {
  110. module.debug('Clearing video embed and showing placeholder');
  111. $module
  112. .removeClass(className.active)
  113. ;
  114. $embed
  115. .html(' ')
  116. ;
  117. $placeholder
  118. .show()
  119. ;
  120. settings.onReset();
  121. },
  122. // plays current video
  123. play: function() {
  124. module.debug('Playing video');
  125. var
  126. source = $module.data(metadata.source) || false,
  127. url = $module.data(metadata.url) || false,
  128. id = $module.data(metadata.id) || false
  129. ;
  130. $embed
  131. .html( module.generate.html(source, id, url) )
  132. ;
  133. $module
  134. .addClass(className.active)
  135. ;
  136. settings.onPlay();
  137. },
  138. get: {
  139. source: function(url) {
  140. if(typeof url !== 'string') {
  141. return false;
  142. }
  143. if(url.search('youtube.com') !== -1) {
  144. return 'youtube';
  145. }
  146. else if(url.search('vimeo.com') !== -1) {
  147. return 'vimeo';
  148. }
  149. return false;
  150. },
  151. id: function(url) {
  152. if(settings.regExp.youtube.test(url)) {
  153. return url.match(settings.regExp.youtube)[1];
  154. }
  155. else if(settings.regExp.vimeo.test(url)) {
  156. return url.match(settings.regExp.vimeo)[2];
  157. }
  158. return false;
  159. }
  160. },
  161. generate: {
  162. // generates iframe html
  163. html: function(source, id, url) {
  164. module.debug('Generating embed html');
  165. var
  166. html
  167. ;
  168. // allow override of settings
  169. source = source || settings.source;
  170. id = id || settings.id;
  171. if((source && id) || url) {
  172. if(!source || !id) {
  173. source = module.get.source(url);
  174. id = module.get.id(url);
  175. }
  176. if(source == 'vimeo') {
  177. html = ''
  178. + '<iframe src="http://player.vimeo.com/video/' + id + '?=' + module.generate.url(source) + '"'
  179. + ' width="100%" height="100%"'
  180. + ' frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>'
  181. ;
  182. }
  183. else if(source == 'youtube') {
  184. html = ''
  185. + '<iframe src="http://www.youtube.com/embed/' + id + '?=' + module.generate.url(source) + '"'
  186. + ' width="100%" height="100%"'
  187. + ' frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>'
  188. ;
  189. }
  190. }
  191. else {
  192. module.error(error.noVideo);
  193. }
  194. return html;
  195. },
  196. // generate url parameters
  197. url: function(source) {
  198. var
  199. api = (settings.api)
  200. ? 1
  201. : 0,
  202. autoplay = (settings.autoplay === 'auto')
  203. ? ($module.data('image') !== undefined)
  204. : settings.autoplay,
  205. hd = (settings.hd)
  206. ? 1
  207. : 0,
  208. showUI = (settings.showUI)
  209. ? 1
  210. : 0,
  211. // opposite used for some params
  212. hideUI = !(settings.showUI)
  213. ? 1
  214. : 0,
  215. url = ''
  216. ;
  217. if(source == 'vimeo') {
  218. url = ''
  219. + 'api=' + api
  220. + '&amp;title=' + showUI
  221. + '&amp;byline=' + showUI
  222. + '&amp;portrait=' + showUI
  223. + '&amp;autoplay=' + autoplay
  224. ;
  225. if(settings.color) {
  226. url += '&amp;color=' + settings.color;
  227. }
  228. }
  229. if(source == 'ustream') {
  230. url = ''
  231. + 'autoplay=' + autoplay
  232. ;
  233. if(settings.color) {
  234. url += '&amp;color=' + settings.color;
  235. }
  236. }
  237. else if(source == 'youtube') {
  238. url = ''
  239. + 'enablejsapi=' + api
  240. + '&amp;autoplay=' + autoplay
  241. + '&amp;autohide=' + hideUI
  242. + '&amp;hq=' + hd
  243. + '&amp;modestbranding=1'
  244. ;
  245. if(settings.color) {
  246. url += '&amp;color=' + settings.color;
  247. }
  248. }
  249. return url;
  250. }
  251. },
  252. setting: function(name, value) {
  253. module.debug('Changing setting', name, value);
  254. if( $.isPlainObject(name) ) {
  255. $.extend(true, settings, name);
  256. }
  257. else if(value !== undefined) {
  258. settings[name] = value;
  259. }
  260. else {
  261. return settings[name];
  262. }
  263. },
  264. internal: function(name, value) {
  265. if( $.isPlainObject(name) ) {
  266. $.extend(true, module, name);
  267. }
  268. else if(value !== undefined) {
  269. module[name] = value;
  270. }
  271. else {
  272. return module[name];
  273. }
  274. },
  275. debug: function() {
  276. if(settings.debug) {
  277. if(settings.performance) {
  278. module.performance.log(arguments);
  279. }
  280. else {
  281. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  282. module.debug.apply(console, arguments);
  283. }
  284. }
  285. },
  286. verbose: function() {
  287. if(settings.verbose && settings.debug) {
  288. if(settings.performance) {
  289. module.performance.log(arguments);
  290. }
  291. else {
  292. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  293. module.verbose.apply(console, arguments);
  294. }
  295. }
  296. },
  297. error: function() {
  298. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  299. module.error.apply(console, arguments);
  300. },
  301. performance: {
  302. log: function(message) {
  303. var
  304. currentTime,
  305. executionTime,
  306. previousTime
  307. ;
  308. if(settings.performance) {
  309. currentTime = new Date().getTime();
  310. previousTime = time || currentTime;
  311. executionTime = currentTime - previousTime;
  312. time = currentTime;
  313. performance.push({
  314. 'Element' : element,
  315. 'Name' : message[0],
  316. 'Arguments' : [].slice.call(message, 1) || '',
  317. 'Execution Time' : executionTime
  318. });
  319. }
  320. clearTimeout(module.performance.timer);
  321. module.performance.timer = setTimeout(module.performance.display, 100);
  322. },
  323. display: function() {
  324. var
  325. title = settings.name + ':',
  326. totalTime = 0
  327. ;
  328. time = false;
  329. clearTimeout(module.performance.timer);
  330. $.each(performance, function(index, data) {
  331. totalTime += data['Execution Time'];
  332. });
  333. title += ' ' + totalTime + 'ms';
  334. if(moduleSelector) {
  335. title += ' \'' + moduleSelector + '\'';
  336. }
  337. if($allModules.size() > 1) {
  338. title += ' ' + '(' + $allModules.size() + ')';
  339. }
  340. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  341. console.groupCollapsed(title);
  342. if(console.table) {
  343. console.table(performance);
  344. }
  345. else {
  346. $.each(performance, function(index, data) {
  347. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  348. });
  349. }
  350. console.groupEnd();
  351. }
  352. performance = [];
  353. }
  354. },
  355. invoke: function(query, passedArguments, context) {
  356. var
  357. object = instance,
  358. maxDepth,
  359. found,
  360. response
  361. ;
  362. passedArguments = passedArguments || queryArguments;
  363. context = element || context;
  364. if(typeof query == 'string' && object !== undefined) {
  365. query = query.split(/[\. ]/);
  366. maxDepth = query.length - 1;
  367. $.each(query, function(depth, value) {
  368. var camelCaseValue = (depth != maxDepth)
  369. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  370. : query
  371. ;
  372. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  373. object = object[camelCaseValue];
  374. }
  375. else if( object[camelCaseValue] !== undefined ) {
  376. found = object[camelCaseValue];
  377. return false;
  378. }
  379. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  380. object = object[value];
  381. }
  382. else if( object[value] !== undefined ) {
  383. found = object[value];
  384. return false;
  385. }
  386. else {
  387. return false;
  388. }
  389. });
  390. }
  391. if ( $.isFunction( found ) ) {
  392. response = found.apply(context, passedArguments);
  393. }
  394. else if(found !== undefined) {
  395. response = found;
  396. }
  397. if($.isArray(returnedValue)) {
  398. returnedValue.push(response);
  399. }
  400. else if(returnedValue !== undefined) {
  401. returnedValue = [returnedValue, response];
  402. }
  403. else if(response !== undefined) {
  404. returnedValue = response;
  405. }
  406. return found;
  407. }
  408. };
  409. if(methodInvoked) {
  410. if(instance === undefined) {
  411. module.initialize();
  412. }
  413. module.invoke(query);
  414. }
  415. else {
  416. if(instance !== undefined) {
  417. module.destroy();
  418. }
  419. module.initialize();
  420. }
  421. })
  422. ;
  423. return (returnedValue !== undefined)
  424. ? returnedValue
  425. : this
  426. ;
  427. };
  428. $.fn.video.settings = {
  429. name : 'Video',
  430. namespace : 'video',
  431. debug : false,
  432. verbose : true,
  433. performance : true,
  434. metadata : {
  435. id : 'id',
  436. image : 'image',
  437. source : 'source',
  438. url : 'url'
  439. },
  440. source : false,
  441. url : false,
  442. id : false,
  443. aspectRatio : (16/9),
  444. onPlay : function(){},
  445. onReset : function(){},
  446. onChange : function(){},
  447. // callbacks not coded yet (needs to use jsapi)
  448. onPause : function() {},
  449. onStop : function() {},
  450. width : 'auto',
  451. height : 'auto',
  452. autoplay : 'auto',
  453. color : '#442359',
  454. hd : true,
  455. showUI : false,
  456. api : true,
  457. regExp : {
  458. youtube : /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/,
  459. vimeo : /http:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/
  460. },
  461. error : {
  462. noVideo : 'No video specified',
  463. method : 'The method you called is not defined'
  464. },
  465. className : {
  466. active : 'active'
  467. },
  468. selector : {
  469. embed : '.embed',
  470. placeholder : '.placeholder',
  471. playButton : '.play'
  472. }
  473. };
  474. $.fn.video.settings.templates = {
  475. video: function(image) {
  476. var
  477. html = ''
  478. ;
  479. if(image) {
  480. html += ''
  481. + '<i class="play sign icon"></i>'
  482. + '<img class="placeholder" src="' + image + '">'
  483. ;
  484. }
  485. html += '<div class="embed"></div>';
  486. return html;
  487. }
  488. };
  489. })( jQuery, window , document );