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.

536 lines
15 KiB

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