ngx-bootstrap-carousel.js 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013
  1. import { Injectable, EventEmitter, Component, NgZone, Input, Output, HostBinding, NgModule } from '@angular/core';
  2. import { LinkedList, isBs3 } from 'ngx-bootstrap/utils';
  3. import { CommonModule } from '@angular/common';
  4. /**
  5. * @fileoverview added by tsickle
  6. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  7. */
  8. class CarouselConfig {
  9. constructor() {
  10. /* Default interval of auto changing of slides */
  11. this.interval = 5000;
  12. /* Is loop of auto changing of slides can be paused */
  13. this.noPause = false;
  14. /* Is slides can wrap from the last to the first slide */
  15. this.noWrap = false;
  16. /* Show carousel-indicators */
  17. this.showIndicators = true;
  18. /* Slides can be paused on focus */
  19. this.pauseOnFocus = false;
  20. /* If `true` - carousel indicators indicate slides chunks works ONLY if singleSlideOffset = FALSE */
  21. this.indicatorsByChunk = false;
  22. /* If value more then 1 — carousel works in multilist mode */
  23. this.itemsPerSlide = 1;
  24. /* If `true` — carousel shifts by one element. By default carousel shifts by number
  25. of visible elements (itemsPerSlide field) */
  26. this.singleSlideOffset = false;
  27. }
  28. }
  29. CarouselConfig.decorators = [
  30. { type: Injectable }
  31. ];
  32. /**
  33. * @fileoverview added by tsickle
  34. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  35. */
  36. /**
  37. * Returns the index of the last element in the array where predicate is true, and -1
  38. * otherwise.
  39. * @template T
  40. * @param {?} array The source array to search in
  41. * @param {?} predicate find calls predicate once for each element of the array, in descending
  42. * order, until it finds one where predicate returns true. If such an element is found,
  43. * findLastIndex immediately returns that element index. Otherwise, findLastIndex returns -1.
  44. * @return {?}
  45. */
  46. function findLastIndex(array, predicate) {
  47. /** @type {?} */
  48. let l = array.length;
  49. while (l--) {
  50. if (predicate(array[l], l, array)) {
  51. return l;
  52. }
  53. }
  54. return -1;
  55. }
  56. /**
  57. * @template T
  58. * @param {?} array
  59. * @param {?} size
  60. * @return {?}
  61. */
  62. function chunkByNumber(array, size) {
  63. /** @type {?} */
  64. const out = [];
  65. /** @type {?} */
  66. const n = Math.ceil((array.length) / size);
  67. /** @type {?} */
  68. let i = 0;
  69. while (i < n) {
  70. /** @type {?} */
  71. const chunk = array.splice(0, (i === n - 1) && size < array.length ? array.length : size);
  72. out.push(chunk);
  73. i++;
  74. }
  75. return out;
  76. }
  77. /**
  78. * @fileoverview added by tsickle
  79. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  80. */
  81. /** @enum {number} */
  82. const Direction = {
  83. UNKNOWN: 0,
  84. NEXT: 1,
  85. PREV: 2,
  86. };
  87. Direction[Direction.UNKNOWN] = 'UNKNOWN';
  88. Direction[Direction.NEXT] = 'NEXT';
  89. Direction[Direction.PREV] = 'PREV';
  90. /**
  91. * Base element to create carousel
  92. */
  93. class CarouselComponent {
  94. /**
  95. * @param {?} config
  96. * @param {?} ngZone
  97. */
  98. constructor(config, ngZone) {
  99. this.ngZone = ngZone;
  100. /* If `true` - carousel indicators indicate slides chunks
  101. works ONLY if singleSlideOffset = FALSE */
  102. this.indicatorsByChunk = false;
  103. /* If value more then 1 — carousel works in multilist mode */
  104. this.itemsPerSlide = 1;
  105. /* If `true` — carousel shifts by one element. By default carousel shifts by number
  106. of visible elements (itemsPerSlide field) */
  107. this.singleSlideOffset = false;
  108. /**
  109. * Will be emitted when active slide has been changed. Part of two-way-bindable [(activeSlide)] property
  110. */
  111. this.activeSlideChange = new EventEmitter(false);
  112. /**
  113. * Will be emitted when active slides has been changed in multilist mode
  114. */
  115. this.slideRangeChange = new EventEmitter();
  116. /* Index to start display slides from it */
  117. this.startFromIndex = 0;
  118. this._slides = new LinkedList();
  119. this._currentVisibleSlidesIndex = 0;
  120. this.destroyed = false;
  121. this.getActive = (/**
  122. * @param {?} slide
  123. * @return {?}
  124. */
  125. (slide) => slide.active);
  126. this.makeSlidesConsistent = (/**
  127. * @param {?} slides
  128. * @return {?}
  129. */
  130. (slides) => {
  131. slides.forEach((/**
  132. * @param {?} slide
  133. * @param {?} index
  134. * @return {?}
  135. */
  136. (slide, index) => slide.item.order = index));
  137. });
  138. Object.assign(this, config);
  139. }
  140. /**
  141. * Index of currently displayed slide(started for 0)
  142. * @param {?} index
  143. * @return {?}
  144. */
  145. set activeSlide(index) {
  146. if (this.multilist) {
  147. return;
  148. }
  149. if (this._slides.length && index !== this._currentActiveSlide) {
  150. this._select(index);
  151. }
  152. }
  153. /**
  154. * @return {?}
  155. */
  156. get activeSlide() {
  157. return this._currentActiveSlide;
  158. }
  159. /**
  160. * Delay of item cycling in milliseconds. If false, carousel won't cycle
  161. * automatically.
  162. * @return {?}
  163. */
  164. get interval() {
  165. return this._interval;
  166. }
  167. /**
  168. * @param {?} value
  169. * @return {?}
  170. */
  171. set interval(value) {
  172. this._interval = value;
  173. this.restartTimer();
  174. }
  175. /**
  176. * @return {?}
  177. */
  178. get slides() {
  179. return this._slides.toArray();
  180. }
  181. /**
  182. * @return {?}
  183. */
  184. get isBs4() {
  185. return !isBs3();
  186. }
  187. /**
  188. * @return {?}
  189. */
  190. ngAfterViewInit() {
  191. setTimeout((/**
  192. * @return {?}
  193. */
  194. () => {
  195. if (this.singleSlideOffset) {
  196. this.indicatorsByChunk = false;
  197. }
  198. if (this.multilist) {
  199. this._chunkedSlides = chunkByNumber(this.mapSlidesAndIndexes(), this.itemsPerSlide);
  200. this.selectInitialSlides();
  201. }
  202. }), 0);
  203. }
  204. /**
  205. * @return {?}
  206. */
  207. ngOnDestroy() {
  208. this.destroyed = true;
  209. }
  210. /**
  211. * Adds new slide. If this slide is first in collection - set it as active
  212. * and starts auto changing
  213. * @param {?} slide
  214. * @return {?}
  215. */
  216. addSlide(slide) {
  217. this._slides.add(slide);
  218. if (this.multilist && this._slides.length <= this.itemsPerSlide) {
  219. slide.active = true;
  220. }
  221. if (!this.multilist && this._slides.length === 1) {
  222. this._currentActiveSlide = undefined;
  223. this.activeSlide = 0;
  224. this.play();
  225. }
  226. if (this.multilist && this._slides.length > this.itemsPerSlide) {
  227. this.play();
  228. }
  229. }
  230. /**
  231. * Removes specified slide. If this slide is active - will roll to another
  232. * slide
  233. * @param {?} slide
  234. * @return {?}
  235. */
  236. removeSlide(slide) {
  237. /** @type {?} */
  238. const remIndex = this._slides.indexOf(slide);
  239. if (this._currentActiveSlide === remIndex) {
  240. // removing of active slide
  241. /** @type {?} */
  242. let nextSlideIndex = void 0;
  243. if (this._slides.length > 1) {
  244. // if this slide last - will roll to first slide, if noWrap flag is
  245. // FALSE or to previous, if noWrap is TRUE in case, if this slide in
  246. // middle of collection, index of next slide is same to removed
  247. nextSlideIndex = !this.isLast(remIndex)
  248. ? remIndex
  249. : this.noWrap ? remIndex - 1 : 0;
  250. }
  251. this._slides.remove(remIndex);
  252. // prevents exception with changing some value after checking
  253. setTimeout((/**
  254. * @return {?}
  255. */
  256. () => {
  257. this._select(nextSlideIndex);
  258. }), 0);
  259. }
  260. else {
  261. this._slides.remove(remIndex);
  262. /** @type {?} */
  263. const currentSlideIndex = this.getCurrentSlideIndex();
  264. setTimeout((/**
  265. * @return {?}
  266. */
  267. () => {
  268. // after removing, need to actualize index of current active slide
  269. this._currentActiveSlide = currentSlideIndex;
  270. this.activeSlideChange.emit(this._currentActiveSlide);
  271. }), 0);
  272. }
  273. }
  274. /**
  275. * @param {?=} force
  276. * @return {?}
  277. */
  278. nextSlideFromInterval(force = false) {
  279. this.move(Direction.NEXT, force);
  280. }
  281. /**
  282. * Rolling to next slide
  283. * @param {?=} force
  284. * @return {?}
  285. */
  286. nextSlide(force = false) {
  287. if (this.isPlaying) {
  288. this.restartTimer();
  289. }
  290. this.move(Direction.NEXT, force);
  291. }
  292. /**
  293. * Rolling to previous slide
  294. * @param {?=} force
  295. * @return {?}
  296. */
  297. previousSlide(force = false) {
  298. if (this.isPlaying) {
  299. this.restartTimer();
  300. }
  301. this.move(Direction.PREV, force);
  302. }
  303. /**
  304. * @return {?}
  305. */
  306. getFirstVisibleIndex() {
  307. return this.slides.findIndex(this.getActive);
  308. }
  309. /**
  310. * @return {?}
  311. */
  312. getLastVisibleIndex() {
  313. return findLastIndex(this.slides, this.getActive);
  314. }
  315. /**
  316. * @param {?} direction
  317. * @param {?=} force
  318. * @return {?}
  319. */
  320. move(direction, force = false) {
  321. /** @type {?} */
  322. const firstVisibleIndex = this.getFirstVisibleIndex();
  323. /** @type {?} */
  324. const lastVisibleIndex = this.getLastVisibleIndex();
  325. if (this.noWrap) {
  326. if (direction === Direction.NEXT &&
  327. this.isLast(lastVisibleIndex) ||
  328. direction === Direction.PREV &&
  329. firstVisibleIndex === 0) {
  330. return;
  331. }
  332. }
  333. if (!this.multilist) {
  334. this.activeSlide = this.findNextSlideIndex(direction, force);
  335. }
  336. else {
  337. this.moveMultilist(direction);
  338. }
  339. }
  340. /**
  341. * Swith slides by enter, space and arrows keys
  342. * \@internal
  343. * @param {?} event
  344. * @return {?}
  345. */
  346. keydownPress(event) {
  347. // tslint:disable-next-line:deprecation
  348. if (event.keyCode === 13 || event.key === 'Enter' || event.keyCode === 32 || event.key === 'Space') {
  349. this.nextSlide();
  350. event.preventDefault();
  351. return;
  352. }
  353. // tslint:disable-next-line:deprecation
  354. if (event.keyCode === 37 || event.key === 'LeftArrow') {
  355. this.previousSlide();
  356. return;
  357. }
  358. // tslint:disable-next-line:deprecation
  359. if (event.keyCode === 39 || event.key === 'RightArrow') {
  360. this.nextSlide();
  361. return;
  362. }
  363. }
  364. /**
  365. * Play on mouse leave
  366. * \@internal
  367. * @return {?}
  368. */
  369. onMouseLeave() {
  370. if (!this.pauseOnFocus) {
  371. this.play();
  372. }
  373. }
  374. /**
  375. * Play on mouse up
  376. * \@internal
  377. * @return {?}
  378. */
  379. onMouseUp() {
  380. if (!this.pauseOnFocus) {
  381. this.play();
  382. }
  383. }
  384. /**
  385. * When slides on focus autoplay is stopped(optional)
  386. * \@internal
  387. * @return {?}
  388. */
  389. pauseFocusIn() {
  390. if (this.pauseOnFocus) {
  391. this.isPlaying = false;
  392. this.resetTimer();
  393. }
  394. }
  395. /**
  396. * When slides out of focus autoplay is started
  397. * \@internal
  398. * @return {?}
  399. */
  400. pauseFocusOut() {
  401. this.play();
  402. }
  403. /**
  404. * Rolling to specified slide
  405. * @param {?} index
  406. * @return {?}
  407. */
  408. selectSlide(index) {
  409. if (this.isPlaying) {
  410. this.restartTimer();
  411. }
  412. if (!this.multilist) {
  413. this.activeSlide = this.indicatorsByChunk ? index * this.itemsPerSlide : index;
  414. }
  415. else {
  416. this.selectSlideRange(this.indicatorsByChunk ? index * this.itemsPerSlide : index);
  417. }
  418. }
  419. /**
  420. * Starts a auto changing of slides
  421. * @return {?}
  422. */
  423. play() {
  424. if (!this.isPlaying) {
  425. this.isPlaying = true;
  426. this.restartTimer();
  427. }
  428. }
  429. /**
  430. * Stops a auto changing of slides
  431. * @return {?}
  432. */
  433. pause() {
  434. if (!this.noPause) {
  435. this.isPlaying = false;
  436. this.resetTimer();
  437. }
  438. }
  439. /**
  440. * Finds and returns index of currently displayed slide
  441. * @return {?}
  442. */
  443. getCurrentSlideIndex() {
  444. return this._slides.findIndex(this.getActive);
  445. }
  446. /**
  447. * Defines, whether the specified index is last in collection
  448. * @param {?} index
  449. * @return {?}
  450. */
  451. isLast(index) {
  452. return index + 1 >= this._slides.length;
  453. }
  454. /**
  455. * Defines, whether the specified index is first in collection
  456. * @param {?} index
  457. * @return {?}
  458. */
  459. isFirst(index) {
  460. return index === 0;
  461. }
  462. /**
  463. * @return {?}
  464. */
  465. indicatorsSlides() {
  466. return this.slides.filter((/**
  467. * @param {?} slide
  468. * @param {?} index
  469. * @return {?}
  470. */
  471. (slide, index) => !this.indicatorsByChunk || index % this.itemsPerSlide === 0));
  472. }
  473. /**
  474. * @private
  475. * @return {?}
  476. */
  477. selectInitialSlides() {
  478. /** @type {?} */
  479. const startIndex = this.startFromIndex <= this._slides.length
  480. ? this.startFromIndex
  481. : 0;
  482. this.hideSlides();
  483. if (this.singleSlideOffset) {
  484. this._slidesWithIndexes = this.mapSlidesAndIndexes();
  485. if (this._slides.length - startIndex < this.itemsPerSlide) {
  486. /** @type {?} */
  487. const slidesToAppend = this._slidesWithIndexes.slice(0, startIndex);
  488. this._slidesWithIndexes = [
  489. ...this._slidesWithIndexes,
  490. ...slidesToAppend
  491. ]
  492. .slice(slidesToAppend.length)
  493. .slice(0, this.itemsPerSlide);
  494. }
  495. else {
  496. this._slidesWithIndexes = this._slidesWithIndexes.slice(startIndex, startIndex + this.itemsPerSlide);
  497. }
  498. this._slidesWithIndexes.forEach((/**
  499. * @param {?} slide
  500. * @return {?}
  501. */
  502. (slide) => slide.item.active = true));
  503. this.makeSlidesConsistent(this._slidesWithIndexes);
  504. }
  505. else {
  506. this.selectRangeByNestedIndex(startIndex);
  507. }
  508. this.slideRangeChange.emit(this.getVisibleIndexes());
  509. }
  510. /**
  511. * Defines next slide index, depending of direction
  512. * @private
  513. * @param {?} direction
  514. * @param {?} force
  515. * @return {?}
  516. */
  517. findNextSlideIndex(direction, force) {
  518. /** @type {?} */
  519. let nextSlideIndex = 0;
  520. if (!force &&
  521. (this.isLast(this.activeSlide) &&
  522. direction !== Direction.PREV &&
  523. this.noWrap)) {
  524. return undefined;
  525. }
  526. switch (direction) {
  527. case Direction.NEXT:
  528. // if this is last slide, not force, looping is disabled
  529. // and need to going forward - select current slide, as a next
  530. nextSlideIndex = !this.isLast(this._currentActiveSlide)
  531. ? this._currentActiveSlide + 1
  532. : !force && this.noWrap ? this._currentActiveSlide : 0;
  533. break;
  534. case Direction.PREV:
  535. // if this is first slide, not force, looping is disabled
  536. // and need to going backward - select current slide, as a next
  537. nextSlideIndex =
  538. this._currentActiveSlide > 0
  539. ? this._currentActiveSlide - 1
  540. : !force && this.noWrap
  541. ? this._currentActiveSlide
  542. : this._slides.length - 1;
  543. break;
  544. default:
  545. throw new Error('Unknown direction');
  546. }
  547. return nextSlideIndex;
  548. }
  549. /**
  550. * @private
  551. * @return {?}
  552. */
  553. mapSlidesAndIndexes() {
  554. return this.slides
  555. .slice()
  556. .map((/**
  557. * @param {?} slide
  558. * @param {?} index
  559. * @return {?}
  560. */
  561. (slide, index) => {
  562. return {
  563. index,
  564. item: slide
  565. };
  566. }));
  567. }
  568. /**
  569. * @private
  570. * @param {?} index
  571. * @return {?}
  572. */
  573. selectSlideRange(index) {
  574. if (this.isIndexInRange(index)) {
  575. return;
  576. }
  577. this.hideSlides();
  578. if (!this.singleSlideOffset) {
  579. this.selectRangeByNestedIndex(index);
  580. }
  581. else {
  582. /** @type {?} */
  583. const startIndex = this.isIndexOnTheEdges(index)
  584. ? index
  585. : index - this.itemsPerSlide + 1;
  586. /** @type {?} */
  587. const endIndex = this.isIndexOnTheEdges(index)
  588. ? index + this.itemsPerSlide
  589. : index + 1;
  590. this._slidesWithIndexes = this.mapSlidesAndIndexes().slice(startIndex, endIndex);
  591. this.makeSlidesConsistent(this._slidesWithIndexes);
  592. this._slidesWithIndexes.forEach((/**
  593. * @param {?} slide
  594. * @return {?}
  595. */
  596. (slide) => slide.item.active = true));
  597. }
  598. this.slideRangeChange.emit(this.getVisibleIndexes());
  599. }
  600. /**
  601. * @private
  602. * @param {?} index
  603. * @return {?}
  604. */
  605. selectRangeByNestedIndex(index) {
  606. /** @type {?} */
  607. const selectedRange = this._chunkedSlides
  608. .map((/**
  609. * @param {?} slidesList
  610. * @param {?} i
  611. * @return {?}
  612. */
  613. (slidesList, i) => {
  614. return {
  615. index: i,
  616. list: slidesList
  617. };
  618. }))
  619. .find((/**
  620. * @param {?} slidesList
  621. * @return {?}
  622. */
  623. (slidesList) => {
  624. return slidesList.list.find((/**
  625. * @param {?} slide
  626. * @return {?}
  627. */
  628. slide => slide.index === index)) !== undefined;
  629. }));
  630. this._currentVisibleSlidesIndex = selectedRange.index;
  631. this._chunkedSlides[selectedRange.index].forEach((/**
  632. * @param {?} slide
  633. * @return {?}
  634. */
  635. (slide) => {
  636. slide.item.active = true;
  637. }));
  638. }
  639. /**
  640. * @private
  641. * @param {?} index
  642. * @return {?}
  643. */
  644. isIndexOnTheEdges(index) {
  645. return (index + 1 - this.itemsPerSlide <= 0 ||
  646. index + this.itemsPerSlide <= this._slides.length);
  647. }
  648. /**
  649. * @private
  650. * @param {?} index
  651. * @return {?}
  652. */
  653. isIndexInRange(index) {
  654. if (this.singleSlideOffset) {
  655. /** @type {?} */
  656. const visibleIndexes = this._slidesWithIndexes.map((/**
  657. * @param {?} slide
  658. * @return {?}
  659. */
  660. (slide) => slide.index));
  661. return visibleIndexes.indexOf(index) >= 0;
  662. }
  663. return (index <= this.getLastVisibleIndex() &&
  664. index >= this.getFirstVisibleIndex());
  665. }
  666. /**
  667. * @private
  668. * @return {?}
  669. */
  670. hideSlides() {
  671. this.slides.forEach((/**
  672. * @param {?} slide
  673. * @return {?}
  674. */
  675. (slide) => slide.active = false));
  676. }
  677. /**
  678. * @private
  679. * @return {?}
  680. */
  681. isVisibleSlideListLast() {
  682. return this._currentVisibleSlidesIndex === this._chunkedSlides.length - 1;
  683. }
  684. /**
  685. * @private
  686. * @return {?}
  687. */
  688. isVisibleSlideListFirst() {
  689. return this._currentVisibleSlidesIndex === 0;
  690. }
  691. /**
  692. * @private
  693. * @param {?} direction
  694. * @return {?}
  695. */
  696. moveSliderByOneItem(direction) {
  697. /** @type {?} */
  698. let firstVisibleIndex;
  699. /** @type {?} */
  700. let lastVisibleIndex;
  701. /** @type {?} */
  702. let indexToHide;
  703. /** @type {?} */
  704. let indexToShow;
  705. if (this.noWrap) {
  706. firstVisibleIndex = this.getFirstVisibleIndex();
  707. lastVisibleIndex = this.getLastVisibleIndex();
  708. indexToHide = direction === Direction.NEXT
  709. ? firstVisibleIndex
  710. : lastVisibleIndex;
  711. indexToShow = direction !== Direction.NEXT
  712. ? firstVisibleIndex - 1
  713. : !this.isLast(lastVisibleIndex)
  714. ? lastVisibleIndex + 1 : 0;
  715. this._slides.get(indexToHide).active = false;
  716. this._slides.get(indexToShow).active = true;
  717. /** @type {?} */
  718. const slidesToReorder = this.mapSlidesAndIndexes().filter((/**
  719. * @param {?} slide
  720. * @return {?}
  721. */
  722. (slide) => slide.item.active));
  723. this.makeSlidesConsistent(slidesToReorder);
  724. this.slideRangeChange.emit(this.getVisibleIndexes());
  725. }
  726. else {
  727. /** @type {?} */
  728. let displayedIndex;
  729. firstVisibleIndex = this._slidesWithIndexes[0].index;
  730. lastVisibleIndex = this._slidesWithIndexes[this._slidesWithIndexes.length - 1].index;
  731. if (direction === Direction.NEXT) {
  732. this._slidesWithIndexes.shift();
  733. displayedIndex = this.isLast(lastVisibleIndex)
  734. ? 0
  735. : lastVisibleIndex + 1;
  736. this._slidesWithIndexes.push({
  737. index: displayedIndex,
  738. item: this._slides.get(displayedIndex)
  739. });
  740. }
  741. else {
  742. this._slidesWithIndexes.pop();
  743. displayedIndex = this.isFirst(firstVisibleIndex)
  744. ? this._slides.length - 1
  745. : firstVisibleIndex - 1;
  746. this._slidesWithIndexes = [{
  747. index: displayedIndex,
  748. item: this._slides.get(displayedIndex)
  749. }, ...this._slidesWithIndexes];
  750. }
  751. this.hideSlides();
  752. this._slidesWithIndexes.forEach((/**
  753. * @param {?} slide
  754. * @return {?}
  755. */
  756. slide => slide.item.active = true));
  757. this.makeSlidesConsistent(this._slidesWithIndexes);
  758. this.slideRangeChange.emit(this._slidesWithIndexes.map((/**
  759. * @param {?} slide
  760. * @return {?}
  761. */
  762. (slide) => slide.index)));
  763. }
  764. }
  765. /**
  766. * @private
  767. * @param {?} direction
  768. * @return {?}
  769. */
  770. moveMultilist(direction) {
  771. if (this.singleSlideOffset) {
  772. this.moveSliderByOneItem(direction);
  773. }
  774. else {
  775. this.hideSlides();
  776. if (this.noWrap) {
  777. this._currentVisibleSlidesIndex = direction === Direction.NEXT
  778. ? this._currentVisibleSlidesIndex + 1
  779. : this._currentVisibleSlidesIndex - 1;
  780. }
  781. else {
  782. if (direction === Direction.NEXT) {
  783. this._currentVisibleSlidesIndex = this.isVisibleSlideListLast()
  784. ? 0
  785. : this._currentVisibleSlidesIndex + 1;
  786. }
  787. else {
  788. this._currentVisibleSlidesIndex = this.isVisibleSlideListFirst()
  789. ? this._chunkedSlides.length - 1
  790. : this._currentVisibleSlidesIndex - 1;
  791. }
  792. }
  793. this._chunkedSlides[this._currentVisibleSlidesIndex].forEach((/**
  794. * @param {?} slide
  795. * @return {?}
  796. */
  797. (slide) => slide.item.active = true));
  798. this.slideRangeChange.emit(this.getVisibleIndexes());
  799. }
  800. }
  801. /**
  802. * @private
  803. * @return {?}
  804. */
  805. getVisibleIndexes() {
  806. if (!this.singleSlideOffset) {
  807. return this._chunkedSlides[this._currentVisibleSlidesIndex]
  808. .map((/**
  809. * @param {?} slide
  810. * @return {?}
  811. */
  812. (slide) => slide.index));
  813. }
  814. else {
  815. return this._slidesWithIndexes.map((/**
  816. * @param {?} slide
  817. * @return {?}
  818. */
  819. (slide) => slide.index));
  820. }
  821. }
  822. /**
  823. * Sets a slide, which specified through index, as active
  824. * @private
  825. * @param {?} index
  826. * @return {?}
  827. */
  828. _select(index) {
  829. if (isNaN(index)) {
  830. this.pause();
  831. return;
  832. }
  833. if (!this.multilist) {
  834. /** @type {?} */
  835. const currentSlide = this._slides.get(this._currentActiveSlide);
  836. if (currentSlide) {
  837. currentSlide.active = false;
  838. }
  839. }
  840. /** @type {?} */
  841. const nextSlide = this._slides.get(index);
  842. if (nextSlide) {
  843. this._currentActiveSlide = index;
  844. nextSlide.active = true;
  845. this.activeSlide = index;
  846. this.activeSlideChange.emit(index);
  847. }
  848. }
  849. /**
  850. * Starts loop of auto changing of slides
  851. * @private
  852. * @return {?}
  853. */
  854. restartTimer() {
  855. this.resetTimer();
  856. /** @type {?} */
  857. const interval = +this.interval;
  858. if (!isNaN(interval) && interval > 0) {
  859. this.currentInterval = this.ngZone.runOutsideAngular((/**
  860. * @return {?}
  861. */
  862. () => {
  863. return setInterval((/**
  864. * @return {?}
  865. */
  866. () => {
  867. /** @type {?} */
  868. const nInterval = +this.interval;
  869. this.ngZone.run((/**
  870. * @return {?}
  871. */
  872. () => {
  873. if (this.isPlaying &&
  874. !isNaN(this.interval) &&
  875. nInterval > 0 &&
  876. this.slides.length) {
  877. this.nextSlideFromInterval();
  878. }
  879. else {
  880. this.pause();
  881. }
  882. }));
  883. }), interval);
  884. }));
  885. }
  886. }
  887. /**
  888. * @return {?}
  889. */
  890. get multilist() {
  891. return this.itemsPerSlide > 1;
  892. }
  893. /**
  894. * Stops loop of auto changing of slides
  895. * @private
  896. * @return {?}
  897. */
  898. resetTimer() {
  899. if (this.currentInterval) {
  900. clearInterval(this.currentInterval);
  901. this.currentInterval = void 0;
  902. }
  903. }
  904. }
  905. CarouselComponent.decorators = [
  906. { type: Component, args: [{
  907. selector: 'carousel',
  908. template: "<div (mouseenter)=\"pause()\" (mouseleave)=\"onMouseLeave()\" (mouseup)=\"onMouseUp()\" class=\"carousel slide\" (keydown)=\"keydownPress($event)\" (focusin)=\"pauseFocusIn()\" (focusout)=\"pauseFocusOut()\" tabindex=\"0\">\n <ol class=\"carousel-indicators\" *ngIf=\"showIndicators && slides.length > 1\">\n <li *ngFor=\"let slidez of indicatorsSlides(); let i = index;\" [class.active]=\"slidez.active === true\" (click)=\"selectSlide(i)\"></li>\n </ol>\n <div class=\"carousel-inner\" [ngStyle]=\"{'display': multilist ? 'flex' : 'block'}\"><ng-content></ng-content></div>\n <a class=\"left carousel-control carousel-control-prev\" [class.disabled]=\"activeSlide === 0 && noWrap\" (click)=\"previousSlide()\" *ngIf=\"slides.length > 1\"\n tabindex=\"0\" role=\"button\">\n <span class=\"icon-prev carousel-control-prev-icon\" aria-hidden=\"true\"></span>\n <span *ngIf=\"isBs4\" class=\"sr-only\">Previous</span>\n </a>\n <a class=\"right carousel-control carousel-control-next\" (click)=\"nextSlide()\" [class.disabled]=\"isLast(activeSlide) && noWrap\" *ngIf=\"slides.length > 1\"\n tabindex=\"0\" role=\"button\">\n <span class=\"icon-next carousel-control-next-icon\" aria-hidden=\"true\"></span>\n <span class=\"sr-only\">Next</span>\n </a>\n</div>\n"
  909. }] }
  910. ];
  911. /** @nocollapse */
  912. CarouselComponent.ctorParameters = () => [
  913. { type: CarouselConfig },
  914. { type: NgZone }
  915. ];
  916. CarouselComponent.propDecorators = {
  917. noWrap: [{ type: Input }],
  918. noPause: [{ type: Input }],
  919. showIndicators: [{ type: Input }],
  920. pauseOnFocus: [{ type: Input }],
  921. indicatorsByChunk: [{ type: Input }],
  922. itemsPerSlide: [{ type: Input }],
  923. singleSlideOffset: [{ type: Input }],
  924. activeSlideChange: [{ type: Output }],
  925. slideRangeChange: [{ type: Output }],
  926. activeSlide: [{ type: Input }],
  927. startFromIndex: [{ type: Input }],
  928. interval: [{ type: Input }]
  929. };
  930. /**
  931. * @fileoverview added by tsickle
  932. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  933. */
  934. class SlideComponent {
  935. /**
  936. * @param {?} carousel
  937. */
  938. constructor(carousel) {
  939. this.itemWidth = '100%';
  940. this.order = 0;
  941. /**
  942. * Wraps element by appropriate CSS classes
  943. */
  944. this.addClass = true;
  945. this.carousel = carousel;
  946. }
  947. /**
  948. * Fires changes in container collection after adding a new slide instance
  949. * @return {?}
  950. */
  951. ngOnInit() {
  952. this.carousel.addSlide(this);
  953. this.itemWidth = `${100 / this.carousel.itemsPerSlide}%`;
  954. }
  955. /**
  956. * Fires changes in container collection after removing of this slide instance
  957. * @return {?}
  958. */
  959. ngOnDestroy() {
  960. this.carousel.removeSlide(this);
  961. }
  962. }
  963. SlideComponent.decorators = [
  964. { type: Component, args: [{
  965. selector: 'slide',
  966. template: `
  967. <div [class.active]="active" class="item">
  968. <ng-content></ng-content>
  969. </div>
  970. `,
  971. host: {
  972. '[attr.aria-hidden]': '!active'
  973. }
  974. }] }
  975. ];
  976. /** @nocollapse */
  977. SlideComponent.ctorParameters = () => [
  978. { type: CarouselComponent }
  979. ];
  980. SlideComponent.propDecorators = {
  981. active: [{ type: HostBinding, args: ['class.active',] }, { type: Input }],
  982. itemWidth: [{ type: HostBinding, args: ['style.width',] }],
  983. order: [{ type: HostBinding, args: ['style.order',] }],
  984. addClass: [{ type: HostBinding, args: ['class.item',] }, { type: HostBinding, args: ['class.carousel-item',] }]
  985. };
  986. /**
  987. * @fileoverview added by tsickle
  988. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  989. */
  990. class CarouselModule {
  991. /**
  992. * @return {?}
  993. */
  994. static forRoot() {
  995. return { ngModule: CarouselModule, providers: [] };
  996. }
  997. }
  998. CarouselModule.decorators = [
  999. { type: NgModule, args: [{
  1000. imports: [CommonModule],
  1001. declarations: [SlideComponent, CarouselComponent],
  1002. exports: [SlideComponent, CarouselComponent],
  1003. providers: [CarouselConfig]
  1004. },] }
  1005. ];
  1006. export { CarouselComponent, CarouselConfig, CarouselModule, SlideComponent };
  1007. //# sourceMappingURL=ngx-bootstrap-carousel.js.map