embed.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. /*!
  2. * # Fomantic-UI - Embed
  3. * http://github.com/fomantic/Fomantic-UI/
  4. *
  5. *
  6. * Released under the MIT license
  7. * http://opensource.org/licenses/MIT
  8. *
  9. */
  10. ;(function ($, window, document, undefined) {
  11. "use strict";
  12. $.isFunction = $.isFunction || function(obj) {
  13. return typeof obj === "function" && typeof obj.nodeType !== "number";
  14. };
  15. window = (typeof window != 'undefined' && window.Math == Math)
  16. ? window
  17. : (typeof self != 'undefined' && self.Math == Math)
  18. ? self
  19. : Function('return this')()
  20. ;
  21. $.fn.embed = function(parameters) {
  22. var
  23. $allModules = $(this),
  24. moduleSelector = $allModules.selector || '',
  25. time = new Date().getTime(),
  26. performance = [],
  27. query = arguments[0],
  28. methodInvoked = (typeof query == 'string'),
  29. queryArguments = [].slice.call(arguments, 1),
  30. returnedValue
  31. ;
  32. $allModules
  33. .each(function() {
  34. var
  35. settings = ( $.isPlainObject(parameters) )
  36. ? $.extend(true, {}, $.fn.embed.settings, parameters)
  37. : $.extend({}, $.fn.embed.settings),
  38. selector = settings.selector,
  39. className = settings.className,
  40. sources = settings.sources,
  41. error = settings.error,
  42. metadata = settings.metadata,
  43. namespace = settings.namespace,
  44. templates = settings.templates,
  45. eventNamespace = '.' + namespace,
  46. moduleNamespace = 'module-' + namespace,
  47. $module = $(this),
  48. $placeholder = $module.find(selector.placeholder),
  49. $icon = $module.find(selector.icon),
  50. $embed = $module.find(selector.embed),
  51. element = this,
  52. instance = $module.data(moduleNamespace),
  53. module
  54. ;
  55. module = {
  56. initialize: function() {
  57. module.debug('Initializing embed');
  58. module.determine.autoplay();
  59. module.create();
  60. module.bind.events();
  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. destroy: function() {
  71. module.verbose('Destroying previous instance of embed');
  72. module.reset();
  73. $module
  74. .removeData(moduleNamespace)
  75. .off(eventNamespace)
  76. ;
  77. },
  78. refresh: function() {
  79. module.verbose('Refreshing selector cache');
  80. $placeholder = $module.find(selector.placeholder);
  81. $icon = $module.find(selector.icon);
  82. $embed = $module.find(selector.embed);
  83. },
  84. bind: {
  85. events: function() {
  86. if( module.has.placeholder() ) {
  87. module.debug('Adding placeholder events');
  88. $module
  89. .on('click' + eventNamespace, selector.placeholder, module.createAndShow)
  90. .on('click' + eventNamespace, selector.icon, module.createAndShow)
  91. ;
  92. }
  93. }
  94. },
  95. create: function() {
  96. var
  97. placeholder = module.get.placeholder()
  98. ;
  99. if(placeholder) {
  100. module.createPlaceholder();
  101. }
  102. else {
  103. module.createAndShow();
  104. }
  105. },
  106. createPlaceholder: function(placeholder) {
  107. var
  108. icon = module.get.icon(),
  109. url = module.get.url(),
  110. embed = module.generate.embed(url)
  111. ;
  112. placeholder = placeholder || module.get.placeholder();
  113. $module.html( templates.placeholder(placeholder, icon) );
  114. module.debug('Creating placeholder for embed', placeholder, icon);
  115. },
  116. createEmbed: function(url) {
  117. module.refresh();
  118. url = url || module.get.url();
  119. $embed = $('<div/>')
  120. .addClass(className.embed)
  121. .html( module.generate.embed(url) )
  122. .appendTo($module)
  123. ;
  124. settings.onCreate.call(element, url);
  125. module.debug('Creating embed object', $embed);
  126. },
  127. changeEmbed: function(url) {
  128. $embed
  129. .html( module.generate.embed(url) )
  130. ;
  131. },
  132. createAndShow: function() {
  133. module.createEmbed();
  134. module.show();
  135. },
  136. // sets new embed
  137. change: function(source, id, url) {
  138. module.debug('Changing video to ', source, id, url);
  139. $module
  140. .data(metadata.source, source)
  141. .data(metadata.id, id)
  142. ;
  143. if(url) {
  144. $module.data(metadata.url, url);
  145. }
  146. else {
  147. $module.removeData(metadata.url);
  148. }
  149. if(module.has.embed()) {
  150. module.changeEmbed();
  151. }
  152. else {
  153. module.create();
  154. }
  155. },
  156. // clears embed
  157. reset: function() {
  158. module.debug('Clearing embed and showing placeholder');
  159. module.remove.data();
  160. module.remove.active();
  161. module.remove.embed();
  162. module.showPlaceholder();
  163. settings.onReset.call(element);
  164. },
  165. // shows current embed
  166. show: function() {
  167. module.debug('Showing embed');
  168. module.set.active();
  169. settings.onDisplay.call(element);
  170. },
  171. hide: function() {
  172. module.debug('Hiding embed');
  173. module.showPlaceholder();
  174. },
  175. showPlaceholder: function() {
  176. module.debug('Showing placeholder image');
  177. module.remove.active();
  178. settings.onPlaceholderDisplay.call(element);
  179. },
  180. get: {
  181. id: function() {
  182. return settings.id || $module.data(metadata.id);
  183. },
  184. placeholder: function() {
  185. return settings.placeholder || $module.data(metadata.placeholder);
  186. },
  187. icon: function() {
  188. return (settings.icon)
  189. ? settings.icon
  190. : ($module.data(metadata.icon) !== undefined)
  191. ? $module.data(metadata.icon)
  192. : module.determine.icon()
  193. ;
  194. },
  195. source: function(url) {
  196. return (settings.source)
  197. ? settings.source
  198. : ($module.data(metadata.source) !== undefined)
  199. ? $module.data(metadata.source)
  200. : module.determine.source()
  201. ;
  202. },
  203. type: function() {
  204. var source = module.get.source();
  205. return (sources[source] !== undefined)
  206. ? sources[source].type
  207. : false
  208. ;
  209. },
  210. url: function() {
  211. return (settings.url)
  212. ? settings.url
  213. : ($module.data(metadata.url) !== undefined)
  214. ? $module.data(metadata.url)
  215. : module.determine.url()
  216. ;
  217. }
  218. },
  219. determine: {
  220. autoplay: function() {
  221. if(module.should.autoplay()) {
  222. settings.autoplay = true;
  223. }
  224. },
  225. source: function(url) {
  226. var
  227. matchedSource = false
  228. ;
  229. url = url || module.get.url();
  230. if(url) {
  231. $.each(sources, function(name, source) {
  232. if(url.search(source.domain) !== -1) {
  233. matchedSource = name;
  234. return false;
  235. }
  236. });
  237. }
  238. return matchedSource;
  239. },
  240. icon: function() {
  241. var
  242. source = module.get.source()
  243. ;
  244. return (sources[source] !== undefined)
  245. ? sources[source].icon
  246. : false
  247. ;
  248. },
  249. url: function() {
  250. var
  251. id = settings.id || $module.data(metadata.id),
  252. source = settings.source || $module.data(metadata.source),
  253. url
  254. ;
  255. url = (sources[source] !== undefined)
  256. ? sources[source].url.replace('{id}', id)
  257. : false
  258. ;
  259. if(url) {
  260. $module.data(metadata.url, url);
  261. }
  262. return url;
  263. }
  264. },
  265. set: {
  266. active: function() {
  267. $module.addClass(className.active);
  268. }
  269. },
  270. remove: {
  271. data: function() {
  272. $module
  273. .removeData(metadata.id)
  274. .removeData(metadata.icon)
  275. .removeData(metadata.placeholder)
  276. .removeData(metadata.source)
  277. .removeData(metadata.url)
  278. ;
  279. },
  280. active: function() {
  281. $module.removeClass(className.active);
  282. },
  283. embed: function() {
  284. $embed.empty();
  285. }
  286. },
  287. encode: {
  288. parameters: function(parameters) {
  289. var
  290. urlString = [],
  291. index
  292. ;
  293. for (index in parameters) {
  294. urlString.push( encodeURIComponent(index) + '=' + encodeURIComponent( parameters[index] ) );
  295. }
  296. return urlString.join('&amp;');
  297. }
  298. },
  299. generate: {
  300. embed: function(url) {
  301. module.debug('Generating embed html');
  302. var
  303. source = module.get.source(),
  304. html,
  305. parameters
  306. ;
  307. url = module.get.url(url);
  308. if(url) {
  309. parameters = module.generate.parameters(source);
  310. html = templates.iframe(url, parameters);
  311. }
  312. else {
  313. module.error(error.noURL, $module);
  314. }
  315. return html;
  316. },
  317. parameters: function(source, extraParameters) {
  318. var
  319. parameters = (sources[source] && sources[source].parameters !== undefined)
  320. ? sources[source].parameters(settings)
  321. : {}
  322. ;
  323. extraParameters = extraParameters || settings.parameters;
  324. if(extraParameters) {
  325. parameters = $.extend({}, parameters, extraParameters);
  326. }
  327. parameters = settings.onEmbed(parameters);
  328. return module.encode.parameters(parameters);
  329. }
  330. },
  331. has: {
  332. embed: function() {
  333. return ($embed.length > 0);
  334. },
  335. placeholder: function() {
  336. return settings.placeholder || $module.data(metadata.placeholder);
  337. }
  338. },
  339. should: {
  340. autoplay: function() {
  341. return (settings.autoplay === 'auto')
  342. ? (settings.placeholder || $module.data(metadata.placeholder) !== undefined)
  343. : settings.autoplay
  344. ;
  345. }
  346. },
  347. is: {
  348. video: function() {
  349. return module.get.type() == 'video';
  350. }
  351. },
  352. setting: function(name, value) {
  353. module.debug('Changing setting', name, value);
  354. if( $.isPlainObject(name) ) {
  355. $.extend(true, settings, name);
  356. }
  357. else if(value !== undefined) {
  358. if($.isPlainObject(settings[name])) {
  359. $.extend(true, settings[name], value);
  360. }
  361. else {
  362. settings[name] = value;
  363. }
  364. }
  365. else {
  366. return settings[name];
  367. }
  368. },
  369. internal: function(name, value) {
  370. if( $.isPlainObject(name) ) {
  371. $.extend(true, module, name);
  372. }
  373. else if(value !== undefined) {
  374. module[name] = value;
  375. }
  376. else {
  377. return module[name];
  378. }
  379. },
  380. debug: function() {
  381. if(!settings.silent && settings.debug) {
  382. if(settings.performance) {
  383. module.performance.log(arguments);
  384. }
  385. else {
  386. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  387. module.debug.apply(console, arguments);
  388. }
  389. }
  390. },
  391. verbose: function() {
  392. if(!settings.silent && settings.verbose && settings.debug) {
  393. if(settings.performance) {
  394. module.performance.log(arguments);
  395. }
  396. else {
  397. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  398. module.verbose.apply(console, arguments);
  399. }
  400. }
  401. },
  402. error: function() {
  403. if(!settings.silent) {
  404. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  405. module.error.apply(console, arguments);
  406. }
  407. },
  408. performance: {
  409. log: function(message) {
  410. var
  411. currentTime,
  412. executionTime,
  413. previousTime
  414. ;
  415. if(settings.performance) {
  416. currentTime = new Date().getTime();
  417. previousTime = time || currentTime;
  418. executionTime = currentTime - previousTime;
  419. time = currentTime;
  420. performance.push({
  421. 'Name' : message[0],
  422. 'Arguments' : [].slice.call(message, 1) || '',
  423. 'Element' : element,
  424. 'Execution Time' : executionTime
  425. });
  426. }
  427. clearTimeout(module.performance.timer);
  428. module.performance.timer = setTimeout(module.performance.display, 500);
  429. },
  430. display: function() {
  431. var
  432. title = settings.name + ':',
  433. totalTime = 0
  434. ;
  435. time = false;
  436. clearTimeout(module.performance.timer);
  437. $.each(performance, function(index, data) {
  438. totalTime += data['Execution Time'];
  439. });
  440. title += ' ' + totalTime + 'ms';
  441. if(moduleSelector) {
  442. title += ' \'' + moduleSelector + '\'';
  443. }
  444. if($allModules.length > 1) {
  445. title += ' ' + '(' + $allModules.length + ')';
  446. }
  447. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  448. console.groupCollapsed(title);
  449. if(console.table) {
  450. console.table(performance);
  451. }
  452. else {
  453. $.each(performance, function(index, data) {
  454. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  455. });
  456. }
  457. console.groupEnd();
  458. }
  459. performance = [];
  460. }
  461. },
  462. invoke: function(query, passedArguments, context) {
  463. var
  464. object = instance,
  465. maxDepth,
  466. found,
  467. response
  468. ;
  469. passedArguments = passedArguments || queryArguments;
  470. context = element || context;
  471. if(typeof query == 'string' && object !== undefined) {
  472. query = query.split(/[\. ]/);
  473. maxDepth = query.length - 1;
  474. $.each(query, function(depth, value) {
  475. var camelCaseValue = (depth != maxDepth)
  476. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  477. : query
  478. ;
  479. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  480. object = object[camelCaseValue];
  481. }
  482. else if( object[camelCaseValue] !== undefined ) {
  483. found = object[camelCaseValue];
  484. return false;
  485. }
  486. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  487. object = object[value];
  488. }
  489. else if( object[value] !== undefined ) {
  490. found = object[value];
  491. return false;
  492. }
  493. else {
  494. module.error(error.method, query);
  495. return false;
  496. }
  497. });
  498. }
  499. if ( $.isFunction( found ) ) {
  500. response = found.apply(context, passedArguments);
  501. }
  502. else if(found !== undefined) {
  503. response = found;
  504. }
  505. if(Array.isArray(returnedValue)) {
  506. returnedValue.push(response);
  507. }
  508. else if(returnedValue !== undefined) {
  509. returnedValue = [returnedValue, response];
  510. }
  511. else if(response !== undefined) {
  512. returnedValue = response;
  513. }
  514. return found;
  515. }
  516. };
  517. if(methodInvoked) {
  518. if(instance === undefined) {
  519. module.initialize();
  520. }
  521. module.invoke(query);
  522. }
  523. else {
  524. if(instance !== undefined) {
  525. instance.invoke('destroy');
  526. }
  527. module.initialize();
  528. }
  529. })
  530. ;
  531. return (returnedValue !== undefined)
  532. ? returnedValue
  533. : this
  534. ;
  535. };
  536. $.fn.embed.settings = {
  537. name : 'Embed',
  538. namespace : 'embed',
  539. silent : false,
  540. debug : false,
  541. verbose : false,
  542. performance : true,
  543. icon : false,
  544. source : false,
  545. url : false,
  546. id : false,
  547. // standard video settings
  548. autoplay : 'auto',
  549. color : '#444444',
  550. hd : true,
  551. brandedUI : false,
  552. // additional parameters to include with the embed
  553. parameters: false,
  554. onDisplay : function() {},
  555. onPlaceholderDisplay : function() {},
  556. onReset : function() {},
  557. onCreate : function(url) {},
  558. onEmbed : function(parameters) {
  559. return parameters;
  560. },
  561. metadata : {
  562. id : 'id',
  563. icon : 'icon',
  564. placeholder : 'placeholder',
  565. source : 'source',
  566. url : 'url'
  567. },
  568. error : {
  569. noURL : 'No URL specified',
  570. method : 'The method you called is not defined'
  571. },
  572. className : {
  573. active : 'active',
  574. embed : 'embed'
  575. },
  576. selector : {
  577. embed : '.embed',
  578. placeholder : '.placeholder',
  579. icon : '.icon'
  580. },
  581. sources: {
  582. youtube: {
  583. name : 'youtube',
  584. type : 'video',
  585. icon : 'video play',
  586. domain : 'youtube.com',
  587. url : '//www.youtube.com/embed/{id}',
  588. parameters: function(settings) {
  589. return {
  590. autohide : !settings.brandedUI,
  591. autoplay : settings.autoplay,
  592. color : settings.color || undefined,
  593. hq : settings.hd,
  594. jsapi : settings.api,
  595. modestbranding : !settings.brandedUI
  596. };
  597. }
  598. },
  599. vimeo: {
  600. name : 'vimeo',
  601. type : 'video',
  602. icon : 'video play',
  603. domain : 'vimeo.com',
  604. url : '//player.vimeo.com/video/{id}',
  605. parameters: function(settings) {
  606. return {
  607. api : settings.api,
  608. autoplay : settings.autoplay,
  609. byline : settings.brandedUI,
  610. color : settings.color || undefined,
  611. portrait : settings.brandedUI,
  612. title : settings.brandedUI
  613. };
  614. }
  615. }
  616. },
  617. templates: {
  618. iframe : function(url, parameters) {
  619. var src = url;
  620. if (parameters) {
  621. src += '?' + parameters;
  622. }
  623. return ''
  624. + '<iframe src="' + src + '"'
  625. + ' width="100%" height="100%"'
  626. + ' webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>'
  627. ;
  628. },
  629. placeholder : function(image, icon) {
  630. var
  631. html = ''
  632. ;
  633. if(icon) {
  634. html += '<i class="' + icon + ' icon"></i>';
  635. }
  636. if(image) {
  637. html += '<img class="placeholder" src="' + image + '">';
  638. }
  639. return html;
  640. }
  641. },
  642. // NOT YET IMPLEMENTED
  643. api : false,
  644. onPause : function() {},
  645. onPlay : function() {},
  646. onStop : function() {}
  647. };
  648. })( jQuery, window, document );