jquery.swipebox.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. /*---------------------------------------------------------------------------------------------
  2. @author Constantin Saguin - @brutaldesign
  3. @link http://csag.co
  4. @github http://github.com/brutaldesign/swipebox
  5. @version 1.2.1
  6. @license MIT License
  7. ----------------------------------------------------------------------------------------------*/
  8. ;
  9. (function (window, document, $, undefined) {
  10. $.swipebox = function (elem, options) {
  11. var defaults = {
  12. useCSS: true,
  13. initialIndexOnArray: 0,
  14. hideBarsDelay: 3000,
  15. videoMaxWidth: 1140,
  16. vimeoColor: 'CCCCCC',
  17. beforeOpen: null,
  18. afterClose: null
  19. },
  20. plugin = this,
  21. elements = [], // slides array [{href:'...', title:'...'}, ...],
  22. elem = elem,
  23. selector = elem.selector,
  24. $selector = $(selector),
  25. isTouch = document.createTouch !== undefined || ('ontouchstart' in window) || ('onmsgesturechange' in window) || navigator.msMaxTouchPoints,
  26. supportSVG = !!(window.SVGSVGElement),
  27. winWidth = window.innerWidth ? window.innerWidth : $(window).width(),
  28. winHeight = window.innerHeight ? window.innerHeight : $(window).height(),
  29. html = '<div id="swipebox-overlay">\
  30. <div id="swipebox-slider"></div>\
  31. <div id="swipebox-caption"></div>\
  32. <div id="swipebox-action">\
  33. <a id="swipebox-close"></a>\
  34. <a id="swipebox-prev"></a>\
  35. <a id="swipebox-next"></a>\
  36. </div>\
  37. </div>';
  38. plugin.settings = {}
  39. plugin.init = function () {
  40. plugin.settings = $.extend({}, defaults, options);
  41. if ($.isArray(elem)) {
  42. elements = elem;
  43. ui.target = $(window);
  44. ui.init(plugin.settings.initialIndexOnArray);
  45. } else {
  46. $selector.click(function (e) {
  47. elements = [];
  48. var index, relType, relVal;
  49. if (!relVal) {
  50. relType = 'rel';
  51. relVal = $(this).attr(relType);
  52. }
  53. if (relVal && relVal !== '' && relVal !== 'nofollow') {
  54. $elem = $selector.filter('[' + relType + '="' + relVal + '"]');
  55. } else {
  56. $elem = $(selector);
  57. }
  58. $elem.each(function () {
  59. var title = null, href = null;
  60. if ($(this).attr('title'))
  61. title = $(this).attr('title');
  62. if ($(this).attr('href'))
  63. href = $(this).attr('href');
  64. elements.push({
  65. href: href,
  66. title: title
  67. });
  68. });
  69. index = $elem.index($(this));
  70. e.preventDefault();
  71. e.stopPropagation();
  72. ui.target = $(e.target);
  73. ui.init(index);
  74. });
  75. }
  76. }
  77. plugin.refresh = function () {
  78. if (!$.isArray(elem)) {
  79. ui.destroy();
  80. $elem = $(selector);
  81. ui.actions();
  82. }
  83. }
  84. var ui = {
  85. init: function (index) {
  86. if (plugin.settings.beforeOpen)
  87. plugin.settings.beforeOpen();
  88. this.target.trigger('swipebox-start');
  89. $.swipebox.isOpen = true;
  90. this.build();
  91. this.openSlide(index);
  92. this.openMedia(index);
  93. this.preloadMedia(index + 1);
  94. this.preloadMedia(index - 1);
  95. },
  96. build: function () {
  97. var $this = this;
  98. $('body').append(html);
  99. if ($this.doCssTrans()) {
  100. $('#swipebox-slider').css({
  101. '-webkit-transition': 'left 0.4s ease',
  102. '-moz-transition': 'left 0.4s ease',
  103. '-o-transition': 'left 0.4s ease',
  104. '-khtml-transition': 'left 0.4s ease',
  105. 'transition': 'left 0.4s ease'
  106. });
  107. $('#swipebox-overlay').css({
  108. '-webkit-transition': 'opacity 1s ease',
  109. '-moz-transition': 'opacity 1s ease',
  110. '-o-transition': 'opacity 1s ease',
  111. '-khtml-transition': 'opacity 1s ease',
  112. 'transition': 'opacity 1s ease'
  113. });
  114. $('#swipebox-action, #swipebox-caption').css({
  115. '-webkit-transition': '0.5s',
  116. '-moz-transition': '0.5s',
  117. '-o-transition': '0.5s',
  118. '-khtml-transition': '0.5s',
  119. 'transition': '0.5s'
  120. });
  121. }
  122. if (supportSVG) {
  123. var bg = $('#swipebox-action #swipebox-close').css('background-image');
  124. bg = bg.replace('png', 'svg');
  125. $('#swipebox-action #swipebox-prev,#swipebox-action #swipebox-next,#swipebox-action #swipebox-close').css({
  126. 'background-image': bg
  127. });
  128. }
  129. $.each(elements, function () {
  130. $('#swipebox-slider').append('<div class="slide"></div>');
  131. });
  132. $this.setDim();
  133. $this.actions();
  134. $this.keyboard();
  135. $this.gesture();
  136. $this.animBars();
  137. $this.resize();
  138. },
  139. setDim: function () {
  140. var width, height, sliderCss = {};
  141. if ("onorientationchange" in window) {
  142. window.addEventListener("orientationchange", function () {
  143. if (window.orientation == 0) {
  144. width = winWidth;
  145. height = winHeight;
  146. } else if (window.orientation == 90 || window.orientation == -90) {
  147. width = winHeight;
  148. height = winWidth;
  149. }
  150. }, false);
  151. } else {
  152. width = window.innerWidth ? window.innerWidth : $(window).width();
  153. height = window.innerHeight ? window.innerHeight : $(window).height();
  154. }
  155. sliderCss = {
  156. width: width,
  157. height: height
  158. }
  159. $('#swipebox-overlay').css(sliderCss);
  160. },
  161. resize: function () {
  162. var $this = this;
  163. $(window).resize(function () {
  164. $this.setDim();
  165. }).resize();
  166. },
  167. supportTransition: function () {
  168. var prefixes = 'transition WebkitTransition MozTransition OTransition msTransition KhtmlTransition'.split(' ');
  169. for (var i = 0; i < prefixes.length; i++) {
  170. if (document.createElement('div').style[prefixes[i]] !== undefined) {
  171. return prefixes[i];
  172. }
  173. }
  174. return false;
  175. },
  176. doCssTrans: function () {
  177. if (plugin.settings.useCSS && this.supportTransition()) {
  178. return true;
  179. }
  180. },
  181. gesture: function () {
  182. if (isTouch) {
  183. var $this = this,
  184. distance = null,
  185. swipMinDistance = 10,
  186. startCoords = {},
  187. endCoords = {};
  188. var bars = $('#swipebox-caption, #swipebox-action');
  189. bars.addClass('visible-bars');
  190. $this.setTimeout();
  191. $('body').bind('touchstart', function (e) {
  192. $(this).addClass('touching');
  193. endCoords = e.originalEvent.targetTouches[0];
  194. startCoords.pageX = e.originalEvent.targetTouches[0].pageX;
  195. $('.touching').bind('touchmove', function (e) {
  196. e.preventDefault();
  197. e.stopPropagation();
  198. endCoords = e.originalEvent.targetTouches[0];
  199. });
  200. return false;
  201. }).bind('touchend', function (e) {
  202. e.preventDefault();
  203. e.stopPropagation();
  204. distance = endCoords.pageX - startCoords.pageX;
  205. if (distance >= swipMinDistance) {
  206. // swipeLeft
  207. $this.getPrev();
  208. } else if (distance <= -swipMinDistance) {
  209. // swipeRight
  210. $this.getNext();
  211. } else {
  212. // tap
  213. if (!bars.hasClass('visible-bars')) {
  214. $this.showBars();
  215. $this.setTimeout();
  216. } else {
  217. $this.clearTimeout();
  218. $this.hideBars();
  219. }
  220. }
  221. $('.touching').off('touchmove').removeClass('touching');
  222. });
  223. }
  224. },
  225. setTimeout: function () {
  226. if (plugin.settings.hideBarsDelay > 0) {
  227. var $this = this;
  228. $this.clearTimeout();
  229. $this.timeout = window.setTimeout(function () {
  230. $this.hideBars()
  231. },
  232. plugin.settings.hideBarsDelay
  233. );
  234. }
  235. },
  236. clearTimeout: function () {
  237. window.clearTimeout(this.timeout);
  238. this.timeout = null;
  239. },
  240. showBars: function () {
  241. var bars = $('#swipebox-caption, #swipebox-action');
  242. if (this.doCssTrans()) {
  243. bars.addClass('visible-bars');
  244. } else {
  245. $('#swipebox-caption').animate({top: 0}, 500);
  246. $('#swipebox-action').animate({bottom: 0}, 500);
  247. setTimeout(function () {
  248. bars.addClass('visible-bars');
  249. }, 1000);
  250. }
  251. },
  252. hideBars: function () {
  253. var bars = $('#swipebox-caption, #swipebox-action');
  254. if (this.doCssTrans()) {
  255. bars.removeClass('visible-bars');
  256. } else {
  257. $('#swipebox-caption').animate({top: '-50px'}, 500);
  258. $('#swipebox-action').animate({bottom: '-50px'}, 500);
  259. setTimeout(function () {
  260. bars.removeClass('visible-bars');
  261. }, 1000);
  262. }
  263. },
  264. animBars: function () {
  265. var $this = this;
  266. var bars = $('#swipebox-caption, #swipebox-action');
  267. bars.addClass('visible-bars');
  268. $this.setTimeout();
  269. $('#swipebox-slider').click(function (e) {
  270. if (!bars.hasClass('visible-bars')) {
  271. $this.showBars();
  272. $this.setTimeout();
  273. }
  274. });
  275. $('#swipebox-action').hover(function () {
  276. $this.showBars();
  277. bars.addClass('force-visible-bars');
  278. $this.clearTimeout();
  279. }, function () {
  280. bars.removeClass('force-visible-bars');
  281. $this.setTimeout();
  282. });
  283. },
  284. keyboard: function () {
  285. var $this = this;
  286. $(window).bind('keyup', function (e) {
  287. e.preventDefault();
  288. e.stopPropagation();
  289. if (e.keyCode == 37) {
  290. $this.getPrev();
  291. }
  292. else if (e.keyCode == 39) {
  293. $this.getNext();
  294. }
  295. else if (e.keyCode == 27) {
  296. $this.closeSlide();
  297. }
  298. });
  299. },
  300. actions: function () {
  301. var $this = this;
  302. if (elements.length < 2) {
  303. $('#swipebox-prev, #swipebox-next').hide();
  304. } else {
  305. $('#swipebox-prev').bind('click touchend', function (e) {
  306. e.preventDefault();
  307. e.stopPropagation();
  308. $this.getPrev();
  309. $this.setTimeout();
  310. });
  311. $('#swipebox-next').bind('click touchend', function (e) {
  312. e.preventDefault();
  313. e.stopPropagation();
  314. $this.getNext();
  315. $this.setTimeout();
  316. });
  317. }
  318. $('#swipebox-close').bind('click touchend', function (e) {
  319. $this.closeSlide();
  320. });
  321. },
  322. setSlide: function (index, isFirst) {
  323. isFirst = isFirst || false;
  324. var slider = $('#swipebox-slider');
  325. if (this.doCssTrans()) {
  326. slider.css({left: (-index * 100) + '%'});
  327. } else {
  328. slider.animate({left: (-index * 100) + '%'});
  329. }
  330. $('#swipebox-slider .slide').removeClass('current');
  331. $('#swipebox-slider .slide').eq(index).addClass('current');
  332. this.setTitle(index);
  333. if (isFirst) {
  334. slider.fadeIn();
  335. }
  336. $('#swipebox-prev, #swipebox-next').removeClass('disabled');
  337. if (index == 0) {
  338. $('#swipebox-prev').addClass('disabled');
  339. } else if (index == elements.length - 1) {
  340. $('#swipebox-next').addClass('disabled');
  341. }
  342. },
  343. openSlide: function (index) {
  344. $('html').addClass('swipebox');
  345. $(window).trigger('resize'); // fix scroll bar visibility on desktop
  346. this.setSlide(index, true);
  347. },
  348. preloadMedia: function (index) {
  349. var $this = this, src = null;
  350. if (elements[index] !== undefined)
  351. src = elements[index].href;
  352. if (!$this.isVideo(src)) {
  353. setTimeout(function () {
  354. $this.openMedia(index);
  355. }, 1000);
  356. } else {
  357. $this.openMedia(index);
  358. }
  359. },
  360. openMedia: function (index) {
  361. var $this = this, src = null;
  362. if (elements[index] !== undefined)
  363. src = elements[index].href;
  364. if (index < 0 || index >= elements.length) {
  365. return false;
  366. }
  367. if (!$this.isVideo(src)) {
  368. $this.loadMedia(src, function () {
  369. $('#swipebox-slider .slide').eq(index).html(this);
  370. });
  371. } else {
  372. $('#swipebox-slider .slide').eq(index).html($this.getVideo(src));
  373. }
  374. },
  375. setTitle: function (index, isFirst) {
  376. var title = null;
  377. $('#swipebox-caption').empty();
  378. if (elements[index] !== undefined)
  379. title = elements[index].title;
  380. if (title) {
  381. $('#swipebox-caption').append(title);
  382. }
  383. },
  384. isVideo: function (src) {
  385. if (src) {
  386. if (
  387. src.match(/youtube\.com\/watch\?v=([a-zA-Z0-9\-_]+)/)
  388. || src.match(/vimeo\.com\/([0-9]*)/)
  389. ) {
  390. return true;
  391. }
  392. }
  393. },
  394. getVideo: function (url) {
  395. var iframe = '';
  396. var output = '';
  397. var youtubeUrl = url.match(/watch\?v=([a-zA-Z0-9\-_]+)/);
  398. var vimeoUrl = url.match(/vimeo\.com\/([0-9]*)/);
  399. if (youtubeUrl) {
  400. iframe = '<iframe width="560" height="315" src="//www.youtube.com/embed/' + youtubeUrl[1] + '" frameborder="0" allowfullscreen></iframe>';
  401. } else if (vimeoUrl) {
  402. iframe = '<iframe width="560" height="315" src="http://player.vimeo.com/video/' + vimeoUrl[1] + '?byline=0&amp;portrait=0&amp;color=' + plugin.settings.vimeoColor + '" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>';
  403. }
  404. return '<div class="swipebox-video-container" style="max-width:' + plugin.settings.videomaxWidth + 'px"><div class="swipebox-video">' + iframe + '</div></div>';
  405. },
  406. loadMedia: function (src, callback) {
  407. if (!this.isVideo(src)) {
  408. var img = $('<img>').on('load', function () {
  409. callback.call(img);
  410. });
  411. img.attr('src', src);
  412. }
  413. },
  414. getNext: function () {
  415. var $this = this;
  416. index = $('#swipebox-slider .slide').index($('#swipebox-slider .slide.current'));
  417. if (index + 1 < elements.length) {
  418. index++;
  419. $this.setSlide(index);
  420. $this.preloadMedia(index + 1);
  421. }
  422. else {
  423. $('#swipebox-slider').addClass('rightSpring');
  424. setTimeout(function () {
  425. $('#swipebox-slider').removeClass('rightSpring');
  426. }, 500);
  427. }
  428. },
  429. getPrev: function () {
  430. index = $('#swipebox-slider .slide').index($('#swipebox-slider .slide.current'));
  431. if (index > 0) {
  432. index--;
  433. this.setSlide(index);
  434. this.preloadMedia(index - 1);
  435. }
  436. else {
  437. $('#swipebox-slider').addClass('leftSpring');
  438. setTimeout(function () {
  439. $('#swipebox-slider').removeClass('leftSpring');
  440. }, 500);
  441. }
  442. },
  443. closeSlide: function () {
  444. $('html').removeClass('swipebox');
  445. $(window).trigger('resize');
  446. this.destroy();
  447. },
  448. destroy: function () {
  449. $(window).unbind('keyup');
  450. $('body').unbind('touchstart');
  451. $('body').unbind('touchmove');
  452. $('body').unbind('touchend');
  453. $('#swipebox-slider').unbind();
  454. $('#swipebox-overlay').remove();
  455. if (!$.isArray(elem))
  456. elem.removeData('_swipebox');
  457. if (this.target)
  458. this.target.trigger('swipebox-destroy');
  459. $.swipebox.isOpen = false;
  460. if (plugin.settings.afterClose)
  461. plugin.settings.afterClose();
  462. }
  463. };
  464. plugin.init();
  465. };
  466. $.fn.swipebox = function (options) {
  467. if (!$.data(this, "_swipebox")) {
  468. var swipebox = new $.swipebox(this, options);
  469. this.data('_swipebox', swipebox);
  470. }
  471. return this.data('_swipebox');
  472. }
  473. }(window, document, jQuery));