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.

540 lines
16 KiB

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