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.

538 lines
15 KiB

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