jquery.fancybox.js 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463
  1. /*!
  2. * fancyBox - jQuery Plugin
  3. * version: 2.0.6 (16/04/2012)
  4. * @requires jQuery v1.6 or later
  5. *
  6. * Examples at http://fancyapps.com/fancybox/
  7. * License: www.fancyapps.com/fancybox/#license
  8. *
  9. * Copyright 2012 Janis Skarnelis - janis@fancyapps.com
  10. *
  11. */
  12. (function (window, document, $, undefined) {
  13. "use strict";
  14. var W = $(window),
  15. D = $(document),
  16. F = $.fancybox = function () {
  17. F.open.apply( this, arguments );
  18. },
  19. didResize = false,
  20. resizeTimer = null,
  21. isTouch = document.createTouch !== undefined,
  22. isString = function(str) {
  23. return $.type(str) === "string";
  24. },
  25. isPercentage = function(str) {
  26. return isString(str) && str.indexOf('%') > 0;
  27. },
  28. getValue = function(value, dim) {
  29. if (dim && isPercentage(value)) {
  30. value = F.getViewport()[ dim ] / 100 * parseInt(value, 10);
  31. }
  32. return Math.round(value) + 'px';
  33. };
  34. $.extend(F, {
  35. // The current version of fancyBox
  36. version: '2.0.5',
  37. defaults: {
  38. padding: 15,
  39. margin: 20,
  40. width: 800,
  41. height: 600,
  42. minWidth: 100,
  43. minHeight: 100,
  44. maxWidth: 9999,
  45. maxHeight: 9999,
  46. autoSize: true,
  47. autoResize: !isTouch,
  48. autoCenter : !isTouch,
  49. fitToView: true,
  50. aspectRatio: false,
  51. topRatio: 0.5,
  52. fixed: false,
  53. scrolling: 'auto', // 'auto', 'yes' or 'no'
  54. wrapCSS: '',
  55. arrows: true,
  56. closeBtn: true,
  57. closeClick: false,
  58. nextClick : false,
  59. mouseWheel: true,
  60. autoPlay: false,
  61. playSpeed: 3000,
  62. preload : 3,
  63. modal: false,
  64. loop: true,
  65. ajax: { dataType: 'html', headers: { 'X-fancyBox': true } },
  66. keys: {
  67. next: [13, 32, 34, 39, 40], // enter, space, page down, right arrow, down arrow
  68. prev: [8, 33, 37, 38], // backspace, page up, left arrow, up arrow
  69. close: [27] // escape key
  70. },
  71. // Override some properties
  72. index: 0,
  73. type: null,
  74. href: null,
  75. content: null,
  76. title: null,
  77. // HTML templates
  78. tpl: {
  79. wrap: '<div class="fancybox-wrap"><div class="fancybox-skin"><div class="fancybox-outer"><div class="fancybox-inner"></div></div></div></div>',
  80. image: '<img class="fancybox-image" src="{href}" alt="" />',
  81. iframe: '<iframe class="fancybox-iframe" name="fancybox-frame{rnd}" frameborder="0" hspace="0"' + ($.browser.msie ? ' allowtransparency="true"' : '') + '></iframe>',
  82. swf: '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"><param name="wmode" value="transparent" /><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="{href}" /><embed src="{href}" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="100%" height="100%" wmode="transparent"></embed></object>',
  83. error: '<p class="fancybox-error">The requested content cannot be loaded.<br/>Please try again later.</p>',
  84. closeBtn: '<div title="Close" class="fancybox-item fancybox-close"></div>',
  85. next: '<a title="Next" class="fancybox-nav fancybox-next"><span></span></a>',
  86. prev: '<a title="Previous" class="fancybox-nav fancybox-prev"><span></span></a>'
  87. },
  88. // Properties for each animation type
  89. // Opening fancyBox
  90. openEffect: 'fade', // 'elastic', 'fade' or 'none'
  91. openSpeed: 300,
  92. openEasing: 'swing',
  93. openOpacity: true,
  94. openMethod: 'zoomIn',
  95. // Closing fancyBox
  96. closeEffect: 'fade', // 'elastic', 'fade' or 'none'
  97. closeSpeed: 300,
  98. closeEasing: 'swing',
  99. closeOpacity: true,
  100. closeMethod: 'zoomOut',
  101. // Changing next gallery item
  102. nextEffect: 'elastic', // 'elastic', 'fade' or 'none'
  103. nextSpeed: 300,
  104. nextEasing: 'swing',
  105. nextMethod: 'changeIn',
  106. // Changing previous gallery item
  107. prevEffect: 'elastic', // 'elastic', 'fade' or 'none'
  108. prevSpeed: 300,
  109. prevEasing: 'swing',
  110. prevMethod: 'changeOut',
  111. // Enabled helpers
  112. helpers: {
  113. overlay: {
  114. speedIn: 0,
  115. speedOut: 300,
  116. opacity: 0.8,
  117. css: {
  118. cursor: 'pointer'
  119. },
  120. closeClick: true
  121. },
  122. title: {
  123. type: 'float' // 'float', 'inside', 'outside' or 'over'
  124. }
  125. },
  126. // Callbacks
  127. onCancel: $.noop, // If canceling
  128. beforeLoad: $.noop, // Before loading
  129. afterLoad: $.noop, // After loading
  130. beforeShow: $.noop, // Before changing in current item
  131. afterShow: $.noop, // After opening
  132. beforeClose: $.noop, // Before closing
  133. afterClose: $.noop // After closing
  134. },
  135. //Current state
  136. group: {}, // Selected group
  137. opts: {}, // Group options
  138. coming: null, // Element being loaded
  139. current: null, // Currently loaded element
  140. isOpen: false, // Is currently open
  141. isOpened: false, // Have been fully opened at least once
  142. wrap: null,
  143. skin: null,
  144. outer: null,
  145. inner: null,
  146. player: {
  147. timer: null,
  148. isActive: false
  149. },
  150. // Loaders
  151. ajaxLoad: null,
  152. imgPreload: null,
  153. // Some collections
  154. transitions: {},
  155. helpers: {},
  156. /*
  157. * Static methods
  158. */
  159. open: function (group, opts) {
  160. //Kill existing instances
  161. F.close(true);
  162. //Normalize group
  163. if (group && !$.isArray(group)) {
  164. group = group instanceof $ ? $(group).get() : [group];
  165. }
  166. F.isActive = true;
  167. //Extend the defaults
  168. F.opts = $.extend(true, {}, F.defaults, opts);
  169. //All options are merged recursive except keys
  170. if ($.isPlainObject(opts) && opts.keys !== undefined) {
  171. F.opts.keys = opts.keys ? $.extend({}, F.defaults.keys, opts.keys) : false;
  172. }
  173. F.group = group;
  174. F._start(F.opts.index || 0);
  175. },
  176. cancel: function () {
  177. if (F.coming && false === F.trigger('onCancel')) {
  178. return;
  179. }
  180. F.coming = null;
  181. F.hideLoading();
  182. if (F.ajaxLoad) {
  183. F.ajaxLoad.abort();
  184. }
  185. F.ajaxLoad = null;
  186. if (F.imgPreload) {
  187. F.imgPreload.onload = F.imgPreload.onabort = F.imgPreload.onerror = null;
  188. }
  189. },
  190. close: function (a) {
  191. F.cancel();
  192. if (!F.current || false === F.trigger('beforeClose')) {
  193. return;
  194. }
  195. F.unbindEvents();
  196. //If forced or is still opening then remove immediately
  197. if (!F.isOpen || (a && a[0] === true)) {
  198. $('.fancybox-wrap').stop().trigger('onReset').remove();
  199. F._afterZoomOut();
  200. } else {
  201. F.isOpen = F.isOpened = false;
  202. $('.fancybox-item, .fancybox-nav').remove();
  203. F.wrap.stop(true).removeClass('fancybox-opened');
  204. F.inner.css('overflow', 'hidden');
  205. F.transitions[F.current.closeMethod]();
  206. }
  207. },
  208. // Start/stop slideshow
  209. play: function (a) {
  210. var clear = function () {
  211. clearTimeout(F.player.timer);
  212. },
  213. set = function () {
  214. clear();
  215. if (F.current && F.player.isActive) {
  216. F.player.timer = setTimeout(F.next, F.current.playSpeed);
  217. }
  218. },
  219. stop = function () {
  220. clear();
  221. $('body').unbind('.player');
  222. F.player.isActive = false;
  223. F.trigger('onPlayEnd');
  224. },
  225. start = function () {
  226. if (F.current && (F.current.loop || F.current.index < F.group.length - 1)) {
  227. F.player.isActive = true;
  228. $('body').bind({
  229. 'afterShow.player onUpdate.player': set,
  230. 'onCancel.player beforeClose.player': stop,
  231. 'beforeLoad.player': clear
  232. });
  233. set();
  234. F.trigger('onPlayStart');
  235. }
  236. };
  237. if (F.player.isActive || (a && a[0] === false)) {
  238. stop();
  239. } else {
  240. start();
  241. }
  242. },
  243. next: function () {
  244. if (F.current) {
  245. F.jumpto(F.current.index + 1);
  246. }
  247. },
  248. prev: function () {
  249. if (F.current) {
  250. F.jumpto(F.current.index - 1);
  251. }
  252. },
  253. jumpto: function (index) {
  254. if (!F.current) {
  255. return;
  256. }
  257. index = parseInt(index, 10);
  258. if (F.group.length > 1 && F.current.loop) {
  259. if (index >= F.group.length) {
  260. index = 0;
  261. } else if (index < 0) {
  262. index = F.group.length - 1;
  263. }
  264. }
  265. if (F.group[index] !== undefined) {
  266. F.cancel();
  267. F._start(index);
  268. }
  269. },
  270. reposition: function (e, onlyAbsolute) {
  271. var pos;
  272. if (F.isOpen) {
  273. pos = F._getPosition(onlyAbsolute);
  274. if (e && e.type === 'scroll') {
  275. delete pos.position;
  276. F.wrap.stop(true, true).animate(pos, 200);
  277. } else {
  278. F.wrap.css(pos);
  279. }
  280. }
  281. },
  282. update: function (e) {
  283. if (!F.isOpen) {
  284. return;
  285. }
  286. // Run this code after a delay for better performance
  287. if (!didResize) {
  288. resizeTimer = setTimeout(function () {
  289. var current = F.current, anyway = !e || (e && e.type === 'orientationchange');
  290. if (didResize) {
  291. didResize = false;
  292. if (!current) {
  293. return;
  294. }
  295. if ((!e || e.type !== 'scroll') || anyway) {
  296. if (current.autoSize && current.type !== 'iframe') {
  297. F.inner.height('auto');
  298. current.height = F.inner.height();
  299. }
  300. if (current.autoResize || anyway) {
  301. F._setDimension();
  302. }
  303. if (current.canGrow && current.type !== 'iframe') {
  304. F.inner.height('auto');
  305. }
  306. }
  307. if (current.autoCenter || anyway) {
  308. F.reposition(e);
  309. }
  310. F.trigger('onUpdate');
  311. }
  312. }, 200);
  313. }
  314. didResize = true;
  315. },
  316. toggle: function () {
  317. if (F.isOpen) {
  318. F.current.fitToView = !F.current.fitToView;
  319. F.update();
  320. }
  321. },
  322. hideLoading: function () {
  323. D.unbind('keypress.fb');
  324. $('#fancybox-loading').remove();
  325. },
  326. showLoading: function () {
  327. F.hideLoading();
  328. //If user will press the escape-button, the request will be canceled
  329. D.bind('keypress.fb', function(e) {
  330. if (e.keyCode === 27) {
  331. e.preventDefault();
  332. F.cancel();
  333. }
  334. });
  335. $('<div id="fancybox-loading"><div></div></div>').click(F.cancel).appendTo('body');
  336. },
  337. getViewport: function () {
  338. // See http://bugs.jquery.com/ticket/6724
  339. return {
  340. x: W.scrollLeft(),
  341. y: W.scrollTop(),
  342. w: isTouch && window.innerWidth ? window.innerWidth : W.width(),
  343. h: isTouch && window.innerHeight ? window.innerHeight : W.height()
  344. };
  345. },
  346. // Unbind the keyboard / clicking actions
  347. unbindEvents: function () {
  348. if (F.wrap) {
  349. F.wrap.unbind('.fb');
  350. }
  351. D.unbind('.fb');
  352. W.unbind('.fb');
  353. },
  354. bindEvents: function () {
  355. var current = F.current,
  356. keys = current.keys;
  357. if (!current) {
  358. return;
  359. }
  360. W.bind('resize.fb orientationchange.fb' + (current.autoCenter && !current.fixed ? ' scroll.fb' : ''), F.update);
  361. if (keys) {
  362. D.bind('keydown.fb', function (e) {
  363. var code, target = e.target || e.srcElement;
  364. // Ignore key combinations and key events within form elements
  365. if (!e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey && !(target && (target.type || $(target).is('[contenteditable]')))) {
  366. code = e.keyCode;
  367. if ($.inArray(code, keys.close) > -1) {
  368. F.close();
  369. e.preventDefault();
  370. } else if ($.inArray(code, keys.next) > -1) {
  371. F.next();
  372. e.preventDefault();
  373. } else if ($.inArray(code, keys.prev) > -1) {
  374. F.prev();
  375. e.preventDefault();
  376. }
  377. }
  378. });
  379. }
  380. if ($.fn.mousewheel && current.mouseWheel && F.group.length > 1) {
  381. F.wrap.bind('mousewheel.fb', function (e, delta) {
  382. var target = e.target || null;
  383. if (delta !== 0 && (!target || target.clientHeight === 0 || (target.scrollHeight === target.clientHeight && target.scrollWidth === target.clientWidth))) {
  384. e.preventDefault();
  385. F[delta > 0 ? 'prev' : 'next']();
  386. }
  387. });
  388. }
  389. },
  390. trigger: function (event, o) {
  391. var ret, obj = o || F[ $.inArray(event, ['onCancel', 'beforeLoad', 'afterLoad']) > -1 ? 'coming' : 'current' ];
  392. if (!obj) {
  393. return;
  394. }
  395. if ($.isFunction( obj[event] )) {
  396. ret = obj[event].apply(obj, Array.prototype.slice.call(arguments, 1));
  397. }
  398. if (ret === false) {
  399. return false;
  400. }
  401. if (obj.helpers) {
  402. $.each(obj.helpers, function (helper, opts) {
  403. if (opts && $.isPlainObject(F.helpers[helper]) && $.isFunction(F.helpers[helper][event])) {
  404. F.helpers[helper][event](opts, obj);
  405. }
  406. });
  407. }
  408. $.event.trigger(event + '.fb');
  409. },
  410. isImage: function (str) {
  411. return isString(str) && str.match(/\.(jpe?g|gif|png|bmp)((\?|#).*)?$/i);
  412. },
  413. isSWF: function (str) {
  414. return isString(str) && str.match(/\.(swf)((\?|#).*)?$/i);
  415. },
  416. _start: function (index) {
  417. var coming = {},
  418. element = F.group[index] || null,
  419. isDom,
  420. href,
  421. type,
  422. rez,
  423. hrefParts;
  424. if (element && (element.nodeType || element instanceof $)) {
  425. isDom = true;
  426. if ($.metadata) {
  427. coming = $(element).metadata();
  428. }
  429. }
  430. coming = $.extend(true, {}, F.opts, {index : index, element : element}, ($.isPlainObject(element) ? element : coming));
  431. // Re-check overridable options
  432. $.each(['href', 'title', 'content', 'type'], function(i,v) {
  433. coming[v] = F.opts[ v ] || (isDom && $(element).attr( v )) || coming[ v ] || null;
  434. });
  435. // Convert margin property to array - top, right, bottom, left
  436. if (typeof coming.margin === 'number') {
  437. coming.margin = [coming.margin, coming.margin, coming.margin, coming.margin];
  438. }
  439. // 'modal' propery is just a shortcut
  440. if (coming.modal) {
  441. $.extend(true, coming, {
  442. closeBtn : false,
  443. closeClick: false,
  444. nextClick : false,
  445. arrows : false,
  446. mouseWheel : false,
  447. keys : null,
  448. helpers: {
  449. overlay : {
  450. css: {
  451. cursor : 'auto'
  452. },
  453. closeClick : false
  454. }
  455. }
  456. });
  457. }
  458. //Give a chance for callback or helpers to update coming item (type, title, etc)
  459. F.coming = coming;
  460. if (false === F.trigger('beforeLoad')) {
  461. F.coming = null;
  462. return;
  463. }
  464. type = coming.type;
  465. href = coming.href || element;
  466. ///Check if content type is set, if not, try to get
  467. if (!type) {
  468. if (isDom) {
  469. type = $(element).data('fancybox-type');
  470. if (!type) {
  471. rez = element.className.match(/fancybox\.(\w+)/);
  472. type = rez ? rez[1] : null;
  473. }
  474. }
  475. if (!type && isString(href)) {
  476. if (F.isImage(href)) {
  477. type = 'image';
  478. } else if (F.isSWF(href)) {
  479. type = 'swf';
  480. } else if (href.match(/^#/)) {
  481. type = 'inline';
  482. }
  483. }
  484. // ...if not - display element itself
  485. if (!type) {
  486. type = isDom ? 'inline' : 'html';
  487. }
  488. coming.type = type;
  489. }
  490. // Check before try to load; 'inline' and 'html' types need content, others - href
  491. if (type === 'inline' || type === 'html') {
  492. if (!coming.content) {
  493. if (type === 'inline') {
  494. coming.content = $( isString(href) ? href.replace(/.*(?=#[^\s]+$)/, '') : href ); //strip for ie7
  495. } else {
  496. coming.content = element;
  497. }
  498. }
  499. if (!coming.content || !coming.content.length) {
  500. type = null;
  501. }
  502. } else if (!href) {
  503. type = null;
  504. }
  505. /*
  506. * Add reference to the group, so it`s possible to access from callbacks, example:
  507. * afterLoad : function() {
  508. * this.title = 'Image ' + (this.index + 1) + ' of ' + this.group.length + (this.title ? ' - ' + this.title : '');
  509. * }
  510. */
  511. if (type === 'ajax' && isString(href)) {
  512. hrefParts = href.split(/\s+/, 2);
  513. href = hrefParts.shift();
  514. coming.selector = hrefParts.shift();
  515. }
  516. coming.href = href;
  517. coming.group = F.group;
  518. coming.isDom = isDom;
  519. switch (type) {
  520. case 'image':
  521. F._loadImage();
  522. break;
  523. case 'ajax':
  524. F._loadAjax();
  525. break;
  526. case 'inline':
  527. case 'iframe':
  528. case 'swf':
  529. case 'html':
  530. F._afterLoad();
  531. break;
  532. default:
  533. F._error( 'type' );
  534. }
  535. },
  536. _error: function ( type ) {
  537. F.hideLoading();
  538. $.extend(F.coming, {
  539. type : 'html',
  540. autoSize : true,
  541. minWidth : 0,
  542. minHeight : 0,
  543. padding : 15,
  544. hasError : type,
  545. content : F.coming.tpl.error
  546. });
  547. F._afterLoad();
  548. },
  549. _loadImage: function () {
  550. // Reset preload image so it is later possible to check "complete" property
  551. var img = F.imgPreload = new Image();
  552. img.onload = function () {
  553. this.onload = this.onerror = null;
  554. F.coming.width = this.width;
  555. F.coming.height = this.height;
  556. F._afterLoad();
  557. };
  558. img.onerror = function () {
  559. this.onload = this.onerror = null;
  560. F._error( 'image' );
  561. };
  562. img.src = F.coming.href;
  563. if (img.complete === undefined || !img.complete) {
  564. F.showLoading();
  565. }
  566. },
  567. _loadAjax: function () {
  568. F.showLoading();
  569. F.ajaxLoad = $.ajax($.extend({}, F.coming.ajax, {
  570. url: F.coming.href,
  571. error: function (jqXHR, textStatus) {
  572. if (F.coming && textStatus !== 'abort') {
  573. F._error( 'ajax', jqXHR );
  574. } else {
  575. F.hideLoading();
  576. }
  577. },
  578. success: function (data, textStatus) {
  579. if (textStatus === 'success') {
  580. F.coming.content = data;
  581. F._afterLoad();
  582. }
  583. }
  584. }));
  585. },
  586. _preloadImages: function() {
  587. var group = F.group,
  588. current = F.current,
  589. len = group.length,
  590. item,
  591. href,
  592. i,
  593. cnt = Math.min(current.preload, len - 1);
  594. if (!current.preload || group.length < 2) {
  595. return;
  596. }
  597. for (i = 1; i <= cnt; i += 1) {
  598. item = group[ (current.index + i ) % len ];
  599. href = item.href || $( item ).attr('href') || item;
  600. if (item.type === 'image' || F.isImage(href)) {
  601. new Image().src = href;
  602. }
  603. }
  604. },
  605. _afterLoad: function () {
  606. F.hideLoading();
  607. if (!F.coming || false === F.trigger('afterLoad', F.current)) {
  608. F.coming = false;
  609. return;
  610. }
  611. if (F.isOpened) {
  612. $('.fancybox-item, .fancybox-nav').remove();
  613. F.wrap.stop(true).removeClass('fancybox-opened');
  614. F.inner.css('overflow', 'hidden');
  615. F.transitions[F.current.prevMethod]();
  616. } else {
  617. $('.fancybox-wrap').stop().trigger('onReset').remove();
  618. F.trigger('afterClose');
  619. }
  620. F.unbindEvents();
  621. F.isOpen = false;
  622. F.current = F.coming;
  623. //Build the neccessary markup
  624. F.wrap = $(F.current.tpl.wrap).addClass('fancybox-' + (isTouch ? 'mobile' : 'desktop') + ' fancybox-type-' + F.current.type + ' fancybox-tmp ' + F.current.wrapCSS).appendTo('body');
  625. F.skin = $('.fancybox-skin', F.wrap).css('padding', getValue(F.current.padding));
  626. F.outer = $('.fancybox-outer', F.wrap);
  627. F.inner = $('.fancybox-inner', F.wrap);
  628. F._setContent();
  629. },
  630. _setContent: function () {
  631. var current = F.current,
  632. content = current.content,
  633. type = current.type,
  634. minWidth = current.minWidth,
  635. minHeight = current.minHeight,
  636. maxWidth = current.maxWidth,
  637. maxHeight = current.maxHeight,
  638. loadingBay;
  639. switch (type) {
  640. case 'inline':
  641. case 'ajax':
  642. case 'html':
  643. if (current.selector) {
  644. content = $('<div>').html(content).find(current.selector);
  645. } else if (content instanceof $) {
  646. if (content.parent().hasClass('fancybox-inner')) {
  647. content.parents('.fancybox-wrap').unbind('onReset');
  648. }
  649. content = content.show().detach();
  650. $(F.wrap).bind('onReset', function () {
  651. content.appendTo('body').hide();
  652. });
  653. }
  654. if (current.autoSize) {
  655. loadingBay = $('<div class="fancybox-wrap ' + F.current.wrapCSS + ' fancybox-tmp"></div>')
  656. .appendTo('body')
  657. .css({
  658. minWidth : getValue(minWidth, 'w'),
  659. minHeight : getValue(minHeight, 'h'),
  660. maxWidth : getValue(maxWidth, 'w'),
  661. maxHeight : getValue(maxHeight, 'h')
  662. })
  663. .append(content);
  664. current.width = loadingBay.width();
  665. current.height = loadingBay.height();
  666. // Re-check to fix 1px bug in some browsers
  667. loadingBay.width( F.current.width );
  668. if (loadingBay.height() > current.height) {
  669. loadingBay.width(current.width + 1);
  670. current.width = loadingBay.width();
  671. current.height = loadingBay.height();
  672. }
  673. content = loadingBay.contents().detach();
  674. loadingBay.remove();
  675. }
  676. break;
  677. case 'image':
  678. content = current.tpl.image.replace('{href}', current.href);
  679. current.aspectRatio = true;
  680. break;
  681. case 'swf':
  682. content = current.tpl.swf.replace(/\{width\}/g, current.width).replace(/\{height\}/g, current.height).replace(/\{href\}/g, current.href);
  683. break;
  684. case 'iframe':
  685. content = $(current.tpl.iframe.replace('{rnd}', new Date().getTime()) )
  686. .attr('scrolling', current.scrolling)
  687. .attr('src', current.href);
  688. current.scrolling = isTouch ? 'scroll' : 'auto';
  689. break;
  690. }
  691. if (type === 'image' || type === 'swf') {
  692. current.autoSize = false;
  693. current.scrolling = 'visible';
  694. }
  695. if (type === 'iframe' && current.autoSize) {
  696. F.showLoading();
  697. F._setDimension();
  698. F.inner.css('overflow', current.scrolling);
  699. content.bind({
  700. onCancel : function() {
  701. $(this).unbind();
  702. F._afterZoomOut();
  703. },
  704. load : function() {
  705. F.hideLoading();
  706. try {
  707. if (this.contentWindow.document.location) {
  708. F.current.height = $(this).contents().find('body').height();
  709. }
  710. } catch (e) {
  711. F.current.autoSize = false;
  712. }
  713. F[ F.isOpen ? '_afterZoomIn' : '_beforeShow']();
  714. }
  715. }).appendTo(F.inner);
  716. } else {
  717. F.inner.append(content);
  718. F._beforeShow();
  719. }
  720. },
  721. _beforeShow : function() {
  722. F.coming = null;
  723. //Give a chance for helpers or callbacks to update elements
  724. F.trigger('beforeShow');
  725. //Set initial dimensions and hide
  726. F._setDimension();
  727. F.wrap.hide().removeClass('fancybox-tmp');
  728. F.bindEvents();
  729. F._preloadImages();
  730. F.transitions[ F.isOpened ? F.current.nextMethod : F.current.openMethod ]();
  731. },
  732. _setDimension: function () {
  733. var wrap = F.wrap,
  734. inner = F.inner,
  735. current = F.current,
  736. viewport = F.getViewport(),
  737. margin = current.margin,
  738. padding2 = current.padding * 2,
  739. width = current.width,
  740. height = current.height,
  741. maxWidth = current.maxWidth + padding2,
  742. maxHeight = current.maxHeight + padding2,
  743. minWidth = current.minWidth + padding2,
  744. minHeight = current.minHeight + padding2,
  745. ratio,
  746. height_;
  747. viewport.w -= (margin[1] + margin[3]);
  748. viewport.h -= (margin[0] + margin[2]);
  749. if (isPercentage(width)) {
  750. width = (((viewport.w - padding2) * parseFloat(width)) / 100);
  751. }
  752. if (isPercentage(height)) {
  753. height = (((viewport.h - padding2) * parseFloat(height)) / 100);
  754. }
  755. ratio = width / height;
  756. width += padding2;
  757. height += padding2;
  758. if (current.fitToView) {
  759. maxWidth = Math.min(viewport.w, maxWidth);
  760. maxHeight = Math.min(viewport.h, maxHeight);
  761. }
  762. if (current.aspectRatio) {
  763. if (width > maxWidth) {
  764. width = maxWidth;
  765. height = ((width - padding2) / ratio) + padding2;
  766. }
  767. if (height > maxHeight) {
  768. height = maxHeight;
  769. width = ((height - padding2) * ratio) + padding2;
  770. }
  771. if (width < minWidth) {
  772. width = minWidth;
  773. height = ((width - padding2) / ratio) + padding2;
  774. }
  775. if (height < minHeight) {
  776. height = minHeight;
  777. width = ((height - padding2) * ratio) + padding2;
  778. }
  779. } else {
  780. width = Math.max(minWidth, Math.min(width, maxWidth));
  781. height = Math.max(minHeight, Math.min(height, maxHeight));
  782. }
  783. width = Math.round(width);
  784. height = Math.round(height);
  785. //Reset dimensions
  786. $(wrap.add(inner)).width('auto').height('auto');
  787. inner.width(width - padding2).height(height - padding2);
  788. wrap.width(width);
  789. height_ = wrap.height(); // Real wrap height
  790. //Fit wrapper inside
  791. if (width > maxWidth || height_ > maxHeight) {
  792. while ((width > maxWidth || height_ > maxHeight) && width > minWidth && height_ > minHeight) {
  793. height = height - 10;
  794. if (current.aspectRatio) {
  795. width = Math.round(((height - padding2) * ratio) + padding2);
  796. if (width < minWidth) {
  797. width = minWidth;
  798. height = ((width - padding2) / ratio) + padding2;
  799. }
  800. } else {
  801. width = width - 10;
  802. }
  803. inner.width(width - padding2).height(height - padding2);
  804. wrap.width(width);
  805. height_ = wrap.height();
  806. }
  807. }
  808. current.dim = {
  809. width : getValue(width),
  810. height : getValue(height_)
  811. };
  812. current.canGrow = current.autoSize && height > minHeight && height < maxHeight;
  813. current.canShrink = false;
  814. current.canExpand = false;
  815. if ((width - padding2) < current.width || (height - padding2) < current.height) {
  816. current.canExpand = true;
  817. } else if ((width > viewport.w || height_ > viewport.h) && width > minWidth && height > minHeight) {
  818. current.canShrink = true;
  819. }
  820. F.innerSpace = height_ - padding2 - inner.height();
  821. },
  822. _getPosition: function (onlyAbsolute) {
  823. var current = F.current,
  824. viewport = F.getViewport(),
  825. margin = current.margin,
  826. width = F.wrap.width() + margin[1] + margin[3],
  827. height = F.wrap.height() + margin[0] + margin[2],
  828. rez = {
  829. position: 'absolute',
  830. top : margin[0] + viewport.y,
  831. left : margin[3] + viewport.x
  832. };
  833. if (current.autoCenter && current.fixed && !onlyAbsolute && height <= viewport.h && width <= viewport.w) {
  834. rez = {
  835. position: 'fixed',
  836. top : margin[0],
  837. left : margin[3]
  838. };
  839. }
  840. rez.top = getValue(Math.max(rez.top, rez.top + ((viewport.h - height) * current.topRatio)));
  841. rez.left = getValue(Math.max(rez.left, rez.left + ((viewport.w - width) * 0.5)));
  842. return rez;
  843. },
  844. _afterZoomIn: function () {
  845. var current = F.current, scrolling = current ? current.scrolling : 'no';
  846. if (!current) {
  847. return;
  848. }
  849. F.isOpen = F.isOpened = true;
  850. F.wrap.addClass('fancybox-opened');
  851. F.inner.css('overflow', scrolling === 'yes' ? 'scroll' : (scrolling === 'no' ? 'hidden' : scrolling));
  852. F.trigger('afterShow');
  853. F.update();
  854. //Assign a click event
  855. if (current.closeClick || current.nextClick) {
  856. F.inner.css('cursor', 'pointer').bind('click.fb', function(e) {
  857. if (!$(e.target).is('a') && !$(e.target).parent().is('a')) {
  858. F[ current.closeClick ? 'close' : 'next' ]();
  859. }
  860. });
  861. }
  862. //Create a close button
  863. if (current.closeBtn) {
  864. $(current.tpl.closeBtn).appendTo(F.skin).bind('click.fb', F.close);
  865. }
  866. //Create navigation arrows
  867. if (current.arrows && F.group.length > 1) {
  868. if (current.loop || current.index > 0) {
  869. $(current.tpl.prev).appendTo(F.outer).bind('click.fb', F.prev);
  870. }
  871. if (current.loop || current.index < F.group.length - 1) {
  872. $(current.tpl.next).appendTo(F.outer).bind('click.fb', F.next);
  873. }
  874. }
  875. if (F.opts.autoPlay && !F.player.isActive) {
  876. F.opts.autoPlay = false;
  877. F.play();
  878. }
  879. },
  880. _afterZoomOut: function () {
  881. var current = F.current;
  882. F.wrap.trigger('onReset').remove();
  883. $.extend(F, {
  884. group: {},
  885. opts: {},
  886. current: null,
  887. isActive: false,
  888. isOpened: false,
  889. isOpen: false,
  890. wrap: null,
  891. skin: null,
  892. outer: null,
  893. inner: null
  894. });
  895. F.trigger('afterClose', current);
  896. }
  897. });
  898. /*
  899. * Default transitions
  900. */
  901. F.transitions = {
  902. getOrigPosition: function () {
  903. var current = F.current,
  904. element = current.element,
  905. padding = current.padding,
  906. orig = $(current.orig),
  907. pos = {},
  908. width = 50,
  909. height = 50,
  910. viewport;
  911. if (!orig.length && current.isDom && $(element).is(':visible')) {
  912. orig = $(element).find('img:first');
  913. if (!orig.length) {
  914. orig = $(element);
  915. }
  916. }
  917. if (orig.length) {
  918. pos = orig.offset();
  919. if (orig.is('img')) {
  920. width = orig.outerWidth();
  921. height = orig.outerHeight();
  922. }
  923. } else {
  924. viewport = F.getViewport();
  925. pos.top = viewport.y + (viewport.h - height) * 0.5;
  926. pos.left = viewport.x + (viewport.w - width) * 0.5;
  927. }
  928. pos = {
  929. top : getValue(pos.top - padding),
  930. left : getValue(pos.left - padding),
  931. width : getValue(width + padding * 2),
  932. height : getValue(height + padding * 2)
  933. };
  934. return pos;
  935. },
  936. step: function (now, fx) {
  937. var prop = fx.prop, value, ratio;
  938. if (prop === 'width' || prop === 'height') {
  939. value = Math.ceil(now - (F.current.padding * 2));
  940. if (prop === 'height') {
  941. ratio = (now - fx.start) / (fx.end - fx.start);
  942. if (fx.start > fx.end) {
  943. ratio = 1 - ratio;
  944. }
  945. value -= F.innerSpace * ratio;
  946. }
  947. F.inner[prop](value);
  948. }
  949. },
  950. zoomIn: function () {
  951. var wrap = F.wrap,
  952. current = F.current,
  953. effect = current.openEffect,
  954. elastic = effect === 'elastic',
  955. dim = current.dim,
  956. startPos = $.extend({}, dim, F._getPosition( elastic )),
  957. endPos = $.extend({opacity : 1}, startPos);
  958. //Remove "position" property that breaks older IE
  959. delete endPos.position;
  960. if (elastic) {
  961. startPos = this.getOrigPosition();
  962. if (current.openOpacity) {
  963. startPos.opacity = 0;
  964. }
  965. F.outer.add(F.inner).width('auto').height('auto');
  966. } else if (effect === 'fade') {
  967. startPos.opacity = 0;
  968. }
  969. wrap.css(startPos)
  970. .show()
  971. .animate(endPos, {
  972. duration : effect === 'none' ? 0 : current.openSpeed,
  973. easing : current.openEasing,
  974. step : elastic ? this.step : null,
  975. complete : F._afterZoomIn
  976. });
  977. },
  978. zoomOut: function () {
  979. var wrap = F.wrap,
  980. current = F.current,
  981. effect = current.openEffect,
  982. elastic = effect === 'elastic',
  983. endPos = {opacity : 0};
  984. if (elastic) {
  985. if (wrap.css('position') === 'fixed') {
  986. wrap.css(F._getPosition(true));
  987. }
  988. endPos = this.getOrigPosition();
  989. if (current.closeOpacity) {
  990. endPos.opacity = 0;
  991. }
  992. }
  993. wrap.animate(endPos, {
  994. duration : effect === 'none' ? 0 : current.closeSpeed,
  995. easing : current.closeEasing,
  996. step : elastic ? this.step : null,
  997. complete : F._afterZoomOut
  998. });
  999. },
  1000. changeIn: function () {
  1001. var wrap = F.wrap,
  1002. current = F.current,
  1003. effect = current.nextEffect,
  1004. elastic = effect === 'elastic',
  1005. startPos = F._getPosition( elastic ),
  1006. endPos = { opacity : 1 };
  1007. startPos.opacity = 0;
  1008. if (elastic) {
  1009. startPos.top = getValue(parseInt(startPos.top, 10) - 200);
  1010. endPos.top = '+=200px';
  1011. }
  1012. wrap.css(startPos)
  1013. .show()
  1014. .animate(endPos, {
  1015. duration : effect === 'none' ? 0 : current.nextSpeed,
  1016. easing : current.nextEasing,
  1017. complete : F._afterZoomIn
  1018. });
  1019. },
  1020. changeOut: function () {
  1021. var wrap = F.wrap,
  1022. current = F.current,
  1023. effect = current.prevEffect,
  1024. endPos = { opacity : 0 },
  1025. cleanUp = function () {
  1026. $(this).trigger('onReset').remove();
  1027. };
  1028. wrap.removeClass('fancybox-opened');
  1029. if (effect === 'elastic') {
  1030. endPos.top = '+=200px';
  1031. }
  1032. wrap.animate(endPos, {
  1033. duration : effect === 'none' ? 0 : current.prevSpeed,
  1034. easing : current.prevEasing,
  1035. complete : cleanUp
  1036. });
  1037. }
  1038. };
  1039. /*
  1040. * Overlay helper
  1041. */
  1042. F.helpers.overlay = {
  1043. overlay: null,
  1044. update: function () {
  1045. var width, scrollWidth, offsetWidth;
  1046. //Reset width/height so it will not mess
  1047. this.overlay.width('100%').height('100%');
  1048. if ($.browser.msie || isTouch) {
  1049. scrollWidth = Math.max(document.documentElement.scrollWidth, document.body.scrollWidth);
  1050. offsetWidth = Math.max(document.documentElement.offsetWidth, document.body.offsetWidth);
  1051. width = scrollWidth < offsetWidth ? W.width() : scrollWidth;
  1052. } else {
  1053. width = D.width();
  1054. }
  1055. this.overlay.width(width).height(D.height());
  1056. },
  1057. beforeShow: function (opts) {
  1058. if (this.overlay) {
  1059. return;
  1060. }
  1061. opts = $.extend(true, {}, F.defaults.helpers.overlay, opts);
  1062. this.overlay = $('<div id="fancybox-overlay"></div>').css(opts.css).appendTo('body');
  1063. if (opts.closeClick) {
  1064. this.overlay.bind('click.fb', F.close);
  1065. }
  1066. if (F.current.fixed && !isTouch) {
  1067. this.overlay.addClass('overlay-fixed');
  1068. } else {
  1069. this.update();
  1070. this.onUpdate = function () {
  1071. this.update();
  1072. };
  1073. }
  1074. this.overlay.fadeTo(opts.speedIn, opts.opacity);
  1075. },
  1076. afterClose: function (opts) {
  1077. if (this.overlay) {
  1078. this.overlay.fadeOut(opts.speedOut || 0, function () {
  1079. $(this).remove();
  1080. });
  1081. }
  1082. this.overlay = null;
  1083. }
  1084. };
  1085. /*
  1086. * Title helper
  1087. */
  1088. F.helpers.title = {
  1089. beforeShow: function (opts) {
  1090. var title, text = F.current.title;
  1091. if (text) {
  1092. title = $('<div class="fancybox-title fancybox-title-' + opts.type + '-wrap">' + text + '</div>').appendTo('body');
  1093. if (opts.type === 'float') {
  1094. //This helps for some browsers
  1095. title.width(title.width());
  1096. title.wrapInner('<span class="child"></span>');
  1097. //Increase bottom margin so this title will also fit into viewport
  1098. F.current.margin[2] += Math.abs(parseInt(title.css('margin-bottom'), 10));
  1099. }
  1100. title.appendTo(opts.type === 'over' ? F.inner : (opts.type === 'outside' ? F.wrap : F.skin));
  1101. }
  1102. }
  1103. };
  1104. // jQuery plugin initialization
  1105. $.fn.fancybox = function (options) {
  1106. var that = $(this),
  1107. selector = this.selector || '',
  1108. index,
  1109. run = function(e) {
  1110. var what = this, idx = index, relType, relVal;
  1111. if (!(e.ctrlKey || e.altKey || e.shiftKey || e.metaKey) && !$(what).is('.fancybox-wrap')) {
  1112. e.preventDefault();
  1113. relType = options.groupAttr || 'data-fancybox-group';
  1114. relVal = $(what).attr(relType);
  1115. if (!relVal) {
  1116. relType = 'rel';
  1117. relVal = what[ relType ];
  1118. }
  1119. if (relVal && relVal !== '' && relVal !== 'nofollow') {
  1120. what = selector.length ? $(selector) : that;
  1121. what = what.filter('[' + relType + '="' + relVal + '"]');
  1122. idx = what.index(this);
  1123. }
  1124. options.index = idx;
  1125. F.open(what, options);
  1126. }
  1127. };
  1128. options = options || {};
  1129. index = options.index || 0;
  1130. if (selector) {
  1131. D.undelegate(selector, 'click.fb-start').delegate(selector, 'click.fb-start', run);
  1132. } else {
  1133. that.unbind('click.fb-start').bind('click.fb-start', run);
  1134. }
  1135. return this;
  1136. };
  1137. // Test for fixedPosition needs a body at doc ready
  1138. $(document).ready(function() {
  1139. F.defaults.fixed = $.support.fixedPosition || (!($.browser.msie && $.browser.version <= 6) && !isTouch);
  1140. });
  1141. }(window, document, jQuery));