532 lines
15 KiB

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