lightbox.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. Ext.ns('Ext.ux');
  2. Ext.ux.Lightbox = (function(){
  3. var els = {},
  4. images = [],
  5. activeImage,
  6. initialized = false,
  7. selectors = [];
  8. return {
  9. overlayOpacity: 0.85,
  10. animate: true,
  11. resizeSpeed: 8,
  12. borderSize: 10,
  13. labelImage: "Image",
  14. labelOf: "of",
  15. init: function() {
  16. this.resizeDuration = this.animate ? ((11 - this.resizeSpeed) * 0.15) : 0;
  17. this.overlayDuration = this.animate ? 0.2 : 0;
  18. if(!initialized) {
  19. Ext.apply(this, Ext.util.Observable.prototype);
  20. Ext.util.Observable.constructor.call(this);
  21. this.addEvents('open', 'close');
  22. this.initMarkup();
  23. this.initEvents();
  24. initialized = true;
  25. }
  26. },
  27. initMarkup: function() {
  28. els.shim = Ext.DomHelper.append(document.body, {
  29. tag: 'iframe',
  30. id: 'ux-lightbox-shim'
  31. }, true);
  32. els.overlay = Ext.DomHelper.append(document.body, {
  33. id: 'ux-lightbox-overlay'
  34. }, true);
  35. var lightboxTpl = new Ext.Template(this.getTemplate());
  36. els.lightbox = lightboxTpl.append(document.body, {}, true);
  37. var ids =
  38. ['outerImageContainer', 'imageContainer', 'image', 'hoverNav', 'navPrev', 'navNext', 'loading', 'loadingLink',
  39. 'outerDataContainer', 'dataContainer', 'data', 'details', 'caption', 'imageNumber', 'bottomNav', 'navClose'];
  40. Ext.each(ids, function(id){
  41. els[id] = Ext.get('ux-lightbox-' + id);
  42. });
  43. Ext.each([els.overlay, els.lightbox, els.shim], function(el){
  44. el.setVisibilityMode(Ext.Element.DISPLAY)
  45. el.hide();
  46. });
  47. var size = (this.animate ? 250 : 1) + 'px';
  48. els.outerImageContainer.setStyle({
  49. width: size,
  50. height: size
  51. });
  52. },
  53. getTemplate : function() {
  54. return [
  55. '<div id="ux-lightbox">',
  56. '<div id="ux-lightbox-outerImageContainer">',
  57. '<div id="ux-lightbox-imageContainer">',
  58. '<img id="ux-lightbox-image">',
  59. '<div id="ux-lightbox-hoverNav">',
  60. '<a href="#" id="ux-lightbox-navPrev"></a>',
  61. '<a href="#" id="ux-lightbox-navNext"></a>',
  62. '</div>',
  63. '<div id="ux-lightbox-loading">',
  64. '<a id="ux-lightbox-loadingLink"></a>',
  65. '</div>',
  66. '</div>',
  67. '</div>',
  68. '<div id="ux-lightbox-outerDataContainer">',
  69. '<div id="ux-lightbox-dataContainer">',
  70. '<div id="ux-lightbox-data">',
  71. '<div id="ux-lightbox-details">',
  72. '<span id="ux-lightbox-caption"></span>',
  73. '<span id="ux-lightbox-imageNumber"></span>',
  74. '</div>',
  75. '<div id="ux-lightbox-bottomNav">',
  76. '<a href="#" id="ux-lightbox-navClose"></a>',
  77. '</div>',
  78. '</div>',
  79. '</div>',
  80. '</div>',
  81. '</div>'
  82. ];
  83. },
  84. initEvents: function() {
  85. var close = function(ev) {
  86. ev.preventDefault();
  87. this.close();
  88. };
  89. els.overlay.on('click', close, this);
  90. els.loadingLink.on('click', close, this);
  91. els.navClose.on('click', close, this);
  92. els.lightbox.on('click', function(ev) {
  93. if(ev.getTarget().id == 'ux-lightbox') {
  94. this.close();
  95. }
  96. }, this);
  97. els.navPrev.on('click', function(ev) {
  98. ev.preventDefault();
  99. this.setImage(activeImage - 1);
  100. }, this);
  101. els.navNext.on('click', function(ev) {
  102. ev.preventDefault();
  103. this.setImage(activeImage + 1);
  104. }, this);
  105. },
  106. register: function(sel, group) {
  107. if(selectors.indexOf(sel) === -1) {
  108. selectors.push(sel);
  109. Ext.fly(document).on('click', function(ev){
  110. var target = ev.getTarget(sel);
  111. if (target) {
  112. ev.preventDefault();
  113. this.open(target, sel, group);
  114. }
  115. }, this);
  116. }
  117. },
  118. open: function(image, sel, group) {
  119. group = group || false;
  120. this.setViewSize();
  121. els.overlay.fadeIn({
  122. duration: this.overlayDuration,
  123. endOpacity: this.overlayOpacity,
  124. callback: function() {
  125. images = [];
  126. var index = 0;
  127. if(!group) {
  128. images.push([image.href, image.title]);
  129. }
  130. else {
  131. var setItems = Ext.query(sel);
  132. Ext.each(setItems, function(item) {
  133. if(item.href) {
  134. images.push([item.href, item.title]);
  135. }
  136. });
  137. while (images[index][0] != image.href) {
  138. index++;
  139. }
  140. }
  141. // calculate top and left offset for the lightbox
  142. var pageScroll = Ext.fly(document).getScroll();
  143. var lightboxTop = pageScroll.top + (Ext.lib.Dom.getViewportHeight() / 10);
  144. var lightboxLeft = pageScroll.left;
  145. els.lightbox.setStyle({
  146. top: lightboxTop + 'px',
  147. left: lightboxLeft + 'px'
  148. }).show();
  149. this.setImage(index);
  150. this.fireEvent('open', images[index]);
  151. },
  152. scope: this
  153. });
  154. },
  155. setViewSize: function(){
  156. var viewSize = this.getViewSize();
  157. els.overlay.setStyle({
  158. width: viewSize[0] + 'px',
  159. height: viewSize[1] + 'px'
  160. });
  161. els.shim.setStyle({
  162. width: viewSize[0] + 'px',
  163. height: viewSize[1] + 'px'
  164. }).show();
  165. },
  166. setImage: function(index){
  167. activeImage = index;
  168. this.disableKeyNav();
  169. if (this.animate) {
  170. els.loading.show();
  171. }
  172. els.image.hide();
  173. els.hoverNav.hide();
  174. els.navPrev.hide();
  175. els.navNext.hide();
  176. els.dataContainer.setOpacity(0.0001);
  177. els.imageNumber.hide();
  178. var preload = new Image();
  179. preload.onload = (function(){
  180. var viewSize = Ext.getBody().getViewSize();
  181. var dim = this.scaleSize(viewSize.width, viewSize.height, preload.width, preload.height);
  182. els.image.setWidth(dim[0]);
  183. els.image.setHeight(dim[1]);
  184. els.image.dom.src = images[activeImage][0];
  185. this.resizeImage(els.image.dom.width, els.image.dom.height);
  186. }).createDelegate(this);
  187. preload.src = images[activeImage][0];
  188. },
  189. scaleSize: function(maxWidth, maxHeight, width, height){
  190. var ratio = 0;
  191. maxHeight = maxHeight - 200;
  192. if(width > maxWidth){
  193. ratio = maxWidth / width;
  194. width = maxWidth;
  195. height = height * ratio;
  196. }
  197. if(height > (maxHeight)){
  198. ratio = maxHeight / height;
  199. width = width * ratio;
  200. height = maxHeight;
  201. }
  202. return [width, height];
  203. },
  204. resizeImage: function(w, h){
  205. var wCur = els.outerImageContainer.getWidth();
  206. var hCur = els.outerImageContainer.getHeight();
  207. var wNew = (w + this.borderSize * 2);
  208. var hNew = (h + this.borderSize * 2);
  209. var wDiff = wCur - wNew;
  210. var hDiff = hCur - hNew;
  211. var afterResize = function(){
  212. els.hoverNav.setWidth(els.imageContainer.getWidth() + 'px');
  213. els.navPrev.setHeight(h + 'px');
  214. els.navNext.setHeight(h + 'px');
  215. els.outerDataContainer.setWidth(wNew + 'px');
  216. this.showImage();
  217. };
  218. if (hDiff != 0 || wDiff != 0) {
  219. els.outerImageContainer.shift({
  220. height: hNew,
  221. width: wNew,
  222. duration: this.resizeDuration,
  223. scope: this,
  224. callback: afterResize,
  225. delay: 50
  226. });
  227. }
  228. else {
  229. afterResize.call(this);
  230. }
  231. },
  232. showImage: function(){
  233. els.loading.hide();
  234. els.image.fadeIn({
  235. duration: this.resizeDuration,
  236. scope: this,
  237. callback: function(){
  238. this.updateDetails();
  239. }
  240. });
  241. this.preloadImages();
  242. },
  243. updateDetails: function(){
  244. var detailsWidth = els.data.getWidth(true) - els.navClose.getWidth() - 10;
  245. els.details.setWidth((detailsWidth > 0 ? detailsWidth : 0) + 'px');
  246. els.caption.update(images[activeImage][1]);
  247. els.caption.show();
  248. if (images.length > 1) {
  249. els.imageNumber.update(this.labelImage + ' ' + (activeImage + 1) + ' ' + this.labelOf + ' ' + images.length);
  250. els.imageNumber.show();
  251. }
  252. els.dataContainer.fadeIn({
  253. duration: this.resizeDuration/2,
  254. scope: this,
  255. callback: function() {
  256. var viewSize = this.getViewSize();
  257. els.overlay.setHeight(viewSize[1] + 'px');
  258. this.updateNav();
  259. }
  260. });
  261. },
  262. updateNav: function(){
  263. this.enableKeyNav();
  264. els.hoverNav.show();
  265. // if not first image in set, display prev image button
  266. if (activeImage > 0)
  267. els.navPrev.show();
  268. // if not last image in set, display next image button
  269. if (activeImage < (images.length - 1))
  270. els.navNext.show();
  271. },
  272. enableKeyNav: function() {
  273. Ext.fly(document).on('keydown', this.keyNavAction, this);
  274. },
  275. disableKeyNav: function() {
  276. Ext.fly(document).un('keydown', this.keyNavAction, this);
  277. },
  278. keyNavAction: function(ev) {
  279. var keyCode = ev.getKey();
  280. if (
  281. keyCode == 88 || // x
  282. keyCode == 67 || // c
  283. keyCode == 27
  284. ) {
  285. this.close();
  286. }
  287. else if (keyCode == 80 || keyCode == 37){ // display previous image
  288. if (activeImage != 0){
  289. this.setImage(activeImage - 1);
  290. }
  291. }
  292. else if (keyCode == 78 || keyCode == 39){ // display next image
  293. if (activeImage != (images.length - 1)){
  294. this.setImage(activeImage + 1);
  295. }
  296. }
  297. },
  298. preloadImages: function(){
  299. var next, prev;
  300. if (images.length > activeImage + 1) {
  301. next = new Image();
  302. next.src = images[activeImage + 1][0];
  303. }
  304. if (activeImage > 0) {
  305. prev = new Image();
  306. prev.src = images[activeImage - 1][0];
  307. }
  308. },
  309. close: function(){
  310. this.disableKeyNav();
  311. els.lightbox.hide();
  312. els.overlay.fadeOut({
  313. duration: this.overlayDuration
  314. });
  315. els.shim.hide();
  316. this.fireEvent('close', activeImage);
  317. },
  318. getViewSize: function() {
  319. return [Ext.lib.Dom.getViewWidth(), Ext.lib.Dom.getViewHeight()];
  320. }
  321. }
  322. })();
  323. Ext.onReady(Ext.ux.Lightbox.init, Ext.ux.Lightbox);