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
  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="http://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="http://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 );