a zip code crypto-currency system good for red ONLY

virtual-scroll.js 34KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. (function (factory) {
  2. if (typeof module === "object" && typeof module.exports === "object") {
  3. var v = factory(require, exports);
  4. if (v !== undefined) module.exports = v;
  5. }
  6. else if (typeof define === "function" && define.amd) {
  7. define(["require", "exports", "@angular/core", "./virtual-util", "../../config/config", "../content/content", "../../platform/dom-controller", "../../util/util", "../../platform/platform", "../../navigation/view-controller", "./virtual-item", "./virtual-footer", "./virtual-header"], factory);
  8. }
  9. })(function (require, exports) {
  10. "use strict";
  11. Object.defineProperty(exports, "__esModule", { value: true });
  12. var core_1 = require("@angular/core");
  13. var virtual_util_1 = require("./virtual-util");
  14. var config_1 = require("../../config/config");
  15. var content_1 = require("../content/content");
  16. var dom_controller_1 = require("../../platform/dom-controller");
  17. var util_1 = require("../../util/util");
  18. var platform_1 = require("../../platform/platform");
  19. var view_controller_1 = require("../../navigation/view-controller");
  20. var virtual_item_1 = require("./virtual-item");
  21. var virtual_footer_1 = require("./virtual-footer");
  22. var virtual_header_1 = require("./virtual-header");
  23. /**
  24. * @name VirtualScroll
  25. * @description
  26. * Virtual Scroll displays a virtual, "infinite" list. An array of records
  27. * is passed to the virtual scroll containing the data to create templates
  28. * for. The template created for each record, referred to as a cell, can
  29. * consist of items, headers, and footers.
  30. *
  31. * For performance reasons, not every record in the list is rendered at once;
  32. * instead a small subset of records (enough to fill the viewport) are rendered
  33. * and reused as the user scrolls.
  34. *
  35. * ### The Basics
  36. *
  37. * The array of records should be passed to the `virtualScroll` property.
  38. * The data given to the `virtualScroll` property must be an array. An item
  39. * template with the `*virtualItem` property is required in the `virtualScroll`.
  40. * The `virtualScroll` and `*virtualItem` properties can be added to any element.
  41. *
  42. * ```html
  43. * <ion-list [virtualScroll]="items">
  44. *
  45. * <ion-item *virtualItem="let item">
  46. * {% raw %}{{ item }}{% endraw %}
  47. * </ion-item>
  48. *
  49. * </ion-list>
  50. * ```
  51. *
  52. *
  53. * ### Section Headers and Footers
  54. *
  55. * Section headers and footers are optional. They can be dynamically created
  56. * from developer-defined functions. For example, a large list of contacts
  57. * usually has a divider for each letter in the alphabet. Developers provide
  58. * their own custom function to be called on each record. The logic in the
  59. * custom function should determine whether to create the section template
  60. * and what data to provide to the template. The custom function should
  61. * return `null` if a template shouldn't be created.
  62. *
  63. * ```html
  64. * <ion-list [virtualScroll]="items" [headerFn]="myHeaderFn">
  65. *
  66. * <ion-item-divider *virtualHeader="let header">
  67. * Header: {% raw %}{{ header }}{% endraw %}
  68. * </ion-item-divider>
  69. *
  70. * <ion-item *virtualItem="let item">
  71. * Item: {% raw %}{{ item }}{% endraw %}
  72. * </ion-item>
  73. *
  74. * </ion-list>
  75. * ```
  76. *
  77. * Below is an example of a custom function called on every record. It
  78. * gets passed the individual record, the record's index number,
  79. * and the entire array of records. In this example, after every 20
  80. * records a header will be inserted. So between the 19th and 20th records,
  81. * between the 39th and 40th, and so on, a `<ion-item-divider>` will
  82. * be created and the template's data will come from the function's
  83. * returned data.
  84. *
  85. * ```ts
  86. * myHeaderFn(record, recordIndex, records) {
  87. * if (recordIndex % 20 === 0) {
  88. * return 'Header ' + recordIndex;
  89. * }
  90. * return null;
  91. * }
  92. * ```
  93. *
  94. *
  95. * ### Approximate Widths and Heights
  96. *
  97. * If the height of items in the virtual scroll are not close to the
  98. * default size of 40px, it is extremely important to provide a value for
  99. * approxItemHeight height. An exact pixel-perfect size is not necessary,
  100. * but without an estimate the virtual scroll will not render correctly.
  101. *
  102. * The approximate width and height of each template is used to help
  103. * determine how many cells should be created, and to help calculate
  104. * the height of the scrollable area. Note that the actual rendered size
  105. * of each cell comes from the app's CSS, whereas this approximation
  106. * is only used to help calculate initial dimensions.
  107. *
  108. * It's also important to know that Ionic's default item sizes have
  109. * slightly different heights between platforms, which is perfectly fine.
  110. *
  111. *
  112. * ### Images Within Virtual Scroll
  113. *
  114. * HTTP requests, image decoding, and image rendering can cause jank while
  115. * scrolling. In order to better control images, Ionic provides `<ion-img>`
  116. * to manage HTTP requests and image rendering. While scrolling through items
  117. * quickly, `<ion-img>` knows when and when not to make requests, when and
  118. * when not to render images, and only loads the images that are viewable
  119. * after scrolling. [Read more about `ion-img`.](../../img/Img/)
  120. *
  121. * It's also important for app developers to ensure image sizes are locked in,
  122. * and after images have fully loaded they do not change size and affect any
  123. * other element sizes. Simply put, to ensure rendering bugs are not introduced,
  124. * it's vital that elements within a virtual item does not dynamically change.
  125. *
  126. * For virtual scrolling, the natural effects of the `<img>` are not desirable
  127. * features. We recommend using the `<ion-img>` component over the native
  128. * `<img>` element because when an `<img>` element is added to the DOM, it
  129. * immediately makes a HTTP request for the image file. Additionally, `<img>`
  130. * renders whenever it wants which could be while the user is scrolling. However,
  131. * `<ion-img>` is governed by the containing `ion-content` and does not render
  132. * images while scrolling quickly.
  133. *
  134. * ```html
  135. * <ion-list [virtualScroll]="items">
  136. *
  137. * <ion-item *virtualItem="let item">
  138. * <ion-avatar item-start>
  139. * <ion-img [src]="item.avatarUrl"></ion-img>
  140. * </ion-avatar>
  141. * {% raw %} {{ item.firstName }} {{ item.lastName }}{% endraw %}
  142. * </ion-item>
  143. *
  144. * </ion-list>
  145. * ```
  146. *
  147. *
  148. * ### Custom Components
  149. *
  150. * If a custom component is going to be used within Virtual Scroll, it's best
  151. * to wrap it with a good old `<div>` to ensure the component is rendered
  152. * correctly. Since each custom component's implementation and internals can be
  153. * quite different, wrapping within a `<div>` is a safe way to make sure
  154. * dimensions are measured correctly.
  155. *
  156. * ```html
  157. * <ion-list [virtualScroll]="items">
  158. *
  159. * <div *virtualItem="let item">
  160. * <my-custom-item [item]="item">
  161. * {% raw %} {{ item }}{% endraw %}
  162. * </my-custom-item>
  163. * </div>
  164. *
  165. * </ion-list>
  166. * ```
  167. *
  168. *
  169. * ## Virtual Scroll Performance Tips
  170. *
  171. * #### iOS Cordova WKWebView
  172. *
  173. * When deploying to iOS with Cordova, it's highly recommended to use the
  174. * [WKWebView plugin](http://blog.ionic.io/cordova-ios-performance-improvements-drop-in-speed-with-wkwebview/)
  175. * in order to take advantage of iOS's higher performimg webview. Additionally,
  176. * WKWebView is superior at scrolling efficiently in comparision to the older
  177. * UIWebView.
  178. *
  179. * #### Lock in element dimensions and locations
  180. *
  181. * In order for virtual scroll to efficiently size and locate every item, it's
  182. * very important every element within each virtual item does not dynamically
  183. * change its dimensions or location. The best way to ensure size and location
  184. * does not change, it's recommended each virtual item has locked in its size
  185. * via CSS.
  186. *
  187. * #### Use `ion-img` for images
  188. *
  189. * When including images within Virtual Scroll, be sure to use
  190. * [`ion-img`](../img/Img/) rather than the standard `<img>` HTML element.
  191. * With `ion-img`, images are lazy loaded so only the viewable ones are
  192. * rendered, and HTTP requests are efficiently controlled while scrolling.
  193. *
  194. * #### Set Approximate Widths and Heights
  195. *
  196. * As mentioned above, all elements should lock in their dimensions. However,
  197. * virtual scroll isn't aware of the dimensions until after they have been
  198. * rendered. For the initial render, virtual scroll still needs to set
  199. * how many items should be built. With "approx" property inputs, such as
  200. * `approxItemHeight`, we're able to give virtual scroll an approximate size,
  201. * therefore allowing virtual scroll to decide how many items should be
  202. * created.
  203. *
  204. * #### Changing dataset should use `virtualTrackBy`
  205. *
  206. * It is possible for the identities of elements in the iterator to change
  207. * while the data does not. This can happen, for example, if the iterator
  208. * produced from an RPC to the server, and that RPC is re-run. Even if the
  209. * "data" hasn't changed, the second response will produce objects with
  210. * different identities, and Ionic will tear down the entire DOM and rebuild
  211. * it. This is an expensive operation and should be avoided if possible.
  212. *
  213. * #### Efficient headers and footer functions
  214. *
  215. * Each virtual item must stay extremely efficient, but one way to really
  216. * kill its performance is to perform any DOM operations within section header
  217. * and footer functions. These functions are called for every record in the
  218. * dataset, so please make sure they're performant.
  219. *
  220. */
  221. var VirtualScroll = (function () {
  222. function VirtualScroll(_iterableDiffers, _elementRef, _renderer, _zone, _cd, _content, _plt, _ctrl, _config, _dom) {
  223. var _this = this;
  224. this._iterableDiffers = _iterableDiffers;
  225. this._elementRef = _elementRef;
  226. this._renderer = _renderer;
  227. this._zone = _zone;
  228. this._cd = _cd;
  229. this._content = _content;
  230. this._plt = _plt;
  231. this._ctrl = _ctrl;
  232. this._config = _config;
  233. this._dom = _dom;
  234. this._init = false;
  235. this._lastEle = false;
  236. this._records = [];
  237. this._cells = [];
  238. this._nodes = [];
  239. this._vHeight = 0;
  240. this._lastCheck = 0;
  241. this._recordSize = 0;
  242. this._data = {
  243. scrollTop: 0,
  244. };
  245. this._queue = 1 /* NoChanges */;
  246. /**
  247. * @input {number} The buffer ratio is used to decide how many cells
  248. * should get created when initially rendered. The number is a
  249. * multiplier against the viewable area's height. For example, if it
  250. * takes `20` cells to fill up the height of the viewable area, then
  251. * with a buffer ratio of `3` it will create `60` cells that are
  252. * available for reuse while scrolling. For better performance, it's
  253. * better to have more cells than what are required to fill the
  254. * viewable area. Default is `3`.
  255. */
  256. this.bufferRatio = 3;
  257. /**
  258. * @input {string} The approximate width of each item template's cell.
  259. * This dimension is used to help determine how many cells should
  260. * be created when initialized, and to help calculate the height of
  261. * the scrollable area. This value can use either `px` or `%` units.
  262. * Note that the actual rendered size of each cell comes from the
  263. * app's CSS, whereas this approximation is used to help calculate
  264. * initial dimensions before the item has been rendered. Default is
  265. * `100%`.
  266. */
  267. this.approxItemWidth = '100%';
  268. /**
  269. * @input {string} The approximate width of each header template's cell.
  270. * This dimension is used to help determine how many cells should
  271. * be created when initialized, and to help calculate the height of
  272. * the scrollable area. This value can use either `px` or `%` units.
  273. * Note that the actual rendered size of each cell comes from the
  274. * app's CSS, whereas this approximation is used to help calculate
  275. * initial dimensions. Default is `100%`.
  276. */
  277. this.approxHeaderWidth = '100%';
  278. /**
  279. * @input {string} The approximate height of each header template's cell.
  280. * This dimension is used to help determine how many cells should
  281. * be created when initialized, and to help calculate the height of
  282. * the scrollable area. This height value can only use `px` units.
  283. * Note that the actual rendered size of each cell comes from the
  284. * app's CSS, whereas this approximation is used to help calculate
  285. * initial dimensions before the item has been rendered. Default is `40px`.
  286. */
  287. this.approxHeaderHeight = '40px';
  288. /**
  289. * @input {string} The approximate width of each footer template's cell.
  290. * This dimension is used to help determine how many cells should
  291. * be created when initialized, and to help calculate the height of
  292. * the scrollable area. This value can use either `px` or `%` units.
  293. * Note that the actual rendered size of each cell comes from the
  294. * app's CSS, whereas this approximation is used to help calculate
  295. * initial dimensions before the item has been rendered. Default is `100%`.
  296. */
  297. this.approxFooterWidth = '100%';
  298. /**
  299. * @input {string} The approximate height of each footer template's cell.
  300. * This dimension is used to help determine how many cells should
  301. * be created when initialized, and to help calculate the height of
  302. * the scrollable area. This height value can only use `px` units.
  303. * Note that the actual rendered size of each cell comes from the
  304. * app's CSS, whereas this approximation is used to help calculate
  305. * initial dimensions before the item has been rendered. Default is `40px`.
  306. */
  307. this.approxFooterHeight = '40px';
  308. // hide the virtual scroll element with opacity so we don't
  309. // see jank as it loads up, but we're still able to read
  310. // dimensions because it's still rendered and only opacity hidden
  311. this.setElementClass('virtual-loading', true);
  312. // wait for the content to be rendered and has readable dimensions
  313. var readSub = _ctrl.readReady.subscribe(function () {
  314. readSub.unsubscribe();
  315. _this.readUpdate(true);
  316. });
  317. // wait for the content to be writable
  318. var writeSub = _ctrl.writeReady.subscribe(function () {
  319. writeSub.unsubscribe();
  320. _this._init = true;
  321. _this.writeUpdate(true);
  322. _this._listeners();
  323. });
  324. }
  325. Object.defineProperty(VirtualScroll.prototype, "virtualScroll", {
  326. get: function () {
  327. return this._records;
  328. },
  329. /**
  330. * @input {array} The data that builds the templates within the virtual scroll.
  331. * This is the same data that you'd pass to `*ngFor`. It's important to note
  332. * that when this data has changed, then the entire virtual scroll is reset,
  333. * which is an expensive operation and should be avoided if possible.
  334. */
  335. set: function (val) {
  336. this._records = val;
  337. },
  338. enumerable: true,
  339. configurable: true
  340. });
  341. Object.defineProperty(VirtualScroll.prototype, "headerFn", {
  342. /**
  343. * @input {function} Section headers and the data used within its given
  344. * template can be dynamically created by passing a function to `headerFn`.
  345. * For example, a large list of contacts usually has dividers between each
  346. * letter in the alphabet. App's can provide their own custom `headerFn`
  347. * which is called with each record within the dataset. The logic within
  348. * the header function can decide if the header template should be used,
  349. * and what data to give to the header template. The function must return
  350. * `null` if a header cell shouldn't be created.
  351. */
  352. set: function (val) {
  353. if (util_1.isFunction(val)) {
  354. this._hdrFn = val.bind((this._ctrl._cmp) || this);
  355. }
  356. },
  357. enumerable: true,
  358. configurable: true
  359. });
  360. Object.defineProperty(VirtualScroll.prototype, "footerFn", {
  361. /**
  362. * @input {function} Section footers and the data used within its given
  363. * template can be dynamically created by passing a function to `footerFn`.
  364. * The logic within the footer function can decide if the footer template
  365. * should be used, and what data to give to the footer template. The function
  366. * must return `null` if a footer cell shouldn't be created.
  367. */
  368. set: function (val) {
  369. if (util_1.isFunction(val)) {
  370. this._ftrFn = val.bind((this._ctrl._cmp) || this);
  371. }
  372. },
  373. enumerable: true,
  374. configurable: true
  375. });
  376. /**
  377. * @hidden
  378. */
  379. VirtualScroll.prototype.firstRecord = function () {
  380. var cells = this._cells;
  381. return (cells.length > 0) ? cells[0].record : 0;
  382. };
  383. /**
  384. * @hidden
  385. */
  386. VirtualScroll.prototype.lastRecord = function () {
  387. var cells = this._cells;
  388. return (cells.length > 0) ? cells[cells.length - 1].record : 0;
  389. };
  390. /**
  391. * @hidden
  392. */
  393. VirtualScroll.prototype.ngOnChanges = function (changes) {
  394. if ('virtualScroll' in changes) {
  395. // React on virtualScroll changes only once all inputs have been initialized
  396. var value = changes['virtualScroll'].currentValue;
  397. if (!util_1.isPresent(this._differ) && util_1.isPresent(value)) {
  398. try {
  399. this._differ = this._iterableDiffers.find(value).create(this.virtualTrackBy);
  400. }
  401. catch (e) {
  402. throw new Error("Cannot find a differ supporting object '" + value + "'. VirtualScroll only supports binding to Iterables such as Arrays.");
  403. }
  404. }
  405. }
  406. };
  407. /**
  408. * @hidden
  409. */
  410. VirtualScroll.prototype.ngDoCheck = function () {
  411. // only continue if we've already initialized
  412. if (!this._init) {
  413. return;
  414. }
  415. // and if there actually are changes
  416. var changes = util_1.isPresent(this._differ) ? this._differ.diff(this.virtualScroll) : null;
  417. if (!util_1.isPresent(changes)) {
  418. return;
  419. }
  420. var needClean = false;
  421. var lastRecord = this._recordSize;
  422. changes.forEachOperation(function (_, pindex, cindex) {
  423. // add new record after current position
  424. if (pindex === null && (cindex < lastRecord)) {
  425. (void 0) /* console.debug */;
  426. needClean = true;
  427. return;
  428. }
  429. // remove record after current position
  430. if (pindex < lastRecord && cindex === null) {
  431. (void 0) /* console.debug */;
  432. needClean = true;
  433. return;
  434. }
  435. });
  436. this._recordSize = this._records ? this._records.length : 0;
  437. this.readUpdate(needClean);
  438. this.writeUpdate(needClean);
  439. };
  440. /**
  441. * @hidden
  442. */
  443. VirtualScroll.prototype.readUpdate = function (needClean) {
  444. if (needClean) {
  445. // reset everything
  446. (void 0) /* console.debug */;
  447. this._cells.length = 0;
  448. // this._nodes.length = 0;
  449. // this._itmTmp.viewContainer.clear();
  450. // ******** DOM READ ****************
  451. this.calcDimensions();
  452. }
  453. else {
  454. (void 0) /* console.debug */;
  455. }
  456. };
  457. /**
  458. * @hidden
  459. */
  460. VirtualScroll.prototype.writeUpdate = function (needClean) {
  461. (void 0) /* console.debug */;
  462. var data = this._data;
  463. var stopAtHeight = (data.scrollTop + data.renderHeight);
  464. data.scrollDiff = SCROLL_DIFFERENCE_MINIMUM + 1;
  465. virtual_util_1.processRecords(stopAtHeight, this._records, this._cells, this._hdrFn, this._ftrFn, this._data);
  466. // ******** DOM WRITE ****************
  467. this.renderVirtual(needClean);
  468. };
  469. /**
  470. * @hidden
  471. */
  472. VirtualScroll.prototype.calcDimensions = function () {
  473. virtual_util_1.calcDimensions(this._data, this._elementRef.nativeElement, this.approxItemWidth, this.approxItemHeight, this.approxHeaderWidth, this.approxHeaderHeight, this.approxFooterWidth, this.approxFooterHeight, this.bufferRatio);
  474. };
  475. /**
  476. * @hidden
  477. * DOM WRITE
  478. */
  479. VirtualScroll.prototype.renderVirtual = function (needClean) {
  480. var _this = this;
  481. this._plt.raf(function () {
  482. var nodes = _this._nodes;
  483. var cells = _this._cells;
  484. var data = _this._data;
  485. var records = _this._records;
  486. if (needClean) {
  487. // ******** DOM WRITE ****************
  488. virtual_util_1.updateDimensions(_this._plt, nodes, cells, data, true);
  489. data.topCell = 0;
  490. data.bottomCell = (cells.length - 1);
  491. }
  492. virtual_util_1.adjustRendered(cells, data);
  493. _this._zone.run(function () {
  494. virtual_util_1.populateNodeData(data.topCell, data.bottomCell, true, cells, records, nodes, _this._itmTmp.viewContainer, _this._itmTmp.templateRef, _this._hdrTmp && _this._hdrTmp.templateRef, _this._ftrTmp && _this._ftrTmp.templateRef);
  495. });
  496. if (needClean) {
  497. _this._cd.detectChanges();
  498. }
  499. // at this point, this fn was called from within another
  500. // requestAnimationFrame, so the next dom reads/writes within the next frame
  501. // wait a frame before trying to read and calculate the dimensions
  502. // ******** DOM READ ****************
  503. _this._dom.read(function () { return virtual_util_1.initReadNodes(_this._plt, nodes, cells, data); });
  504. _this._dom.write(function () {
  505. // update the bound context for each node
  506. virtual_util_1.updateNodeContext(nodes, cells, data);
  507. // ******** DOM WRITE ****************
  508. _this._stepChangeDetection();
  509. // ******** DOM WRITE ****************
  510. _this._stepDOMWrite();
  511. // ******** DOM WRITE ****************
  512. _this._content.imgsUpdate();
  513. // First time load
  514. if (!_this._lastEle) {
  515. // add an element at the end so :last-child css doesn't get messed up
  516. // ******** DOM WRITE ****************
  517. var ele = _this._elementRef.nativeElement;
  518. var lastEle = _this._renderer.createElement(ele, 'div');
  519. lastEle.className = 'virtual-last';
  520. _this._lastEle = true;
  521. // ******** DOM WRITE ****************
  522. _this.setElementClass('virtual-scroll', true);
  523. // ******** DOM WRITE ****************
  524. _this.setElementClass('virtual-loading', false);
  525. }
  526. (void 0) /* assert */;
  527. });
  528. });
  529. };
  530. /**
  531. * @hidden
  532. */
  533. VirtualScroll.prototype.resize = function () {
  534. // only continue if we've already initialized
  535. if (!this._init) {
  536. return;
  537. }
  538. // check if component is rendered in the dom currently
  539. if (this._elementRef.nativeElement.offsetParent === null) {
  540. return;
  541. }
  542. (void 0) /* console.debug */;
  543. this.calcDimensions();
  544. this.writeUpdate(false);
  545. };
  546. /**
  547. * @hidden
  548. */
  549. VirtualScroll.prototype._stepDOMWrite = function () {
  550. var cells = this._cells;
  551. var nodes = this._nodes;
  552. // ******** DOM WRITE ****************
  553. virtual_util_1.writeToNodes(this._plt, nodes, cells, this._recordSize);
  554. // ******** DOM WRITE ****************
  555. this._setHeight(virtual_util_1.estimateHeight(this._recordSize, cells[cells.length - 1], this._vHeight, 0.25));
  556. // we're done here, good work
  557. this._queue = 1 /* NoChanges */;
  558. };
  559. /**
  560. * @hidden
  561. */
  562. VirtualScroll.prototype._stepChangeDetection = function () {
  563. // we need to do some change detection in this frame
  564. // we've got work painting do, let's throw it in the
  565. // domWrite callback so everyone plays nice
  566. // ******** DOM WRITE ****************
  567. var nodes = this._nodes;
  568. for (var i = 0; i < nodes.length; i++) {
  569. if (nodes[i].hasChanges) {
  570. nodes[i].view.detectChanges();
  571. }
  572. }
  573. // on the next frame we need write to the dom nodes manually
  574. this._queue = 3 /* DomWrite */;
  575. };
  576. /**
  577. * @hidden
  578. */
  579. VirtualScroll.prototype._stepNoChanges = function () {
  580. var data = this._data;
  581. // let's see if we've scroll far enough to require another check
  582. var diff = data.scrollDiff = (data.scrollTop - this._lastCheck);
  583. if (Math.abs(diff) < SCROLL_DIFFERENCE_MINIMUM) {
  584. return;
  585. }
  586. var cells = this._cells;
  587. var nodes = this._nodes;
  588. var records = this._records;
  589. // don't bother updating if the scrollTop hasn't changed much
  590. this._lastCheck = data.scrollTop;
  591. if (diff > 0) {
  592. // load data we may not have processed yet
  593. var stopAtHeight = (data.scrollTop + data.renderHeight);
  594. virtual_util_1.processRecords(stopAtHeight, records, cells, this._hdrFn, this._ftrFn, data);
  595. }
  596. // ******** DOM READ ****************
  597. virtual_util_1.updateDimensions(this._plt, nodes, cells, data, false);
  598. virtual_util_1.adjustRendered(cells, data);
  599. var hasChanges = virtual_util_1.populateNodeData(data.topCell, data.bottomCell, diff > 0, cells, records, nodes, this._itmTmp.viewContainer, this._itmTmp.templateRef, this._hdrTmp && this._hdrTmp.templateRef, this._ftrTmp && this._ftrTmp.templateRef);
  600. if (hasChanges) {
  601. // queue making updates in the next frame
  602. this._queue = 2 /* ChangeDetection */;
  603. // update the bound context for each node
  604. virtual_util_1.updateNodeContext(nodes, cells, data);
  605. }
  606. };
  607. /**
  608. * @hidden
  609. */
  610. VirtualScroll.prototype.scrollUpdate = function (ev) {
  611. var _this = this;
  612. // set the scroll top from the scroll event
  613. this._data.scrollTop = ev.scrollTop;
  614. // there is a queue system so that we can
  615. // spread out the work over multiple frames
  616. var queue = this._queue;
  617. if (queue === 1 /* NoChanges */) {
  618. // no dom writes or change detection to take care of
  619. this._stepNoChanges();
  620. }
  621. else if (queue === 2 /* ChangeDetection */) {
  622. this._dom.write(function () { return _this._stepChangeDetection(); });
  623. }
  624. else {
  625. (void 0) /* assert */;
  626. // there are DOM writes we need to take care of in this frame
  627. this._dom.write(function () { return _this._stepDOMWrite(); });
  628. }
  629. };
  630. /**
  631. * @hidden
  632. * DOM WRITE
  633. */
  634. VirtualScroll.prototype.scrollEnd = function () {
  635. var _this = this;
  636. // ******** DOM READ ****************
  637. virtual_util_1.updateDimensions(this._plt, this._nodes, this._cells, this._data, false);
  638. virtual_util_1.adjustRendered(this._cells, this._data);
  639. virtual_util_1.populateNodeData(this._data.topCell, this._data.bottomCell, true, this._cells, this._records, this._nodes, this._itmTmp.viewContainer, this._itmTmp.templateRef, this._hdrTmp && this._hdrTmp.templateRef, this._ftrTmp && this._ftrTmp.templateRef);
  640. // ******** DOM WRITE ***************
  641. this._dom.write(function () {
  642. // update the bound context for each node
  643. virtual_util_1.updateNodeContext(_this._nodes, _this._cells, _this._data);
  644. // ******** DOM WRITE ***************
  645. _this._stepChangeDetection();
  646. // ******** DOM WRITE ****************
  647. _this._stepDOMWrite();
  648. });
  649. };
  650. /**
  651. * @hidden
  652. * NO DOM
  653. */
  654. VirtualScroll.prototype._listeners = function () {
  655. (void 0) /* assert */;
  656. if (!this._scrollSub) {
  657. if (this._config.getBoolean('virtualScrollEventAssist')) {
  658. // use JS scrolling for iOS UIWebView
  659. // goal is to completely remove this when iOS
  660. // fully supports scroll events
  661. // listen to JS scroll events
  662. this._content.enableJsScroll();
  663. }
  664. this._resizeSub = this._plt.resize.subscribe(this.resize.bind(this));
  665. this._scrollSub = this._content.ionScroll.subscribe(this.scrollUpdate.bind(this));
  666. this._scrollEndSub = this._content.ionScrollEnd.subscribe(this.scrollEnd.bind(this));
  667. }
  668. };
  669. /**
  670. * @hidden
  671. * DOM WRITE
  672. */
  673. VirtualScroll.prototype._setHeight = function (newVirtualHeight) {
  674. if (newVirtualHeight !== this._vHeight) {
  675. // ******** DOM WRITE ****************
  676. this._renderer.setElementStyle(this._elementRef.nativeElement, 'height', newVirtualHeight > 0 ? newVirtualHeight + 'px' : '');
  677. this._vHeight = newVirtualHeight;
  678. (void 0) /* console.debug */;
  679. }
  680. };
  681. /**
  682. * @hidden
  683. */
  684. VirtualScroll.prototype.ngAfterContentInit = function () {
  685. (void 0) /* assert */;
  686. if (!this.approxItemHeight) {
  687. this.approxItemHeight = '40px';
  688. console.warn('Virtual Scroll: Please provide an "approxItemHeight" input to ensure proper virtual scroll rendering');
  689. }
  690. };
  691. /**
  692. * @hidden
  693. */
  694. VirtualScroll.prototype.setElementClass = function (className, add) {
  695. this._renderer.setElementClass(this._elementRef.nativeElement, className, add);
  696. };
  697. /**
  698. * @hidden
  699. */
  700. VirtualScroll.prototype.ngOnDestroy = function () {
  701. this._resizeSub && this._resizeSub.unsubscribe();
  702. this._scrollSub && this._scrollSub.unsubscribe();
  703. this._scrollEndSub && this._scrollEndSub.unsubscribe();
  704. this._resizeSub = this._scrollEndSub = this._scrollSub = null;
  705. this._hdrFn = this._ftrFn = this._records = this._cells = this._nodes = this._data = null;
  706. };
  707. VirtualScroll.decorators = [
  708. { type: core_1.Directive, args: [{
  709. selector: '[virtualScroll]'
  710. },] },
  711. ];
  712. /** @nocollapse */
  713. VirtualScroll.ctorParameters = function () { return [
  714. { type: core_1.IterableDiffers, },
  715. { type: core_1.ElementRef, },
  716. { type: core_1.Renderer, },
  717. { type: core_1.NgZone, },
  718. { type: core_1.ChangeDetectorRef, },
  719. { type: content_1.Content, },
  720. { type: platform_1.Platform, },
  721. { type: view_controller_1.ViewController, },
  722. { type: config_1.Config, },
  723. { type: dom_controller_1.DomController, },
  724. ]; };
  725. VirtualScroll.propDecorators = {
  726. '_itmTmp': [{ type: core_1.ContentChild, args: [virtual_item_1.VirtualItem,] },],
  727. '_hdrTmp': [{ type: core_1.ContentChild, args: [virtual_header_1.VirtualHeader,] },],
  728. '_ftrTmp': [{ type: core_1.ContentChild, args: [virtual_footer_1.VirtualFooter,] },],
  729. 'virtualScroll': [{ type: core_1.Input },],
  730. 'bufferRatio': [{ type: core_1.Input },],
  731. 'approxItemWidth': [{ type: core_1.Input },],
  732. 'approxItemHeight': [{ type: core_1.Input },],
  733. 'approxHeaderWidth': [{ type: core_1.Input },],
  734. 'approxHeaderHeight': [{ type: core_1.Input },],
  735. 'approxFooterWidth': [{ type: core_1.Input },],
  736. 'approxFooterHeight': [{ type: core_1.Input },],
  737. 'headerFn': [{ type: core_1.Input },],
  738. 'footerFn': [{ type: core_1.Input },],
  739. 'virtualTrackBy': [{ type: core_1.Input },],
  740. };
  741. return VirtualScroll;
  742. }());
  743. exports.VirtualScroll = VirtualScroll;
  744. var SCROLL_DIFFERENCE_MINIMUM = 40;
  745. });
  746. //# sourceMappingURL=virtual-scroll.js.map