Nenhuma Descrição

angular-bootstrap-lightbox.js 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. /**
  2. * @namespace bootstrapLightbox
  3. */
  4. angular.module('bootstrapLightbox', [
  5. 'ui.bootstrap'
  6. ]);
  7. // optional dependencies
  8. try {
  9. angular.module('angular-loading-bar');
  10. angular.module('bootstrapLightbox').requires.push('angular-loading-bar');
  11. } catch (e) {}
  12. try {
  13. angular.module('ngTouch');
  14. angular.module('bootstrapLightbox').requires.push('ngTouch');
  15. } catch (e) {}
  16. try {
  17. angular.module('videosharing-embed');
  18. angular.module('bootstrapLightbox').requires.push('videosharing-embed');
  19. } catch (e) {}
  20. angular.module('bootstrapLightbox').run(['$templateCache', function($templateCache) {
  21. 'use strict';
  22. $templateCache.put('lightbox.html',
  23. "<div class=modal-body ng-swipe-left=Lightbox.nextImage() ng-swipe-right=Lightbox.prevImage()><div class=lightbox-nav><button class=close aria-hidden=true ng-click=$dismiss()>×</button><div class=btn-group ng-if=\"Lightbox.images.length > 1\"><a class=\"btn btn-xs btn-default\" ng-click=Lightbox.prevImage()>‹ Previous</a> <a ng-href={{Lightbox.imageUrl}} target=_blank class=\"btn btn-xs btn-default\" title=\"Open in new tab\">Open image in new tab</a> <a class=\"btn btn-xs btn-default\" ng-click=Lightbox.nextImage()>Next ›</a></div></div><div class=lightbox-image-container><div class=lightbox-image-caption><span>{{Lightbox.imageCaption}}</span></div><img ng-if=!Lightbox.isVideo(Lightbox.image) lightbox-src={{Lightbox.imageUrl}}><div ng-if=Lightbox.isVideo(Lightbox.image) class=\"embed-responsive embed-responsive-16by9\"><video ng-if=!Lightbox.isSharedVideo(Lightbox.image) lightbox-src={{Lightbox.imageUrl}} controls autoplay></video><embed-video ng-if=Lightbox.isSharedVideo(Lightbox.image) lightbox-src={{Lightbox.imageUrl}} ng-href={{Lightbox.imageUrl}} iframe-id=lightbox-video class=embed-responsive-item><a ng-href={{Lightbox.imageUrl}}>Watch video</a></embed-video></div></div></div>"
  24. );
  25. }]);
  26. /**
  27. * @class ImageLoader
  28. * @classdesc Service for loading an image.
  29. * @memberOf bootstrapLightbox
  30. */
  31. angular.module('bootstrapLightbox').service('ImageLoader', ['$q',
  32. function ($q) {
  33. /**
  34. * Load the image at the given URL.
  35. * @param {String} url
  36. * @return {Promise} A $q promise that resolves when the image has loaded
  37. * successfully.
  38. * @type {Function}
  39. * @name load
  40. * @memberOf bootstrapLightbox.ImageLoader
  41. */
  42. this.load = function (url) {
  43. var deferred = $q.defer();
  44. var image = new Image();
  45. // when the image has loaded
  46. image.onload = function () {
  47. // check image properties for possible errors
  48. if ((typeof this.complete === 'boolean' && this.complete === false) ||
  49. (typeof this.naturalWidth === 'number' && this.naturalWidth === 0)) {
  50. deferred.reject();
  51. }
  52. deferred.resolve(image);
  53. };
  54. // when the image fails to load
  55. image.onerror = function () {
  56. deferred.reject();
  57. };
  58. // start loading the image
  59. image.src = url;
  60. return deferred.promise;
  61. };
  62. }]);
  63. /**
  64. * @class Lightbox
  65. * @classdesc Lightbox service.
  66. * @memberOf bootstrapLightbox
  67. */
  68. angular.module('bootstrapLightbox').provider('Lightbox', function () {
  69. /**
  70. * Template URL passed into `$uibModal.open()`.
  71. * @type {String}
  72. * @name templateUrl
  73. * @memberOf bootstrapLightbox.Lightbox
  74. */
  75. this.templateUrl = 'lightbox.html';
  76. /**
  77. * Whether images should be scaled to the maximum possible dimensions.
  78. * @type {Boolean}
  79. * @name fullScreenMode
  80. * @memberOf bootstrapLightbox.Lightbox
  81. */
  82. this.fullScreenMode = false;
  83. /**
  84. * @param {*} image An element in the array of images.
  85. * @return {String} The URL of the given image.
  86. * @type {Function}
  87. * @name getImageUrl
  88. * @memberOf bootstrapLightbox.Lightbox
  89. */
  90. this.getImageUrl = function (image) {
  91. return typeof image === 'string' ? image : image.url;
  92. };
  93. /**
  94. * @param {*} image An element in the array of images.
  95. * @return {String} The caption of the given image.
  96. * @type {Function}
  97. * @name getImageCaption
  98. * @memberOf bootstrapLightbox.Lightbox
  99. */
  100. this.getImageCaption = function (image) {
  101. return image.caption;
  102. };
  103. /**
  104. * Calculate the max and min limits to the width and height of the displayed
  105. * image (all are optional). The max dimensions override the min
  106. * dimensions if they conflict.
  107. * @param {Object} dimensions Contains the properties `windowWidth`,
  108. * `windowHeight`, `imageWidth`, and `imageHeight`.
  109. * @return {Object} May optionally contain the properties `minWidth`,
  110. * `minHeight`, `maxWidth`, and `maxHeight`.
  111. * @type {Function}
  112. * @name calculateImageDimensionLimits
  113. * @memberOf bootstrapLightbox.Lightbox
  114. */
  115. this.calculateImageDimensionLimits = function (dimensions) {
  116. if (dimensions.windowWidth >= 768) {
  117. return {
  118. // 92px = 2 * (30px margin of .modal-dialog
  119. // + 1px border of .modal-content
  120. // + 15px padding of .modal-body)
  121. // with the goal of 30px side margins; however, the actual side margins
  122. // will be slightly less (at 22.5px) due to the vertical scrollbar
  123. 'maxWidth': dimensions.windowWidth - 92,
  124. // 126px = 92px as above
  125. // + 34px outer height of .lightbox-nav
  126. 'maxHeight': dimensions.windowHeight - 126
  127. };
  128. } else {
  129. return {
  130. // 52px = 2 * (10px margin of .modal-dialog
  131. // + 1px border of .modal-content
  132. // + 15px padding of .modal-body)
  133. 'maxWidth': dimensions.windowWidth - 52,
  134. // 86px = 52px as above
  135. // + 34px outer height of .lightbox-nav
  136. 'maxHeight': dimensions.windowHeight - 86
  137. };
  138. }
  139. };
  140. /**
  141. * Calculate the width and height of the modal. This method gets called
  142. * after the width and height of the image, as displayed inside the modal,
  143. * are calculated.
  144. * @param {Object} dimensions Contains the properties `windowWidth`,
  145. * `windowHeight`, `imageDisplayWidth`, and `imageDisplayHeight`.
  146. * @return {Object} Must contain the properties `width` and `height`.
  147. * @type {Function}
  148. * @name calculateModalDimensions
  149. * @memberOf bootstrapLightbox.Lightbox
  150. */
  151. this.calculateModalDimensions = function (dimensions) {
  152. // 400px = arbitrary min width
  153. // 32px = 2 * (1px border of .modal-content
  154. // + 15px padding of .modal-body)
  155. var width = Math.max(400, dimensions.imageDisplayWidth + 32);
  156. // 200px = arbitrary min height
  157. // 66px = 32px as above
  158. // + 34px outer height of .lightbox-nav
  159. var height = Math.max(200, dimensions.imageDisplayHeight + 66);
  160. // first case: the modal width cannot be larger than the window width
  161. // 20px = arbitrary value larger than the vertical scrollbar
  162. // width in order to avoid having a horizontal scrollbar
  163. // second case: Bootstrap modals are not centered below 768px
  164. if (width >= dimensions.windowWidth - 20 || dimensions.windowWidth < 768) {
  165. width = 'auto';
  166. }
  167. // the modal height cannot be larger than the window height
  168. if (height >= dimensions.windowHeight) {
  169. height = 'auto';
  170. }
  171. return {
  172. 'width': width,
  173. 'height': height
  174. };
  175. };
  176. /**
  177. * @param {*} image An element in the array of images.
  178. * @return {Boolean} Whether the provided element is a video.
  179. * @type {Function}
  180. * @name isVideo
  181. * @memberOf bootstrapLightbox.Lightbox
  182. */
  183. this.isVideo = function (image) {
  184. if (typeof image === 'object' && image && image.type) {
  185. return image.type === 'video';
  186. }
  187. return false;
  188. };
  189. /**
  190. * @param {*} image An element in the array of images.
  191. * @return {Boolean} Whether the provided element is a video that is to be
  192. * embedded with an external service like YouTube. By default, this is
  193. * determined by the url not ending in `.mp4`, `.ogg`, or `.webm`.
  194. * @type {Function}
  195. * @name isSharedVideo
  196. * @memberOf bootstrapLightbox.Lightbox
  197. */
  198. this.isSharedVideo = function (image) {
  199. return this.isVideo(image) &&
  200. !this.getImageUrl(image).match(/\.(mp4|ogg|webm)$/);
  201. };
  202. this.$get = ['$document', '$injector', '$uibModal', '$timeout', 'ImageLoader',
  203. function ($document, $injector, $uibModal, $timeout, ImageLoader) {
  204. // optional dependency
  205. var cfpLoadingBar = $injector.has('cfpLoadingBar') ?
  206. $injector.get('cfpLoadingBar'): null;
  207. var Lightbox = {};
  208. /**
  209. * Array of all images to be shown in the lightbox (not `Image` objects).
  210. * @type {Array}
  211. * @name images
  212. * @memberOf bootstrapLightbox.Lightbox
  213. */
  214. Lightbox.images = [];
  215. /**
  216. * The index in the `Lightbox.images` aray of the image that is currently
  217. * shown in the lightbox.
  218. * @type {Number}
  219. * @name index
  220. * @memberOf bootstrapLightbox.Lightbox
  221. */
  222. Lightbox.index = -1;
  223. // set the configurable properties and methods, the defaults of which are
  224. // defined above
  225. Lightbox.templateUrl = this.templateUrl;
  226. Lightbox.fullScreenMode = this.fullScreenMode;
  227. Lightbox.getImageUrl = this.getImageUrl;
  228. Lightbox.getImageCaption = this.getImageCaption;
  229. Lightbox.calculateImageDimensionLimits = this.calculateImageDimensionLimits;
  230. Lightbox.calculateModalDimensions = this.calculateModalDimensions;
  231. Lightbox.isVideo = this.isVideo;
  232. Lightbox.isSharedVideo = this.isSharedVideo;
  233. /**
  234. * Whether keyboard navigation is currently enabled for navigating through
  235. * images in the lightbox.
  236. * @type {Boolean}
  237. * @name keyboardNavEnabled
  238. * @memberOf bootstrapLightbox.Lightbox
  239. */
  240. Lightbox.keyboardNavEnabled = false;
  241. /**
  242. * The image currently shown in the lightbox.
  243. * @type {*}
  244. * @name image
  245. * @memberOf bootstrapLightbox.Lightbox
  246. */
  247. Lightbox.image = {};
  248. /**
  249. * The UI Bootstrap modal instance. See {@link
  250. * http://angular-ui.github.io/bootstrap/#/modal}.
  251. * @type {Object}
  252. * @name modalInstance
  253. * @memberOf bootstrapLightbox.Lightbox
  254. */
  255. Lightbox.modalInstance = null;
  256. /**
  257. * The URL of the current image. This is a property of the service rather
  258. * than of `Lightbox.image` because `Lightbox.image` need not be an
  259. * object, and besides it would be poor practice to alter the given
  260. * objects.
  261. * @type {String}
  262. * @name imageUrl
  263. * @memberOf bootstrapLightbox.Lightbox
  264. */
  265. /**
  266. * The optional caption of the current image.
  267. * @type {String}
  268. * @name imageCaption
  269. * @memberOf bootstrapLightbox.Lightbox
  270. */
  271. /**
  272. * Whether an image is currently being loaded.
  273. * @type {Boolean}
  274. * @name loading
  275. * @memberOf bootstrapLightbox.Lightbox
  276. */
  277. Lightbox.loading = false;
  278. /**
  279. * Open the lightbox modal.
  280. * @param {Array} newImages An array of images. Each image may be of
  281. * any type.
  282. * @param {Number} newIndex The index in `newImages` to set as the
  283. * current image.
  284. * @param {Object} modalParams Custom params for the angular UI
  285. * bootstrap modal (in $uibModal.open()).
  286. * @return {Object} The created UI Bootstrap modal instance.
  287. * @type {Function}
  288. * @name openModal
  289. * @memberOf bootstrapLightbox.Lightbox
  290. */
  291. Lightbox.openModal = function (newImages, newIndex, modalParams) {
  292. Lightbox.images = newImages;
  293. Lightbox.setImage(newIndex);
  294. // store the modal instance so we can close it manually if we need to
  295. Lightbox.modalInstance = $uibModal.open(angular.extend({
  296. 'templateUrl': Lightbox.templateUrl,
  297. 'controller': ['$scope', function ($scope) {
  298. // $scope is the modal scope, a child of $rootScope
  299. $scope.Lightbox = Lightbox;
  300. Lightbox.keyboardNavEnabled = true;
  301. }],
  302. 'windowClass': 'lightbox-modal'
  303. }, modalParams || {}));
  304. // modal close handler
  305. Lightbox.modalInstance.result['finally'](function () {
  306. // prevent the lightbox from flickering from the old image when it gets
  307. // opened again
  308. Lightbox.images = [];
  309. Lightbox.index = 1;
  310. Lightbox.image = {};
  311. Lightbox.imageUrl = null;
  312. Lightbox.imageCaption = null;
  313. Lightbox.keyboardNavEnabled = false;
  314. // complete any lingering loading bar progress
  315. if (cfpLoadingBar) {
  316. cfpLoadingBar.complete();
  317. }
  318. });
  319. return Lightbox.modalInstance;
  320. };
  321. /**
  322. * Close the lightbox modal.
  323. * @param {*} result This argument can be useful if the modal promise
  324. * gets handler(s) attached to it.
  325. * @type {Function}
  326. * @name closeModal
  327. * @memberOf bootstrapLightbox.Lightbox
  328. */
  329. Lightbox.closeModal = function (result) {
  330. return Lightbox.modalInstance.close(result);
  331. };
  332. /**
  333. * This method can be used in all methods which navigate/change the
  334. * current image.
  335. * @param {Number} newIndex The index in the array of images to set as
  336. * the new current image.
  337. * @type {Function}
  338. * @name setImage
  339. * @memberOf bootstrapLightbox.Lightbox
  340. */
  341. Lightbox.setImage = function (newIndex) {
  342. if (!(newIndex in Lightbox.images)) {
  343. throw 'Invalid image.';
  344. }
  345. // update the loading flag and start the loading bar
  346. Lightbox.loading = true;
  347. if (cfpLoadingBar) {
  348. cfpLoadingBar.start();
  349. }
  350. var image = Lightbox.images[newIndex];
  351. var imageUrl = Lightbox.getImageUrl(image);
  352. var success = function (properties) {
  353. // update service properties for the image
  354. properties = properties || {};
  355. Lightbox.index = properties.index || newIndex;
  356. Lightbox.image = properties.image || image;
  357. Lightbox.imageUrl = properties.imageUrl || imageUrl;
  358. Lightbox.imageCaption = properties.imageCaption ||
  359. Lightbox.getImageCaption(image);
  360. // restore the loading flag and complete the loading bar
  361. Lightbox.loading = false;
  362. if (cfpLoadingBar) {
  363. cfpLoadingBar.complete();
  364. }
  365. };
  366. if (!Lightbox.isVideo(image)) {
  367. // load the image before setting it, so everything in the view is
  368. // updated at the same time; otherwise, the previous image remains while
  369. // the current image is loading
  370. ImageLoader.load(imageUrl).then(function () {
  371. success();
  372. }, function () {
  373. success({
  374. 'imageUrl': '#', // blank image
  375. // use the caption to show the user an error
  376. 'imageCaption': 'Failed to load image'
  377. });
  378. });
  379. } else {
  380. success();
  381. }
  382. };
  383. /**
  384. * Navigate to the first image.
  385. * @type {Function}
  386. * @name firstImage
  387. * @memberOf bootstrapLightbox.Lightbox
  388. */
  389. Lightbox.firstImage = function () {
  390. Lightbox.setImage(0);
  391. };
  392. /**
  393. * Navigate to the previous image.
  394. * @type {Function}
  395. * @name prevImage
  396. * @memberOf bootstrapLightbox.Lightbox
  397. */
  398. Lightbox.prevImage = function () {
  399. Lightbox.setImage((Lightbox.index - 1 + Lightbox.images.length) %
  400. Lightbox.images.length);
  401. };
  402. /**
  403. * Navigate to the next image.
  404. * @type {Function}
  405. * @name nextImage
  406. * @memberOf bootstrapLightbox.Lightbox
  407. */
  408. Lightbox.nextImage = function () {
  409. Lightbox.setImage((Lightbox.index + 1) % Lightbox.images.length);
  410. };
  411. /**
  412. * Navigate to the last image.
  413. * @type {Function}
  414. * @name lastImage
  415. * @memberOf bootstrapLightbox.Lightbox
  416. */
  417. Lightbox.lastImage = function () {
  418. Lightbox.setImage(Lightbox.images.length - 1);
  419. };
  420. /**
  421. * Call this method to set both the array of images and the current image
  422. * (based on the current index). A use case is when the image collection
  423. * gets changed dynamically in some way while the lightbox is still
  424. * open.
  425. * @param {Array} newImages The new array of images.
  426. * @type {Function}
  427. * @name setImages
  428. * @memberOf bootstrapLightbox.Lightbox
  429. */
  430. Lightbox.setImages = function (newImages) {
  431. Lightbox.images = newImages;
  432. Lightbox.setImage(Lightbox.index);
  433. };
  434. // Bind the left and right arrow keys for image navigation. This event
  435. // handler never gets unbinded. Disable this using the `keyboardNavEnabled`
  436. // flag. It is automatically disabled when the target is an input and or a
  437. // textarea. TODO: Move this to a directive.
  438. $document.bind('keydown', function (event) {
  439. if (!Lightbox.keyboardNavEnabled) {
  440. return;
  441. }
  442. // method of Lightbox to call
  443. var method = null;
  444. switch (event.which) {
  445. case 39: // right arrow key
  446. method = 'nextImage';
  447. break;
  448. case 37: // left arrow key
  449. method = 'prevImage';
  450. break;
  451. }
  452. if (method !== null && ['input', 'textarea'].indexOf(
  453. event.target.tagName.toLowerCase()) === -1) {
  454. // the view doesn't update without a manual digest
  455. $timeout(function () {
  456. Lightbox[method]();
  457. });
  458. event.preventDefault();
  459. }
  460. });
  461. return Lightbox;
  462. }];
  463. });
  464. /**
  465. * @class lightboxSrc
  466. * @classdesc This attribute directive is used in an `<img>` element in the
  467. * modal template in place of `src`. It handles resizing both the `<img>`
  468. * element and its relevant parent elements within the modal.
  469. * @memberOf bootstrapLightbox
  470. */
  471. angular.module('bootstrapLightbox').directive('lightboxSrc', ['$window',
  472. 'ImageLoader', 'Lightbox', function ($window, ImageLoader, Lightbox) {
  473. // Calculate the dimensions to display the image. The max dimensions override
  474. // the min dimensions if they conflict.
  475. var calculateImageDisplayDimensions = function (dimensions, fullScreenMode) {
  476. var w = dimensions.width;
  477. var h = dimensions.height;
  478. var minW = dimensions.minWidth;
  479. var minH = dimensions.minHeight;
  480. var maxW = dimensions.maxWidth;
  481. var maxH = dimensions.maxHeight;
  482. var displayW = w;
  483. var displayH = h;
  484. if (!fullScreenMode) {
  485. // resize the image if it is too small
  486. if (w < minW && h < minH) {
  487. // the image is both too thin and short, so compare the aspect ratios to
  488. // determine whether to min the width or height
  489. if (w / h > maxW / maxH) {
  490. displayH = minH;
  491. displayW = Math.round(w * minH / h);
  492. } else {
  493. displayW = minW;
  494. displayH = Math.round(h * minW / w);
  495. }
  496. } else if (w < minW) {
  497. // the image is too thin
  498. displayW = minW;
  499. displayH = Math.round(h * minW / w);
  500. } else if (h < minH) {
  501. // the image is too short
  502. displayH = minH;
  503. displayW = Math.round(w * minH / h);
  504. }
  505. // resize the image if it is too large
  506. if (w > maxW && h > maxH) {
  507. // the image is both too tall and wide, so compare the aspect ratios
  508. // to determine whether to max the width or height
  509. if (w / h > maxW / maxH) {
  510. displayW = maxW;
  511. displayH = Math.round(h * maxW / w);
  512. } else {
  513. displayH = maxH;
  514. displayW = Math.round(w * maxH / h);
  515. }
  516. } else if (w > maxW) {
  517. // the image is too wide
  518. displayW = maxW;
  519. displayH = Math.round(h * maxW / w);
  520. } else if (h > maxH) {
  521. // the image is too tall
  522. displayH = maxH;
  523. displayW = Math.round(w * maxH / h);
  524. }
  525. } else {
  526. // full screen mode
  527. var ratio = Math.min(maxW / w, maxH / h);
  528. var zoomedW = Math.round(w * ratio);
  529. var zoomedH = Math.round(h * ratio);
  530. displayW = Math.max(minW, zoomedW);
  531. displayH = Math.max(minH, zoomedH);
  532. }
  533. return {
  534. 'width': displayW || 0,
  535. 'height': displayH || 0 // NaN is possible when dimensions.width is 0
  536. };
  537. };
  538. // format the given dimension for passing into the `css()` method of `jqLite`
  539. var formatDimension = function (dimension) {
  540. return typeof dimension === 'number' ? dimension + 'px' : dimension;
  541. };
  542. // the dimensions of the image
  543. var imageWidth = 0;
  544. var imageHeight = 0;
  545. return {
  546. 'link': function (scope, element, attrs) {
  547. // resize the img element and the containing modal
  548. var resize = function () {
  549. // get the window dimensions
  550. var windowWidth = $window.innerWidth;
  551. var windowHeight = $window.innerHeight;
  552. // calculate the max/min dimensions for the image
  553. var imageDimensionLimits = Lightbox.calculateImageDimensionLimits({
  554. 'windowWidth': windowWidth,
  555. 'windowHeight': windowHeight,
  556. 'imageWidth': imageWidth,
  557. 'imageHeight': imageHeight
  558. });
  559. // calculate the dimensions to display the image
  560. var imageDisplayDimensions = calculateImageDisplayDimensions(
  561. angular.extend({
  562. 'width': imageWidth,
  563. 'height': imageHeight,
  564. 'minWidth': 1,
  565. 'minHeight': 1,
  566. 'maxWidth': 3000,
  567. 'maxHeight': 3000,
  568. }, imageDimensionLimits),
  569. Lightbox.fullScreenMode
  570. );
  571. // calculate the dimensions of the modal container
  572. var modalDimensions = Lightbox.calculateModalDimensions({
  573. 'windowWidth': windowWidth,
  574. 'windowHeight': windowHeight,
  575. 'imageDisplayWidth': imageDisplayDimensions.width,
  576. 'imageDisplayHeight': imageDisplayDimensions.height
  577. });
  578. // resize the image
  579. element.css({
  580. 'width': imageDisplayDimensions.width + 'px',
  581. 'height': imageDisplayDimensions.height + 'px'
  582. });
  583. // setting the height on .modal-dialog does not expand the div with the
  584. // background, which is .modal-content
  585. angular.element(
  586. document.querySelector('.lightbox-modal .modal-dialog')
  587. ).css({
  588. 'width': formatDimension(modalDimensions.width)
  589. });
  590. // .modal-content has no width specified; if we set the width on
  591. // .modal-content and not on .modal-dialog, .modal-dialog retains its
  592. // default width of 600px and that places .modal-content off center
  593. angular.element(
  594. document.querySelector('.lightbox-modal .modal-content')
  595. ).css({
  596. 'height': formatDimension(modalDimensions.height)
  597. });
  598. };
  599. // load the new image and/or resize the video whenever the attr changes
  600. scope.$watch(function () {
  601. return attrs.lightboxSrc;
  602. }, function (src) {
  603. // do nothing if there's no image
  604. if (!Lightbox.image) {
  605. return;
  606. }
  607. if (!Lightbox.isVideo(Lightbox.image)) { // image
  608. // blank the image before resizing the element
  609. element[0].src = '#';
  610. // handle failure to load the image
  611. var failure = function () {
  612. imageWidth = 0;
  613. imageHeight = 0;
  614. resize();
  615. };
  616. if (src) {
  617. ImageLoader.load(src).then(function (image) {
  618. // these variables must be set before resize(), as they are used
  619. // in it
  620. imageWidth = image.naturalWidth;
  621. imageHeight = image.naturalHeight;
  622. // resize the img element and the containing modal
  623. resize();
  624. // show the image
  625. element[0].src = src;
  626. }, failure);
  627. } else {
  628. failure();
  629. }
  630. } else { // video
  631. // default dimensions
  632. imageWidth = 1280;
  633. imageHeight = 720;
  634. // resize the video element and the containing modal
  635. resize();
  636. // the src attribute applies to `<video>` and not `<embed-video>`
  637. element[0].src = src;
  638. }
  639. });
  640. // resize the image and modal whenever the window gets resized
  641. angular.element($window).on('resize', resize);
  642. }
  643. };
  644. }]);