angular-dual-listbox.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. import { EventEmitter, Component, IterableDiffers, Input, Output, NgModule } from '@angular/core';
  2. import { CommonModule } from '@angular/common';
  3. import { FormsModule } from '@angular/forms';
  4. /**
  5. * @fileoverview added by tsickle
  6. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  7. */
  8. class BasicList {
  9. /**
  10. * @param {?} name
  11. */
  12. constructor(name) {
  13. this._name = name;
  14. this.last = null;
  15. this.picker = '';
  16. this.dragStart = false;
  17. this.dragOver = false;
  18. // Arrays will contain objects of { _id, _name }.
  19. this.pick = [];
  20. this.list = [];
  21. this.sift = [];
  22. }
  23. /**
  24. * @return {?}
  25. */
  26. get name() {
  27. return this._name;
  28. }
  29. }
  30. /**
  31. * @fileoverview added by tsickle
  32. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  33. */
  34. /** @type {?} */
  35. var nextId = 0;
  36. class DualListComponent {
  37. /**
  38. * @param {?} differs
  39. */
  40. constructor(differs) {
  41. this.differs = differs;
  42. this.id = `dual-list-${nextId++}`;
  43. this.key = '_id';
  44. this.display = '_name';
  45. this.height = '100px';
  46. this.filter = false;
  47. this.format = DualListComponent.DEFAULT_FORMAT;
  48. this.sort = false;
  49. this.disabled = false;
  50. this.destinationChange = new EventEmitter();
  51. this.sorter = (/**
  52. * @param {?} a
  53. * @param {?} b
  54. * @return {?}
  55. */
  56. (a, b) => { return (a._name < b._name) ? -1 : ((a._name > b._name) ? 1 : 0); });
  57. this.available = new BasicList(DualListComponent.AVAILABLE_LIST_NAME);
  58. this.confirmed = new BasicList(DualListComponent.CONFIRMED_LIST_NAME);
  59. }
  60. /**
  61. * @param {?} changeRecord
  62. * @return {?}
  63. */
  64. ngOnChanges(changeRecord) {
  65. if (changeRecord['filter']) {
  66. if (changeRecord['filter'].currentValue === false) {
  67. this.clearFilter(this.available);
  68. this.clearFilter(this.confirmed);
  69. }
  70. }
  71. if (changeRecord['sort']) {
  72. if (changeRecord['sort'].currentValue === true && this.compare === undefined) {
  73. this.compare = this.sorter;
  74. }
  75. else if (changeRecord['sort'].currentValue === false) {
  76. this.compare = undefined;
  77. }
  78. }
  79. if (changeRecord['format']) {
  80. this.format = changeRecord['format'].currentValue;
  81. if (typeof (this.format.direction) === 'undefined') {
  82. this.format.direction = DualListComponent.LTR;
  83. }
  84. if (typeof (this.format.add) === 'undefined') {
  85. this.format.add = DualListComponent.DEFAULT_FORMAT.add;
  86. }
  87. if (typeof (this.format.remove) === 'undefined') {
  88. this.format.remove = DualListComponent.DEFAULT_FORMAT.remove;
  89. }
  90. if (typeof (this.format.all) === 'undefined') {
  91. this.format.all = DualListComponent.DEFAULT_FORMAT.all;
  92. }
  93. if (typeof (this.format.none) === 'undefined') {
  94. this.format.none = DualListComponent.DEFAULT_FORMAT.none;
  95. }
  96. if (typeof (this.format.draggable) === 'undefined') {
  97. this.format.draggable = DualListComponent.DEFAULT_FORMAT.draggable;
  98. }
  99. }
  100. if (changeRecord['source']) {
  101. this.available = new BasicList(DualListComponent.AVAILABLE_LIST_NAME);
  102. this.updatedSource();
  103. this.updatedDestination();
  104. }
  105. if (changeRecord['destination']) {
  106. this.confirmed = new BasicList(DualListComponent.CONFIRMED_LIST_NAME);
  107. this.updatedDestination();
  108. this.updatedSource();
  109. }
  110. }
  111. /**
  112. * @return {?}
  113. */
  114. ngDoCheck() {
  115. if (this.source && this.buildAvailable(this.source)) {
  116. this.onFilter(this.available);
  117. }
  118. if (this.destination && this.buildConfirmed(this.destination)) {
  119. this.onFilter(this.confirmed);
  120. }
  121. }
  122. /**
  123. * @param {?} source
  124. * @return {?}
  125. */
  126. buildAvailable(source) {
  127. /** @type {?} */
  128. const sourceChanges = this.sourceDiffer.diff(source);
  129. if (sourceChanges) {
  130. sourceChanges.forEachRemovedItem((/**
  131. * @param {?} r
  132. * @return {?}
  133. */
  134. (r) => {
  135. /** @type {?} */
  136. const idx = this.findItemIndex(this.available.list, r.item, this.key);
  137. if (idx !== -1) {
  138. this.available.list.splice(idx, 1);
  139. }
  140. }));
  141. sourceChanges.forEachAddedItem((/**
  142. * @param {?} r
  143. * @return {?}
  144. */
  145. (r) => {
  146. // Do not add duplicates even if source has duplicates.
  147. if (this.findItemIndex(this.available.list, r.item, this.key) === -1) {
  148. this.available.list.push({ _id: this.makeId(r.item), _name: this.makeName(r.item) });
  149. }
  150. }));
  151. if (this.compare !== undefined) {
  152. this.available.list.sort(this.compare);
  153. }
  154. this.available.sift = this.available.list;
  155. return true;
  156. }
  157. return false;
  158. }
  159. /**
  160. * @param {?} destination
  161. * @return {?}
  162. */
  163. buildConfirmed(destination) {
  164. /** @type {?} */
  165. let moved = false;
  166. /** @type {?} */
  167. const destChanges = this.destinationDiffer.diff(destination);
  168. if (destChanges) {
  169. destChanges.forEachRemovedItem((/**
  170. * @param {?} r
  171. * @return {?}
  172. */
  173. (r) => {
  174. /** @type {?} */
  175. const idx = this.findItemIndex(this.confirmed.list, r.item, this.key);
  176. if (idx !== -1) {
  177. if (!this.isItemSelected(this.confirmed.pick, this.confirmed.list[idx])) {
  178. this.selectItem(this.confirmed.pick, this.confirmed.list[idx]);
  179. }
  180. this.moveItem(this.confirmed, this.available, this.confirmed.list[idx], false);
  181. moved = true;
  182. }
  183. }));
  184. destChanges.forEachAddedItem((/**
  185. * @param {?} r
  186. * @return {?}
  187. */
  188. (r) => {
  189. /** @type {?} */
  190. const idx = this.findItemIndex(this.available.list, r.item, this.key);
  191. if (idx !== -1) {
  192. if (!this.isItemSelected(this.available.pick, this.available.list[idx])) {
  193. this.selectItem(this.available.pick, this.available.list[idx]);
  194. }
  195. this.moveItem(this.available, this.confirmed, this.available.list[idx], false);
  196. moved = true;
  197. }
  198. }));
  199. if (this.compare !== undefined) {
  200. this.confirmed.list.sort(this.compare);
  201. }
  202. this.confirmed.sift = this.confirmed.list;
  203. if (moved) {
  204. this.trueUp();
  205. }
  206. return true;
  207. }
  208. return false;
  209. }
  210. /**
  211. * @return {?}
  212. */
  213. updatedSource() {
  214. this.available.list.length = 0;
  215. this.available.pick.length = 0;
  216. if (this.source !== undefined) {
  217. this.sourceDiffer = this.differs.find(this.source).create(null);
  218. }
  219. }
  220. /**
  221. * @return {?}
  222. */
  223. updatedDestination() {
  224. if (this.destination !== undefined) {
  225. this.destinationDiffer = this.differs.find(this.destination).create(null);
  226. }
  227. }
  228. /**
  229. * @return {?}
  230. */
  231. direction() {
  232. return this.format.direction === DualListComponent.LTR;
  233. }
  234. /**
  235. * @param {?=} list
  236. * @return {?}
  237. */
  238. dragEnd(list = null) {
  239. if (list) {
  240. list.dragStart = false;
  241. }
  242. else {
  243. this.available.dragStart = false;
  244. this.confirmed.dragStart = false;
  245. }
  246. return false;
  247. }
  248. /**
  249. * @param {?} event
  250. * @param {?} item
  251. * @param {?} list
  252. * @return {?}
  253. */
  254. drag(event, item, list) {
  255. if (!this.isItemSelected(list.pick, item)) {
  256. this.selectItem(list.pick, item);
  257. }
  258. list.dragStart = true;
  259. // Set a custom type to be this dual-list's id.
  260. event.dataTransfer.setData(this.id, item['_id']);
  261. }
  262. /**
  263. * @param {?} event
  264. * @param {?} list
  265. * @return {?}
  266. */
  267. allowDrop(event, list) {
  268. if (event.dataTransfer.types.length && (event.dataTransfer.types[0] === this.id)) {
  269. event.preventDefault();
  270. if (!list.dragStart) {
  271. list.dragOver = true;
  272. }
  273. }
  274. return false;
  275. }
  276. /**
  277. * @return {?}
  278. */
  279. dragLeave() {
  280. this.available.dragOver = false;
  281. this.confirmed.dragOver = false;
  282. }
  283. /**
  284. * @param {?} event
  285. * @param {?} list
  286. * @return {?}
  287. */
  288. drop(event, list) {
  289. if (event.dataTransfer.types.length && (event.dataTransfer.types[0] === this.id)) {
  290. event.preventDefault();
  291. this.dragLeave();
  292. this.dragEnd();
  293. if (list === this.available) {
  294. this.moveItem(this.available, this.confirmed);
  295. }
  296. else {
  297. this.moveItem(this.confirmed, this.available);
  298. }
  299. }
  300. }
  301. /**
  302. * @private
  303. * @return {?}
  304. */
  305. trueUp() {
  306. /** @type {?} */
  307. let changed = false;
  308. // Clear removed items.
  309. /** @type {?} */
  310. let pos = this.destination.length;
  311. while ((pos -= 1) >= 0) {
  312. /** @type {?} */
  313. const mv = this.confirmed.list.filter((/**
  314. * @param {?} conf
  315. * @return {?}
  316. */
  317. conf => {
  318. if (typeof this.destination[pos] === 'object') {
  319. return conf._id === this.destination[pos][this.key];
  320. }
  321. else {
  322. return conf._id === this.destination[pos];
  323. }
  324. }));
  325. if (mv.length === 0) {
  326. // Not found so remove.
  327. this.destination.splice(pos, 1);
  328. changed = true;
  329. }
  330. }
  331. // Push added items.
  332. for (let i = 0, len = this.confirmed.list.length; i < len; i += 1) {
  333. /** @type {?} */
  334. let mv = this.destination.filter((/**
  335. * @param {?} d
  336. * @return {?}
  337. */
  338. (d) => {
  339. if (typeof d === 'object') {
  340. return (d[this.key] === this.confirmed.list[i]._id);
  341. }
  342. else {
  343. return (d === this.confirmed.list[i]._id);
  344. }
  345. }));
  346. if (mv.length === 0) {
  347. // Not found so add.
  348. mv = this.source.filter((/**
  349. * @param {?} o
  350. * @return {?}
  351. */
  352. (o) => {
  353. if (typeof o === 'object') {
  354. return (o[this.key] === this.confirmed.list[i]._id);
  355. }
  356. else {
  357. return (o === this.confirmed.list[i]._id);
  358. }
  359. }));
  360. if (mv.length > 0) {
  361. this.destination.push(mv[0]);
  362. changed = true;
  363. }
  364. }
  365. }
  366. if (changed) {
  367. this.destinationChange.emit(this.destination);
  368. }
  369. }
  370. /**
  371. * @param {?} list
  372. * @param {?} item
  373. * @param {?=} key
  374. * @return {?}
  375. */
  376. findItemIndex(list, item, key = '_id') {
  377. /** @type {?} */
  378. let idx = -1;
  379. /**
  380. * @param {?} e
  381. * @return {?}
  382. */
  383. function matchObject(e) {
  384. if (e._id === item[key]) {
  385. idx = list.indexOf(e);
  386. return true;
  387. }
  388. return false;
  389. }
  390. /**
  391. * @param {?} e
  392. * @return {?}
  393. */
  394. function match(e) {
  395. if (e._id === item) {
  396. idx = list.indexOf(e);
  397. return true;
  398. }
  399. return false;
  400. }
  401. // Assumption is that the arrays do not have duplicates.
  402. if (typeof item === 'object') {
  403. list.filter(matchObject);
  404. }
  405. else {
  406. list.filter(match);
  407. }
  408. return idx;
  409. }
  410. /**
  411. * @private
  412. * @param {?} source
  413. * @param {?} item
  414. * @return {?}
  415. */
  416. makeUnavailable(source, item) {
  417. /** @type {?} */
  418. const idx = source.list.indexOf(item);
  419. if (idx !== -1) {
  420. source.list.splice(idx, 1);
  421. }
  422. }
  423. /**
  424. * @param {?} source
  425. * @param {?} target
  426. * @param {?=} item
  427. * @param {?=} trueup
  428. * @return {?}
  429. */
  430. moveItem(source, target, item = null, trueup = true) {
  431. /** @type {?} */
  432. let i = 0;
  433. /** @type {?} */
  434. let len = source.pick.length;
  435. if (item) {
  436. i = source.list.indexOf(item);
  437. len = i + 1;
  438. }
  439. for (; i < len; i += 1) {
  440. // Is the pick still in list?
  441. /** @type {?} */
  442. let mv = [];
  443. if (item) {
  444. /** @type {?} */
  445. const idx = this.findItemIndex(source.pick, item);
  446. if (idx !== -1) {
  447. mv[0] = source.pick[idx];
  448. }
  449. }
  450. else {
  451. mv = source.list.filter((/**
  452. * @param {?} src
  453. * @return {?}
  454. */
  455. src => {
  456. return (src._id === source.pick[i]._id);
  457. }));
  458. }
  459. // Should only ever be 1
  460. if (mv.length === 1) {
  461. // Add if not already in target.
  462. if (target.list.filter((/**
  463. * @param {?} trg
  464. * @return {?}
  465. */
  466. trg => trg._id === mv[0]._id)).length === 0) {
  467. target.list.push(mv[0]);
  468. }
  469. this.makeUnavailable(source, mv[0]);
  470. }
  471. }
  472. if (this.compare !== undefined) {
  473. target.list.sort(this.compare);
  474. }
  475. source.pick.length = 0;
  476. // Update destination
  477. if (trueup) {
  478. this.trueUp();
  479. }
  480. // Delay ever-so-slightly to prevent race condition.
  481. setTimeout((/**
  482. * @return {?}
  483. */
  484. () => {
  485. this.onFilter(source);
  486. this.onFilter(target);
  487. }), 10);
  488. }
  489. /**
  490. * @param {?} list
  491. * @param {?} item
  492. * @return {?}
  493. */
  494. isItemSelected(list, item) {
  495. if (list.filter((/**
  496. * @param {?} e
  497. * @return {?}
  498. */
  499. e => Object.is(e, item))).length > 0) {
  500. return true;
  501. }
  502. return false;
  503. }
  504. /**
  505. * @param {?} event
  506. * @param {?} index
  507. * @param {?} source
  508. * @param {?} item
  509. * @return {?}
  510. */
  511. shiftClick(event, index, source, item) {
  512. if (event.shiftKey && source.last && !Object.is(item, source.last)) {
  513. /** @type {?} */
  514. const idx = source.sift.indexOf(source.last);
  515. if (index > idx) {
  516. for (let i = (idx + 1); i < index; i += 1) {
  517. this.selectItem(source.pick, source.sift[i]);
  518. }
  519. }
  520. else if (idx !== -1) {
  521. for (let i = (index + 1); i < idx; i += 1) {
  522. this.selectItem(source.pick, source.sift[i]);
  523. }
  524. }
  525. }
  526. source.last = item;
  527. }
  528. /**
  529. * @param {?} list
  530. * @param {?} item
  531. * @return {?}
  532. */
  533. selectItem(list, item) {
  534. /** @type {?} */
  535. const pk = list.filter((/**
  536. * @param {?} e
  537. * @return {?}
  538. */
  539. (e) => {
  540. return Object.is(e, item);
  541. }));
  542. if (pk.length > 0) {
  543. // Already in list, so deselect.
  544. for (let i = 0, len = pk.length; i < len; i += 1) {
  545. /** @type {?} */
  546. const idx = list.indexOf(pk[i]);
  547. if (idx !== -1) {
  548. list.splice(idx, 1);
  549. }
  550. }
  551. }
  552. else {
  553. list.push(item);
  554. }
  555. }
  556. /**
  557. * @param {?} source
  558. * @return {?}
  559. */
  560. selectAll(source) {
  561. source.pick.length = 0;
  562. source.pick = source.sift.slice(0);
  563. }
  564. /**
  565. * @param {?} source
  566. * @return {?}
  567. */
  568. selectNone(source) {
  569. source.pick.length = 0;
  570. }
  571. /**
  572. * @param {?} source
  573. * @return {?}
  574. */
  575. isAllSelected(source) {
  576. if (source.list.length === 0 || source.list.length === source.pick.length) {
  577. return true;
  578. }
  579. return false;
  580. }
  581. /**
  582. * @param {?} source
  583. * @return {?}
  584. */
  585. isAnySelected(source) {
  586. if (source.pick.length > 0) {
  587. return true;
  588. }
  589. return false;
  590. }
  591. /**
  592. * @private
  593. * @param {?} source
  594. * @return {?}
  595. */
  596. unpick(source) {
  597. for (let i = source.pick.length - 1; i >= 0; i -= 1) {
  598. if (source.sift.indexOf(source.pick[i]) === -1) {
  599. source.pick.splice(i, 1);
  600. }
  601. }
  602. }
  603. /**
  604. * @param {?} source
  605. * @return {?}
  606. */
  607. clearFilter(source) {
  608. if (source) {
  609. source.picker = '';
  610. this.onFilter(source);
  611. }
  612. }
  613. /**
  614. * @param {?} source
  615. * @return {?}
  616. */
  617. onFilter(source) {
  618. if (source.picker.length > 0) {
  619. try {
  620. /** @type {?} */
  621. const filtered = source.list.filter((/**
  622. * @param {?} item
  623. * @return {?}
  624. */
  625. (item) => {
  626. if (Object.prototype.toString.call(item) === '[object Object]') {
  627. if (item._name !== undefined) {
  628. // @ts-ignore: remove when d.ts has locale as an argument.
  629. return item._name.toLocaleLowerCase(this.format.locale).indexOf(source.picker.toLocaleLowerCase(this.format.locale)) !== -1;
  630. }
  631. else {
  632. // @ts-ignore: remove when d.ts has locale as an argument.
  633. return JSON.stringify(item).toLocaleLowerCase(this.format.locale).indexOf(source.picker.toLocaleLowerCase(this.format.locale)) !== -1;
  634. }
  635. }
  636. else {
  637. // @ts-ignore: remove when d.ts has locale as an argument.
  638. return item.toLocaleLowerCase(this.format.locale).indexOf(source.picker.toLocaleLowerCase(this.format.locale)) !== -1;
  639. }
  640. }));
  641. source.sift = filtered;
  642. this.unpick(source);
  643. }
  644. catch (e) {
  645. if (e instanceof RangeError) {
  646. this.format.locale = undefined;
  647. }
  648. source.sift = source.list;
  649. }
  650. }
  651. else {
  652. source.sift = source.list;
  653. }
  654. }
  655. /**
  656. * @private
  657. * @param {?} item
  658. * @return {?}
  659. */
  660. makeId(item) {
  661. if (typeof item === 'object') {
  662. return item[this.key];
  663. }
  664. else {
  665. return item;
  666. }
  667. }
  668. // Allow for complex names by passing an array of strings.
  669. // Example: [display]="[ '_type.substring(0,1)', '_name' ]"
  670. /**
  671. * @protected
  672. * @param {?} item
  673. * @param {?=} separator
  674. * @return {?}
  675. */
  676. makeName(item, separator = '_') {
  677. /** @type {?} */
  678. const display = this.display;
  679. /**
  680. * @param {?} itm
  681. * @return {?}
  682. */
  683. function fallback(itm) {
  684. switch (Object.prototype.toString.call(itm)) {
  685. case '[object Number]':
  686. return itm;
  687. case '[object String]':
  688. return itm;
  689. default:
  690. if (itm !== undefined) {
  691. return itm[display];
  692. }
  693. else {
  694. return 'undefined';
  695. }
  696. }
  697. }
  698. /** @type {?} */
  699. let str = '';
  700. if (this.display !== undefined) {
  701. switch (Object.prototype.toString.call(this.display)) {
  702. case '[object Function]':
  703. str = this.display(item);
  704. break;
  705. case '[object Array]':
  706. for (let i = 0, len = this.display.length; i < len; i += 1) {
  707. if (str.length > 0) {
  708. str = str + separator;
  709. }
  710. if (this.display[i].indexOf('.') === -1) {
  711. // Simple, just add to string.
  712. str = str + item[this.display[i]];
  713. }
  714. else {
  715. // Complex, some action needs to be performed
  716. /** @type {?} */
  717. const parts = this.display[i].split('.');
  718. /** @type {?} */
  719. const s = item[parts[0]];
  720. if (s) {
  721. // Use brute force
  722. if (parts[1].indexOf('substring') !== -1) {
  723. /** @type {?} */
  724. const nums = (parts[1].substring(parts[1].indexOf('(') + 1, parts[1].indexOf(')'))).split(',');
  725. switch (nums.length) {
  726. case 1:
  727. str = str + s.substring(parseInt(nums[0], 10));
  728. break;
  729. case 2:
  730. str = str + s.substring(parseInt(nums[0], 10), parseInt(nums[1], 10));
  731. break;
  732. default:
  733. str = str + s;
  734. break;
  735. }
  736. }
  737. else {
  738. // method not approved, so just add s.
  739. str = str + s;
  740. }
  741. }
  742. }
  743. }
  744. break;
  745. default:
  746. str = fallback(item);
  747. break;
  748. }
  749. }
  750. else {
  751. str = fallback(item);
  752. }
  753. return str;
  754. }
  755. }
  756. DualListComponent.AVAILABLE_LIST_NAME = 'available';
  757. DualListComponent.CONFIRMED_LIST_NAME = 'confirmed';
  758. DualListComponent.LTR = 'left-to-right';
  759. DualListComponent.RTL = 'right-to-left';
  760. DualListComponent.DEFAULT_FORMAT = {
  761. add: 'Add',
  762. remove: 'Remove',
  763. all: 'All',
  764. none: 'None',
  765. direction: DualListComponent.LTR,
  766. draggable: true,
  767. locale: undefined
  768. };
  769. DualListComponent.decorators = [
  770. { type: Component, args: [{
  771. selector: 'dual-list',
  772. template: "<div class=\"dual-list\">\n\t<div class=\"listbox\" [ngStyle]=\"{ 'order' : direction() ? 1 : 2, 'margin-left' : direction() ? 0 : '10px' }\">\n\t\t<button type=\"button\" name=\"addBtn\" class=\"btn btn-primary btn-block\"\n\t\t\t(click)=\"moveItem(available, confirmed)\" [ngClass]=\"direction() ? 'point-right' : 'point-left'\"\n\t\t\t[disabled]=\"available.pick.length === 0\">{{format.add}}</button>\n\n\t\t<form *ngIf=\"filter\" class=\"filter\">\n\t\t\t<input class=\"form-control\" name=\"filterSource\" [(ngModel)]=\"available.picker\" (ngModelChange)=\"onFilter(available)\">\n\t\t</form>\n\n\t\t<div class=\"record-picker\">\n\t\t\t<ul [ngStyle]=\"{'max-height': height, 'min-height': height}\" [ngClass]=\"{over:available.dragOver}\"\n\t\t\t\t(drop)=\"drop($event, confirmed)\" (dragover)=\"allowDrop($event, available)\" (dragleave)=\"dragLeave()\">\n\t\t\t\t<li *ngFor=\"let item of available.sift; let idx=index;\"\n\t\t\t\t\t(click)=\"disabled ? null : selectItem(available.pick, item); shiftClick($event, idx, available, item)\"\n\t\t\t\t\t[ngClass]=\"{selected: isItemSelected(available.pick, item), disabled: disabled}\"\n\t\t\t\t\t[draggable]=\"!disabled && format.draggable\" (dragstart)=\"drag($event, item, available)\" (dragend)=\"dragEnd(available)\"\n\t\t\t\t><label>{{item._name}}</label></li>\n\t\t\t</ul>\n\t\t</div>\n\n\t\t<div class=\"button-bar\">\n\t\t\t<button type=\"button\" class=\"btn btn-primary pull-left\" (click)=\"selectAll(available)\"\n\t\t\t\t[disabled]=\"disabled || isAllSelected(available)\">{{format.all}}</button>\n\t\t\t<button type=\"button\" class=\"btn btn-default pull-right\" (click)=\"selectNone(available)\"\n\t\t\t\t[disabled]=\"!isAnySelected(available)\">{{format.none}}</button>\n\t\t</div>\n\t</div>\n\n\t<div class=\"listbox\" [ngStyle]=\"{ 'order' : direction() ? 2 : 1, 'margin-left' : direction() ? '10px' : 0 }\">\n\t\t<button type=\"button\" name=\"removeBtn\" class=\"btn btn-primary btn-block\"\n\t\t\t(click)=\"moveItem(confirmed, available)\" [ngClass]=\"direction() ? 'point-left' : 'point-right'\"\n\t\t\t[disabled]=\"confirmed.pick.length === 0\">{{format.remove}}</button>\n\n\t\t<form *ngIf=\"filter\" class=\"filter\">\n\t\t\t<input class=\"form-control\" name=\"filterDestination\" [(ngModel)]=\"confirmed.picker\" (ngModelChange)=\"onFilter(confirmed)\">\n\t\t</form>\n\n\t\t<div class=\"record-picker\">\n\t\t\t<ul [ngStyle]=\"{'max-height': height, 'min-height': height}\" [ngClass]=\"{over:confirmed.dragOver}\"\n\t\t\t\t(drop)=\"drop($event, available)\" (dragover)=\"allowDrop($event, confirmed)\" (dragleave)=\"dragLeave()\">\n\t\t\t\t<li #itmConf *ngFor=\"let item of confirmed.sift; let idx=index;\"\n\t\t\t\t\t(click)=\"disabled ? null : selectItem(confirmed.pick, item); shiftClick($event, idx, confirmed, item)\"\n\t\t\t\t\t[ngClass]=\"{selected: isItemSelected(confirmed.pick, item), disabled: disabled}\"\n\t\t\t\t\t[draggable]=\"!disabled && format.draggable\" (dragstart)=\"drag($event, item, confirmed)\" (dragend)=\"dragEnd(confirmed)\"\n\t\t\t\t><label>{{item._name}}</label></li>\n\t\t\t</ul>\n\t\t</div>\n\n\t\t<div class=\"button-bar\">\n\t\t\t<button type=\"button\" class=\"btn btn-primary pull-left\" (click)=\"selectAll(confirmed)\"\n\t\t\t\t[disabled]=\"disabled || isAllSelected(confirmed)\">{{format.all}}</button>\n\t\t\t<button type=\"button\" class=\"btn btn-default pull-right\" (click)=\"selectNone(confirmed)\"\n\t\t\t\t[disabled]=\"!isAnySelected(confirmed)\">{{format.none}}</button>\n\t\t</div>\n\t</div>\n</div>\n",
  773. styles: ["div.record-picker{overflow-x:hidden;overflow-y:auto;border:1px solid #ddd;border-radius:8px;position:relative;cursor:pointer;scrollbar-base-color:#337ab7;scrollbar-3dlight-color:#337ab7;scrollbar-highlight-color:#337ab7;scrollbar-track-color:#eee;scrollbar-arrow-color:gray;scrollbar-shadow-color:gray;scrollbar-dark-shadow-color:gray}div.record-picker::-webkit-scrollbar{width:12px}div.record-picker::-webkit-scrollbar-button{width:0;height:0}div.record-picker::-webkit-scrollbar-track{background:#eee;box-shadow:0 0 3px #dfdfdf inset;border-top-right-radius:8px;border-bottom-right-radius:8px}div.record-picker::-webkit-scrollbar-thumb{background:#337ab7;border:thin solid gray;border-top-right-radius:8px;border-bottom-right-radius:8px}div.record-picker::-webkit-scrollbar-thumb:hover{background:#286090}.record-picker ul{margin:0;padding:0 0 1px}.record-picker li{border-top:thin solid #ddd;border-bottom:1px solid #ddd;display:block;padding:2px 2px 2px 10px;margin-bottom:-1px;font-size:.85em;cursor:pointer;white-space:nowrap;min-height:16px}.record-picker li:hover{background-color:#f5f5f5}.record-picker li.selected{background-color:#d9edf7}.record-picker li.selected:hover{background-color:#c4e3f3}.record-picker li.disabled{opacity:.5;cursor:default;background-color:inherit}.record-picker li:first-child{border-top-left-radius:8px;border-top-right-radius:8px;border-top:none}.record-picker li:last-child{border-bottom-left-radius:8px;border-bottom-right-radius:8px;border-bottom:none}.record-picker label{cursor:pointer;font-weight:inherit;font-size:14px;padding:4px;margin-bottom:-1px;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.record-picker ul.over{background-color:#d3d3d3}.dual-list{display:flex;flex-direction:row;align-content:flex-start}.dual-list .listbox{width:50%;margin:0}.dual-list .button-bar{margin-top:8px}.point-right::after{content:\"\\25B6\";padding-left:1em}.point-left::before{content:\"\\25C0\";padding-right:1em}.dual-list .button-bar button{width:47%}button.btn-block{display:block;width:100%;margin-bottom:8px}.filter{margin-bottom:-2.2em}.filter::after{content:\"o\";width:40px;color:transparent;font-size:2em;background-image:url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"><path d=\"M0 64l192 192v192l128-32V256L512 64H0z\"/></svg>');background-repeat:no-repeat;background-position:center center;opacity:.2;top:-36px;left:calc(100% - 21px);position:relative}"]
  774. }] }
  775. ];
  776. /** @nocollapse */
  777. DualListComponent.ctorParameters = () => [
  778. { type: IterableDiffers }
  779. ];
  780. DualListComponent.propDecorators = {
  781. id: [{ type: Input }],
  782. key: [{ type: Input }],
  783. display: [{ type: Input }],
  784. height: [{ type: Input }],
  785. filter: [{ type: Input }],
  786. format: [{ type: Input }],
  787. sort: [{ type: Input }],
  788. compare: [{ type: Input }],
  789. disabled: [{ type: Input }],
  790. source: [{ type: Input }],
  791. destination: [{ type: Input }],
  792. destinationChange: [{ type: Output }]
  793. };
  794. /**
  795. * @fileoverview added by tsickle
  796. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  797. */
  798. class AngularDualListBoxModule {
  799. }
  800. AngularDualListBoxModule.decorators = [
  801. { type: NgModule, args: [{
  802. imports: [
  803. CommonModule,
  804. FormsModule
  805. ],
  806. declarations: [DualListComponent],
  807. exports: [DualListComponent]
  808. },] }
  809. ];
  810. /**
  811. * @fileoverview added by tsickle
  812. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  813. */
  814. /**
  815. * @fileoverview added by tsickle
  816. * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  817. */
  818. export { AngularDualListBoxModule, BasicList, DualListComponent };
  819. //# sourceMappingURL=angular-dual-listbox.js.map