infinity.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. /*!
  2. * better-scroll / infinity
  3. * (c) 2016-2021 ustbhuangyi
  4. * Released under the MIT License.
  5. */
  6. (function (global, factory) {
  7. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  8. typeof define === 'function' && define.amd ? define(factory) :
  9. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Infinity = factory());
  10. }(this, (function () { 'use strict';
  11. function warn(msg) {
  12. console.error("[BScroll warn]: " + msg);
  13. }
  14. /*! *****************************************************************************
  15. Copyright (c) Microsoft Corporation.
  16. Permission to use, copy, modify, and/or distribute this software for any
  17. purpose with or without fee is hereby granted.
  18. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  19. REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  20. AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  21. INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  22. LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  23. OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  24. PERFORMANCE OF THIS SOFTWARE.
  25. ***************************************************************************** */
  26. var __assign = function() {
  27. __assign = Object.assign || function __assign(t) {
  28. for (var s, i = 1, n = arguments.length; i < n; i++) {
  29. s = arguments[i];
  30. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
  31. }
  32. return t;
  33. };
  34. return __assign.apply(this, arguments);
  35. };
  36. function __awaiter(thisArg, _arguments, P, generator) {
  37. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  38. return new (P || (P = Promise))(function (resolve, reject) {
  39. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  40. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  41. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  42. step((generator = generator.apply(thisArg, _arguments || [])).next());
  43. });
  44. }
  45. function __generator(thisArg, body) {
  46. var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
  47. return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
  48. function verb(n) { return function (v) { return step([n, v]); }; }
  49. function step(op) {
  50. if (f) throw new TypeError("Generator is already executing.");
  51. while (_) try {
  52. if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
  53. if (y = 0, t) op = [op[0] & 2, t.value];
  54. switch (op[0]) {
  55. case 0: case 1: t = op; break;
  56. case 4: _.label++; return { value: op[1], done: false };
  57. case 5: _.label++; y = op[1]; op = [0]; continue;
  58. case 7: op = _.ops.pop(); _.trys.pop(); continue;
  59. default:
  60. if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
  61. if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
  62. if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
  63. if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
  64. if (t[2]) _.ops.pop();
  65. _.trys.pop(); continue;
  66. }
  67. op = body.call(thisArg, _);
  68. } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
  69. if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
  70. }
  71. }
  72. // ssr support
  73. var inBrowser = typeof window !== 'undefined';
  74. var ua = inBrowser && navigator.userAgent.toLowerCase();
  75. !!(ua && /wechatdevtools/.test(ua));
  76. ua && ua.indexOf('android') > 0;
  77. /* istanbul ignore next */
  78. ((function () {
  79. if (typeof ua === 'string') {
  80. var regex = /os (\d\d?_\d(_\d)?)/;
  81. var matches = regex.exec(ua);
  82. if (!matches)
  83. return false;
  84. var parts = matches[1].split('_').map(function (item) {
  85. return parseInt(item, 10);
  86. });
  87. // ios version >= 13.4 issue 982
  88. return !!(parts[0] === 13 && parts[1] >= 4);
  89. }
  90. return false;
  91. }))();
  92. /* istanbul ignore next */
  93. var supportsPassive = false;
  94. /* istanbul ignore next */
  95. if (inBrowser) {
  96. var EventName = 'test-passive';
  97. try {
  98. var opts = {};
  99. Object.defineProperty(opts, 'passive', {
  100. get: function () {
  101. supportsPassive = true;
  102. },
  103. }); // https://github.com/facebook/flow/issues/285
  104. window.addEventListener(EventName, function () { }, opts);
  105. }
  106. catch (e) { }
  107. }
  108. var elementStyle = (inBrowser &&
  109. document.createElement('div').style);
  110. var vendor = (function () {
  111. /* istanbul ignore if */
  112. if (!inBrowser) {
  113. return false;
  114. }
  115. var transformNames = [
  116. {
  117. key: 'standard',
  118. value: 'transform',
  119. },
  120. {
  121. key: 'webkit',
  122. value: 'webkitTransform',
  123. },
  124. {
  125. key: 'Moz',
  126. value: 'MozTransform',
  127. },
  128. {
  129. key: 'O',
  130. value: 'OTransform',
  131. },
  132. {
  133. key: 'ms',
  134. value: 'msTransform',
  135. },
  136. ];
  137. for (var _i = 0, transformNames_1 = transformNames; _i < transformNames_1.length; _i++) {
  138. var obj = transformNames_1[_i];
  139. if (elementStyle[obj.value] !== undefined) {
  140. return obj.key;
  141. }
  142. }
  143. /* istanbul ignore next */
  144. return false;
  145. })();
  146. /* istanbul ignore next */
  147. function prefixStyle(style) {
  148. if (vendor === false) {
  149. return style;
  150. }
  151. if (vendor === 'standard') {
  152. if (style === 'transitionEnd') {
  153. return 'transitionend';
  154. }
  155. return style;
  156. }
  157. return vendor + style.charAt(0).toUpperCase() + style.substr(1);
  158. }
  159. var cssVendor = vendor && vendor !== 'standard' ? '-' + vendor.toLowerCase() + '-' : '';
  160. var transform = prefixStyle('transform');
  161. var transition = prefixStyle('transition');
  162. inBrowser && prefixStyle('perspective') in elementStyle;
  163. var style = {
  164. transform: transform,
  165. transition: transition,
  166. transitionTimingFunction: prefixStyle('transitionTimingFunction'),
  167. transitionDuration: prefixStyle('transitionDuration'),
  168. transitionDelay: prefixStyle('transitionDelay'),
  169. transformOrigin: prefixStyle('transformOrigin'),
  170. transitionEnd: prefixStyle('transitionEnd'),
  171. transitionProperty: prefixStyle('transitionProperty'),
  172. };
  173. var PRE_NUM = 10;
  174. var POST_NUM = 30;
  175. var IndexCalculator = /** @class */ (function () {
  176. function IndexCalculator(wrapperHeight, tombstoneHeight) {
  177. this.wrapperHeight = wrapperHeight;
  178. this.tombstoneHeight = tombstoneHeight;
  179. this.lastDirection = 1 /* DOWN */;
  180. this.lastPos = 0;
  181. }
  182. IndexCalculator.prototype.calculate = function (pos, list) {
  183. var offset = pos - this.lastPos;
  184. this.lastPos = pos;
  185. var direction = this.getDirection(offset);
  186. // important! start index is much more important than end index.
  187. var start = this.calculateIndex(0, pos, list);
  188. var end = this.calculateIndex(start, pos + this.wrapperHeight, list);
  189. if (direction === 1 /* DOWN */) {
  190. start -= PRE_NUM;
  191. end += POST_NUM;
  192. }
  193. else {
  194. start -= POST_NUM;
  195. end += PRE_NUM;
  196. }
  197. if (start < 0) {
  198. start = 0;
  199. }
  200. return {
  201. start: start,
  202. end: end,
  203. };
  204. };
  205. IndexCalculator.prototype.getDirection = function (offset) {
  206. var direction;
  207. if (offset > 0) {
  208. direction = 1 /* DOWN */;
  209. }
  210. else if (offset < 0) {
  211. direction = 0 /* UP */;
  212. }
  213. else {
  214. return this.lastDirection;
  215. }
  216. this.lastDirection = direction;
  217. return direction;
  218. };
  219. IndexCalculator.prototype.calculateIndex = function (start, offset, list) {
  220. if (offset <= 0) {
  221. return start;
  222. }
  223. var i = start;
  224. var startPos = list[i] && list[i].pos !== -1 ? list[i].pos : 0;
  225. var lastPos = startPos;
  226. var tombstone = 0;
  227. while (i < list.length && list[i].pos < offset) {
  228. lastPos = list[i].pos;
  229. i++;
  230. }
  231. if (i === list.length) {
  232. tombstone = Math.floor((offset - lastPos) / this.tombstoneHeight);
  233. }
  234. i += tombstone;
  235. return i;
  236. };
  237. IndexCalculator.prototype.resetState = function () {
  238. this.lastDirection = 1 /* DOWN */;
  239. this.lastPos = 0;
  240. };
  241. return IndexCalculator;
  242. }());
  243. var ListItem = /** @class */ (function () {
  244. function ListItem() {
  245. this.data = null;
  246. this.dom = null;
  247. this.tombstone = null;
  248. this.width = 0;
  249. this.height = 0;
  250. this.pos = 0;
  251. }
  252. return ListItem;
  253. }());
  254. var DataManager = /** @class */ (function () {
  255. function DataManager(list, fetchFn, onFetchFinish) {
  256. this.fetchFn = fetchFn;
  257. this.onFetchFinish = onFetchFinish;
  258. this.loadedNum = 0;
  259. this.fetching = false;
  260. this.hasMore = true;
  261. this.list = list || [];
  262. }
  263. DataManager.prototype.update = function (end) {
  264. return __awaiter(this, void 0, void 0, function () {
  265. var len;
  266. return __generator(this, function (_a) {
  267. if (!this.hasMore) {
  268. end = Math.min(end, this.list.length);
  269. }
  270. // add data placeholder
  271. if (end > this.list.length) {
  272. len = end - this.list.length;
  273. this.addEmptyData(len);
  274. }
  275. // tslint:disable-next-line: no-floating-promises
  276. return [2 /*return*/, this.checkToFetch(end)];
  277. });
  278. });
  279. };
  280. DataManager.prototype.add = function (data) {
  281. for (var i = 0; i < data.length; i++) {
  282. if (!this.list[this.loadedNum]) {
  283. this.list[this.loadedNum] = { data: data[i] };
  284. }
  285. else {
  286. this.list[this.loadedNum] = __assign(__assign({}, this.list[this.loadedNum]), { data: data[i] });
  287. }
  288. this.loadedNum++;
  289. }
  290. return this.list;
  291. };
  292. DataManager.prototype.addEmptyData = function (len) {
  293. for (var i = 0; i < len; i++) {
  294. this.list.push(new ListItem());
  295. }
  296. return this.list;
  297. };
  298. DataManager.prototype.fetch = function (len) {
  299. return __awaiter(this, void 0, void 0, function () {
  300. var data;
  301. return __generator(this, function (_a) {
  302. switch (_a.label) {
  303. case 0:
  304. if (this.fetching) {
  305. return [2 /*return*/, []];
  306. }
  307. this.fetching = true;
  308. return [4 /*yield*/, this.fetchFn(len)];
  309. case 1:
  310. data = _a.sent();
  311. this.fetching = false;
  312. return [2 /*return*/, data];
  313. }
  314. });
  315. });
  316. };
  317. DataManager.prototype.checkToFetch = function (end) {
  318. return __awaiter(this, void 0, void 0, function () {
  319. var min, newData, currentEnd;
  320. return __generator(this, function (_a) {
  321. switch (_a.label) {
  322. case 0:
  323. if (!this.hasMore) {
  324. return [2 /*return*/];
  325. }
  326. if (end <= this.loadedNum) {
  327. return [2 /*return*/];
  328. }
  329. min = end - this.loadedNum;
  330. return [4 /*yield*/, this.fetch(min)];
  331. case 1:
  332. newData = _a.sent();
  333. if (newData instanceof Array && newData.length) {
  334. this.add(newData);
  335. currentEnd = this.onFetchFinish(this.list, true);
  336. return [2 /*return*/, this.checkToFetch(currentEnd)];
  337. }
  338. else if (typeof newData === 'boolean' && newData === false) {
  339. this.hasMore = false;
  340. this.list.splice(this.loadedNum);
  341. this.onFetchFinish(this.list, false);
  342. }
  343. return [2 /*return*/];
  344. }
  345. });
  346. });
  347. };
  348. DataManager.prototype.getList = function () {
  349. return this.list;
  350. };
  351. DataManager.prototype.resetState = function () {
  352. this.loadedNum = 0;
  353. this.fetching = false;
  354. this.hasMore = true;
  355. this.list = [];
  356. };
  357. return DataManager;
  358. }());
  359. var Tombstone = /** @class */ (function () {
  360. function Tombstone(create) {
  361. this.create = create;
  362. this.cached = [];
  363. this.width = 0;
  364. this.height = 0;
  365. this.initialed = false;
  366. this.getSize();
  367. }
  368. Tombstone.isTombstone = function (el) {
  369. if (el && el.classList) {
  370. return el.classList.contains('tombstone');
  371. }
  372. return false;
  373. };
  374. Tombstone.prototype.getSize = function () {
  375. if (!this.initialed) {
  376. var tombstone = this.create();
  377. tombstone.style.position = 'absolute';
  378. document.body.appendChild(tombstone);
  379. tombstone.style.display = '';
  380. this.height = tombstone.offsetHeight;
  381. this.width = tombstone.offsetWidth;
  382. document.body.removeChild(tombstone);
  383. this.cached.push(tombstone);
  384. }
  385. };
  386. Tombstone.prototype.getOne = function () {
  387. var tombstone = this.cached.pop();
  388. if (tombstone) {
  389. var tombstoneStyle = tombstone.style;
  390. tombstoneStyle.display = '';
  391. tombstoneStyle.opacity = '1';
  392. tombstoneStyle[style.transform] = '';
  393. tombstoneStyle[style.transition] = '';
  394. return tombstone;
  395. }
  396. return this.create();
  397. };
  398. Tombstone.prototype.recycle = function (tombstones) {
  399. for (var _i = 0, tombstones_1 = tombstones; _i < tombstones_1.length; _i++) {
  400. var tombstone = tombstones_1[_i];
  401. tombstone.style.display = 'none';
  402. this.cached.push(tombstone);
  403. }
  404. return this.cached;
  405. };
  406. Tombstone.prototype.recycleOne = function (tombstone) {
  407. this.cached.push(tombstone);
  408. return this.cached;
  409. };
  410. return Tombstone;
  411. }());
  412. var ANIMATION_DURATION_MS = 200;
  413. var DomManager = /** @class */ (function () {
  414. function DomManager(content, renderFn, tombstone) {
  415. this.renderFn = renderFn;
  416. this.tombstone = tombstone;
  417. this.unusedDom = [];
  418. this.timers = [];
  419. this.setContent(content);
  420. }
  421. DomManager.prototype.update = function (list, start, end) {
  422. if (start >= list.length) {
  423. start = list.length - 1;
  424. }
  425. if (end > list.length) {
  426. end = list.length;
  427. }
  428. this.collectUnusedDom(list, start, end);
  429. this.createDom(list, start, end);
  430. this.cacheHeight(list, start, end);
  431. var _a = this.positionDom(list, start, end), startPos = _a.startPos, startDelta = _a.startDelta, endPos = _a.endPos;
  432. return {
  433. start: start,
  434. startPos: startPos,
  435. startDelta: startDelta,
  436. end: end,
  437. endPos: endPos,
  438. };
  439. };
  440. DomManager.prototype.collectUnusedDom = function (list, start, end) {
  441. // TODO optimise
  442. for (var i = 0; i < list.length; i++) {
  443. if (i === start) {
  444. i = end - 1;
  445. continue;
  446. }
  447. if (list[i].dom) {
  448. var dom = list[i].dom;
  449. if (Tombstone.isTombstone(dom)) {
  450. this.tombstone.recycleOne(dom);
  451. dom.style.display = 'none';
  452. }
  453. else {
  454. this.unusedDom.push(dom);
  455. }
  456. list[i].dom = null;
  457. }
  458. }
  459. return list;
  460. };
  461. DomManager.prototype.createDom = function (list, start, end) {
  462. for (var i = start; i < end; i++) {
  463. var dom = list[i].dom;
  464. var data = list[i].data;
  465. if (dom) {
  466. if (Tombstone.isTombstone(dom) && data) {
  467. list[i].tombstone = dom;
  468. list[i].dom = null;
  469. }
  470. else {
  471. continue;
  472. }
  473. }
  474. dom = data
  475. ? this.renderFn(data, this.unusedDom.pop())
  476. : this.tombstone.getOne();
  477. dom.style.position = 'absolute';
  478. list[i].dom = dom;
  479. list[i].pos = -1;
  480. this.content.appendChild(dom);
  481. }
  482. };
  483. DomManager.prototype.cacheHeight = function (list, start, end) {
  484. for (var i = start; i < end; i++) {
  485. if (list[i].data && !list[i].height) {
  486. list[i].height = list[i].dom.offsetHeight;
  487. }
  488. }
  489. };
  490. DomManager.prototype.positionDom = function (list, start, end) {
  491. var _this = this;
  492. var tombstoneEles = [];
  493. var _a = this.getStartPos(list, start, end), startPos = _a.start, startDelta = _a.delta;
  494. var pos = startPos;
  495. for (var i = start; i < end; i++) {
  496. var tombstone = list[i].tombstone;
  497. if (tombstone) {
  498. var tombstoneStyle = tombstone.style;
  499. tombstoneStyle[style.transition] = cssVendor + "transform " + ANIMATION_DURATION_MS + "ms, opacity " + ANIMATION_DURATION_MS + "ms";
  500. tombstoneStyle[style.transform] = "translateY(" + pos + "px)";
  501. tombstoneStyle.opacity = '0';
  502. list[i].tombstone = null;
  503. tombstoneEles.push(tombstone);
  504. }
  505. if (list[i].dom && list[i].pos !== pos) {
  506. list[i].dom.style[style.transform] = "translateY(" + pos + "px)";
  507. list[i].pos = pos;
  508. }
  509. pos += list[i].height || this.tombstone.height;
  510. }
  511. var timerId = window.setTimeout(function () {
  512. _this.tombstone.recycle(tombstoneEles);
  513. }, ANIMATION_DURATION_MS);
  514. this.timers.push(timerId);
  515. return {
  516. startPos: startPos,
  517. startDelta: startDelta,
  518. endPos: pos,
  519. };
  520. };
  521. DomManager.prototype.getStartPos = function (list, start, end) {
  522. if (list[start] && list[start].pos !== -1) {
  523. return {
  524. start: list[start].pos,
  525. delta: 0,
  526. };
  527. }
  528. // TODO optimise
  529. var pos = list[0].pos === -1 ? 0 : list[0].pos;
  530. for (var i_1 = 0; i_1 < start; i_1++) {
  531. pos += list[i_1].height || this.tombstone.height;
  532. }
  533. var originPos = pos;
  534. var i;
  535. for (i = start; i < end; i++) {
  536. if (!Tombstone.isTombstone(list[i].dom) && list[i].pos !== -1) {
  537. pos = list[i].pos;
  538. break;
  539. }
  540. }
  541. var x = i;
  542. if (x < end) {
  543. while (x > start) {
  544. pos -= list[x - 1].height;
  545. x--;
  546. }
  547. }
  548. var delta = originPos - pos;
  549. return {
  550. start: pos,
  551. delta: delta,
  552. };
  553. };
  554. DomManager.prototype.removeTombstone = function () {
  555. var tombstones = this.content.querySelectorAll('.tombstone');
  556. for (var i = tombstones.length - 1; i >= 0; i--) {
  557. this.content.removeChild(tombstones[i]);
  558. }
  559. };
  560. DomManager.prototype.setContent = function (content) {
  561. if (content !== this.content) {
  562. this.content = content;
  563. }
  564. };
  565. DomManager.prototype.destroy = function () {
  566. this.removeTombstone();
  567. this.timers.forEach(function (id) {
  568. clearTimeout(id);
  569. });
  570. };
  571. DomManager.prototype.resetState = function () {
  572. this.destroy();
  573. this.timers = [];
  574. this.unusedDom = [];
  575. };
  576. return DomManager;
  577. }());
  578. var EXTRA_SCROLL_Y = -2000;
  579. var InfinityScroll = /** @class */ (function () {
  580. function InfinityScroll(scroll) {
  581. this.scroll = scroll;
  582. this.start = 0;
  583. this.end = 0;
  584. this.init();
  585. }
  586. InfinityScroll.prototype.init = function () {
  587. var _this = this;
  588. this.handleOptions();
  589. var _a = this.options, fetchFn = _a.fetch, renderFn = _a.render, createTombstoneFn = _a.createTombstone;
  590. this.tombstone = new Tombstone(createTombstoneFn);
  591. this.indexCalculator = new IndexCalculator(this.scroll.scroller.scrollBehaviorY.wrapperSize, this.tombstone.height);
  592. this.domManager = new DomManager(this.scroll.scroller.content, renderFn, this.tombstone);
  593. this.dataManager = new DataManager([], fetchFn, this.onFetchFinish.bind(this));
  594. this.scroll.on(this.scroll.eventTypes.destroy, this.destroy, this);
  595. this.scroll.on(this.scroll.eventTypes.scroll, this.update, this);
  596. this.scroll.on(this.scroll.eventTypes.contentChanged, function (content) {
  597. _this.domManager.setContent(content);
  598. _this.indexCalculator.resetState();
  599. _this.domManager.resetState();
  600. _this.dataManager.resetState();
  601. _this.update({ y: 0 });
  602. });
  603. var scrollBehaviorY = this.scroll.scroller.scrollBehaviorY;
  604. scrollBehaviorY.hooks.on(scrollBehaviorY.hooks.eventTypes.computeBoundary, this.modifyBoundary, this);
  605. this.update({ y: 0 });
  606. };
  607. InfinityScroll.prototype.modifyBoundary = function (boundary) {
  608. // manually set position to allow scroll
  609. boundary.maxScrollPos = EXTRA_SCROLL_Y;
  610. };
  611. InfinityScroll.prototype.handleOptions = function () {
  612. // narrow down type to an object
  613. var infinityOptions = this.scroll.options.infinity;
  614. if (infinityOptions) {
  615. if (typeof infinityOptions.fetch !== 'function') {
  616. warn('Infinity plugin need fetch Function to new data.');
  617. }
  618. if (typeof infinityOptions.render !== 'function') {
  619. warn('Infinity plugin need render Function to render each item.');
  620. }
  621. if (typeof infinityOptions.render !== 'function') {
  622. warn('Infinity plugin need createTombstone Function to create tombstone.');
  623. }
  624. this.options = infinityOptions;
  625. }
  626. this.scroll.options.probeType = 3 /* Realtime */;
  627. };
  628. InfinityScroll.prototype.update = function (pos) {
  629. var position = Math.round(-pos.y);
  630. // important! calculate start/end index to render
  631. var _a = this.indexCalculator.calculate(position, this.dataManager.getList()), start = _a.start, end = _a.end;
  632. this.start = start;
  633. this.end = end;
  634. // tslint:disable-next-line: no-floating-promises
  635. this.dataManager.update(end);
  636. this.updateDom(this.dataManager.getList());
  637. };
  638. InfinityScroll.prototype.onFetchFinish = function (list, hasMore) {
  639. var end = this.updateDom(list).end;
  640. if (!hasMore) {
  641. this.domManager.removeTombstone();
  642. this.scroll.scroller.animater.stop();
  643. this.scroll.resetPosition();
  644. }
  645. // tslint:disable-next-line: no-floating-promises
  646. return end;
  647. };
  648. InfinityScroll.prototype.updateDom = function (list) {
  649. var _a = this.domManager.update(list, this.start, this.end), end = _a.end, startPos = _a.startPos, endPos = _a.endPos, startDelta = _a.startDelta;
  650. if (startDelta) {
  651. this.scroll.minScrollY = startDelta;
  652. }
  653. if (endPos > this.scroll.maxScrollY) {
  654. this.scroll.maxScrollY = -(endPos - this.scroll.scroller.scrollBehaviorY.wrapperSize);
  655. }
  656. return {
  657. end: end,
  658. startPos: startPos,
  659. endPos: endPos,
  660. };
  661. };
  662. InfinityScroll.prototype.destroy = function () {
  663. var _a = this.scroll.scroller, content = _a.content, scrollBehaviorY = _a.scrollBehaviorY;
  664. while (content.firstChild) {
  665. content.removeChild(content.firstChild);
  666. }
  667. this.domManager.destroy();
  668. this.scroll.off('scroll', this.update);
  669. this.scroll.off('destroy', this.destroy);
  670. scrollBehaviorY.hooks.off(scrollBehaviorY.hooks.eventTypes.computeBoundary);
  671. };
  672. InfinityScroll.pluginName = 'infinity';
  673. return InfinityScroll;
  674. }());
  675. return InfinityScroll;
  676. })));