UI for Zipcoin Blue

content.js 34KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946
  1. var __extends = (this && this.__extends) || (function () {
  2. var extendStatics = Object.setPrototypeOf ||
  3. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  4. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  5. return function (d, b) {
  6. extendStatics(d, b);
  7. function __() { this.constructor = d; }
  8. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  9. };
  10. })();
  11. import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, NgZone, Optional, Output, Renderer, ViewChild, ViewEncapsulation } from '@angular/core';
  12. import { App } from '../app/app';
  13. import { Config } from '../../config/config';
  14. import { DomController } from '../../platform/dom-controller';
  15. import { Ion } from '../ion';
  16. import { isTabs } from '../../navigation/nav-util';
  17. import { isTrueProperty, removeArrayItem } from '../../util/util';
  18. import { Keyboard } from '../../platform/keyboard';
  19. import { NavController } from '../../navigation/nav-controller';
  20. import { Platform } from '../../platform/platform';
  21. import { ScrollView } from '../../util/scroll-view';
  22. import { ViewController } from '../../navigation/view-controller';
  23. var EventEmitterProxy = (function (_super) {
  24. __extends(EventEmitterProxy, _super);
  25. function EventEmitterProxy() {
  26. return _super !== null && _super.apply(this, arguments) || this;
  27. }
  28. EventEmitterProxy.prototype.subscribe = function (generatorOrNext, error, complete) {
  29. this.onSubscribe();
  30. return _super.prototype.subscribe.call(this, generatorOrNext, error, complete);
  31. };
  32. return EventEmitterProxy;
  33. }(EventEmitter));
  34. export { EventEmitterProxy };
  35. /**
  36. * @name Content
  37. * @description
  38. * The Content component provides an easy to use content area with
  39. * some useful methods to control the scrollable area. There should
  40. * only be one content in a single view component. If additional scrollable
  41. * elements are needed, use [ionScroll](../../scroll/Scroll).
  42. *
  43. *
  44. * The content area can also implement pull-to-refresh with the
  45. * [Refresher](../../refresher/Refresher) component.
  46. *
  47. * @usage
  48. * ```html
  49. * <ion-content>
  50. * Add your content here!
  51. * </ion-content>
  52. * ```
  53. *
  54. * To get a reference to the content component from a Page's logic,
  55. * you can use Angular's `@ViewChild` annotation:
  56. *
  57. * ```ts
  58. * import { Component, ViewChild } from '@angular/core';
  59. * import { Content } from 'ionic-angular';
  60. *
  61. * @Component({...})
  62. * export class MyPage{
  63. * @ViewChild(Content) content: Content;
  64. *
  65. * scrollToTop() {
  66. * this.content.scrollToTop();
  67. * }
  68. * }
  69. * ```
  70. *
  71. * @advanced
  72. *
  73. * ### Scroll Events
  74. *
  75. * Scroll events happen outside of Angular's Zones. This is for performance reasons. So
  76. * if you're trying to bind a value to any scroll event, it will need to be wrapped in
  77. * a `zone.run()`
  78. *
  79. * ```ts
  80. * import { Component, NgZone } from '@angular/core';
  81. * @Component({
  82. * template: `
  83. * <ion-header>
  84. * <ion-navbar>
  85. * <ion-title>{{scrollAmount}}</ion-title>
  86. * </ion-navbar>
  87. * </ion-header>
  88. * <ion-content (ionScroll)="scrollHandler($event)">
  89. * <p> Some realllllllly long content </p>
  90. * </ion-content>
  91. * `})
  92. * class E2EPage {
  93. * public scrollAmount = 0;
  94. * constructor( public zone: NgZone){}
  95. * scrollHandler(event) {
  96. * console.log(`ScrollEvent: ${event}`)
  97. * this.zone.run(()=>{
  98. * // since scrollAmount is data-binded,
  99. * // the update needs to happen in zone
  100. * this.scrollAmount++
  101. * })
  102. * }
  103. * }
  104. * ```
  105. *
  106. * This goes for any scroll event, not just `ionScroll`.
  107. *
  108. * ### Resizing the content
  109. *
  110. * If the height of `ion-header`, `ion-footer` or `ion-tabbar`
  111. * changes dynamically, `content.resize()` has to be called in order to update the
  112. * layout of `Content`.
  113. *
  114. *
  115. * ```ts
  116. * @Component({
  117. * template: `
  118. * <ion-header>
  119. * <ion-navbar>
  120. * <ion-title>Main Navbar</ion-title>
  121. * </ion-navbar>
  122. * <ion-toolbar *ngIf="showToolbar">
  123. * <ion-title>Dynamic Toolbar</ion-title>
  124. * </ion-toolbar>
  125. * </ion-header>
  126. * <ion-content>
  127. * <button ion-button (click)="toggleToolbar()">Toggle Toolbar</button>
  128. * </ion-content>
  129. * `})
  130. *
  131. * class E2EPage {
  132. * @ViewChild(Content) content: Content;
  133. * showToolbar: boolean = false;
  134. *
  135. * toggleToolbar() {
  136. * this.showToolbar = !this.showToolbar;
  137. * this.content.resize();
  138. * }
  139. * }
  140. * ```
  141. *
  142. *
  143. * Scroll to a specific position
  144. *
  145. * ```ts
  146. * import { Component, ViewChild } from '@angular/core';
  147. * import { Content } from 'ionic-angular';
  148. *
  149. * @Component({
  150. * template: `<ion-content>
  151. * <button ion-button (click)="scrollTo()">Down 500px</button>
  152. * </ion-content>`
  153. * )}
  154. * export class MyPage{
  155. * @ViewChild(Content) content: Content;
  156. *
  157. * scrollTo() {
  158. * // set the scrollLeft to 0px, and scrollTop to 500px
  159. * // the scroll duration should take 200ms
  160. * this.content.scrollTo(0, 500, 200);
  161. * }
  162. * }
  163. * ```
  164. *
  165. */
  166. var Content = (function (_super) {
  167. __extends(Content, _super);
  168. function Content(config, _plt, _dom, elementRef, renderer, _app, _keyboard, _zone, viewCtrl, navCtrl) {
  169. var _this = _super.call(this, config, elementRef, renderer, 'content') || this;
  170. _this._plt = _plt;
  171. _this._dom = _dom;
  172. _this._app = _app;
  173. _this._keyboard = _keyboard;
  174. _this._zone = _zone;
  175. /** @internal */
  176. _this._scrollPadding = 0;
  177. /** @internal */
  178. _this._inputPolling = false;
  179. /** @internal */
  180. _this._hasRefresher = false;
  181. /** @internal */
  182. _this._imgs = [];
  183. /** @internal */
  184. _this._scrollDownOnLoad = false;
  185. /**
  186. * @output {ScrollEvent} Emitted when the scrolling first starts.
  187. */
  188. _this.ionScrollStart = new EventEmitterProxy();
  189. /**
  190. * @output {ScrollEvent} Emitted on every scroll event.
  191. */
  192. _this.ionScroll = new EventEmitterProxy();
  193. /**
  194. * @output {ScrollEvent} Emitted when scrolling ends.
  195. */
  196. _this.ionScrollEnd = new EventEmitterProxy();
  197. var enableScrollListener = function () { return _this._scroll.enableEvents(); };
  198. _this.ionScroll.onSubscribe = enableScrollListener;
  199. _this.ionScrollStart.onSubscribe = enableScrollListener;
  200. _this.ionScrollEnd.onSubscribe = enableScrollListener;
  201. _this.statusbarPadding = config.getBoolean('statusbarPadding', false);
  202. _this._imgReqBfr = config.getNumber('imgRequestBuffer', 1400);
  203. _this._imgRndBfr = config.getNumber('imgRenderBuffer', 400);
  204. _this._imgVelMax = config.getNumber('imgVelocityMax', 3);
  205. _this._scroll = new ScrollView(_app, _plt, _dom);
  206. while (navCtrl) {
  207. if (isTabs(navCtrl)) {
  208. _this._tabs = navCtrl;
  209. break;
  210. }
  211. navCtrl = navCtrl.parent;
  212. }
  213. if (viewCtrl) {
  214. _this._viewCtrl = viewCtrl;
  215. // content has a view controller
  216. viewCtrl._setIONContent(_this);
  217. viewCtrl._setIONContentRef(elementRef);
  218. _this._viewCtrlReadSub = viewCtrl.readReady.subscribe(function () {
  219. _this._viewCtrlReadSub.unsubscribe();
  220. _this._readDimensions();
  221. });
  222. _this._viewCtrlWriteSub = viewCtrl.writeReady.subscribe(function () {
  223. _this._viewCtrlWriteSub.unsubscribe();
  224. _this._writeDimensions();
  225. });
  226. }
  227. else {
  228. // content does not have a view controller
  229. _dom.read(_this._readDimensions.bind(_this));
  230. _dom.write(_this._writeDimensions.bind(_this));
  231. }
  232. return _this;
  233. }
  234. Object.defineProperty(Content.prototype, "contentHeight", {
  235. /**
  236. * Content height of the viewable area. This does not include content
  237. * which is outside the overflow area, or content area which is under
  238. * headers and footers. Read-only.
  239. *
  240. * @return {number}
  241. */
  242. get: function () {
  243. return this._scroll.ev.contentHeight;
  244. },
  245. enumerable: true,
  246. configurable: true
  247. });
  248. Object.defineProperty(Content.prototype, "contentWidth", {
  249. /**
  250. * Content width including content which is not visible on the screen
  251. * due to overflow. Read-only.
  252. *
  253. * @return {number}
  254. */
  255. get: function () {
  256. return this._scroll.ev.contentWidth;
  257. },
  258. enumerable: true,
  259. configurable: true
  260. });
  261. Object.defineProperty(Content.prototype, "scrollHeight", {
  262. /**
  263. * Content height including content which is not visible on the screen
  264. * due to overflow. Read-only.
  265. *
  266. * @return {number}
  267. */
  268. get: function () {
  269. return this._scroll.ev.scrollHeight;
  270. },
  271. enumerable: true,
  272. configurable: true
  273. });
  274. Object.defineProperty(Content.prototype, "scrollWidth", {
  275. /**
  276. * Content width including content which is not visible due to
  277. * overflow. Read-only.
  278. *
  279. * @return {number}
  280. */
  281. get: function () {
  282. return this._scroll.ev.scrollWidth;
  283. },
  284. enumerable: true,
  285. configurable: true
  286. });
  287. Object.defineProperty(Content.prototype, "scrollTop", {
  288. /**
  289. * The distance of the content's top to its topmost visible content.
  290. *
  291. * @return {number}
  292. */
  293. get: function () {
  294. return this._scroll.ev.scrollTop;
  295. },
  296. /**
  297. * @param {number} top
  298. */
  299. set: function (top) {
  300. this._scroll.setTop(top);
  301. },
  302. enumerable: true,
  303. configurable: true
  304. });
  305. Object.defineProperty(Content.prototype, "scrollLeft", {
  306. /**
  307. * The distance of the content's left to its leftmost visible content.
  308. *
  309. * @return {number}
  310. */
  311. get: function () {
  312. return this._scroll.ev.scrollLeft;
  313. },
  314. /**
  315. * @param {number} top
  316. */
  317. set: function (top) {
  318. this._scroll.setLeft(top);
  319. },
  320. enumerable: true,
  321. configurable: true
  322. });
  323. Object.defineProperty(Content.prototype, "isScrolling", {
  324. /**
  325. * If the content is actively scrolling or not.
  326. *
  327. * @return {boolean}
  328. */
  329. get: function () {
  330. return this._scroll.isScrolling;
  331. },
  332. enumerable: true,
  333. configurable: true
  334. });
  335. Object.defineProperty(Content.prototype, "directionY", {
  336. /**
  337. * The current, or last known, vertical scroll direction. Possible
  338. * string values include `down` and `up`.
  339. *
  340. * @return {string}
  341. */
  342. get: function () {
  343. return this._scroll.ev.directionY;
  344. },
  345. enumerable: true,
  346. configurable: true
  347. });
  348. Object.defineProperty(Content.prototype, "directionX", {
  349. /**
  350. * The current, or last known, horizontal scroll direction. Possible
  351. * string values include `right` and `left`.
  352. *
  353. * @return {string}
  354. */
  355. get: function () {
  356. return this._scroll.ev.directionX;
  357. },
  358. enumerable: true,
  359. configurable: true
  360. });
  361. /**
  362. * @hidden
  363. */
  364. Content.prototype.ngAfterViewInit = function () {
  365. var _this = this;
  366. (void 0) /* assert */;
  367. (void 0) /* assert */;
  368. var scroll = this._scroll;
  369. scroll.ev.fixedElement = this.getFixedElement();
  370. scroll.ev.scrollElement = this.getScrollElement();
  371. // subscribe to the scroll start
  372. scroll.onScrollStart = function (ev) {
  373. _this.ionScrollStart.emit(ev);
  374. };
  375. // subscribe to every scroll move
  376. scroll.onScroll = function (ev) {
  377. // emit to all of our other friends things be scrolling
  378. _this.ionScroll.emit(ev);
  379. _this.imgsUpdate();
  380. };
  381. // subscribe to the scroll end
  382. scroll.onScrollEnd = function (ev) {
  383. _this.ionScrollEnd.emit(ev);
  384. _this.imgsUpdate();
  385. };
  386. };
  387. /**
  388. * @hidden
  389. */
  390. Content.prototype.enableJsScroll = function () {
  391. this._scroll.enableJsScroll(this._cTop, this._cBottom);
  392. };
  393. /**
  394. * @hidden
  395. */
  396. Content.prototype.ngOnDestroy = function () {
  397. this._scLsn && this._scLsn();
  398. this._viewCtrlReadSub && this._viewCtrlReadSub.unsubscribe();
  399. this._viewCtrlWriteSub && this._viewCtrlWriteSub.unsubscribe();
  400. this._viewCtrlReadSub = this._viewCtrlWriteSub = null;
  401. this._scroll && this._scroll.destroy();
  402. this._footerEle = this._scLsn = this._scroll = null;
  403. };
  404. /**
  405. * @hidden
  406. */
  407. Content.prototype.getScrollElement = function () {
  408. return this._scrollContent.nativeElement;
  409. };
  410. /**
  411. * @private
  412. */
  413. Content.prototype.getFixedElement = function () {
  414. return this._fixedContent.nativeElement;
  415. };
  416. /**
  417. * @hidden
  418. */
  419. Content.prototype.onScrollElementTransitionEnd = function (callback) {
  420. this._plt.transitionEnd(this.getScrollElement(), callback);
  421. };
  422. /**
  423. * Scroll to the specified position.
  424. *
  425. * @param {number} x The x-value to scroll to.
  426. * @param {number} y The y-value to scroll to.
  427. * @param {number} [duration] Duration of the scroll animation in milliseconds. Defaults to `300`.
  428. * @returns {Promise} Returns a promise which is resolved when the scroll has completed.
  429. */
  430. Content.prototype.scrollTo = function (x, y, duration, done) {
  431. if (duration === void 0) { duration = 300; }
  432. (void 0) /* console.debug */;
  433. return this._scroll.scrollTo(x, y, duration, done);
  434. };
  435. /**
  436. * Scroll to the top of the content component.
  437. *
  438. * @param {number} [duration] Duration of the scroll animation in milliseconds. Defaults to `300`.
  439. * @returns {Promise} Returns a promise which is resolved when the scroll has completed.
  440. */
  441. Content.prototype.scrollToTop = function (duration) {
  442. if (duration === void 0) { duration = 300; }
  443. (void 0) /* console.debug */;
  444. return this._scroll.scrollToTop(duration);
  445. };
  446. /**
  447. * Scroll to the bottom of the content component.
  448. *
  449. * @param {number} [duration] Duration of the scroll animation in milliseconds. Defaults to `300`.
  450. * @returns {Promise} Returns a promise which is resolved when the scroll has completed.
  451. */
  452. Content.prototype.scrollToBottom = function (duration) {
  453. if (duration === void 0) { duration = 300; }
  454. (void 0) /* console.debug */;
  455. return this._scroll.scrollToBottom(duration);
  456. };
  457. Object.defineProperty(Content.prototype, "fullscreen", {
  458. /**
  459. * @input {boolean} If true, the content will scroll behind the headers
  460. * and footers. This effect can easily be seen by setting the toolbar
  461. * to transparent.
  462. */
  463. get: function () {
  464. return this._fullscreen;
  465. },
  466. set: function (val) {
  467. this._fullscreen = isTrueProperty(val);
  468. },
  469. enumerable: true,
  470. configurable: true
  471. });
  472. Object.defineProperty(Content.prototype, "scrollDownOnLoad", {
  473. /**
  474. * @input {boolean} If true, the content will scroll down on load.
  475. */
  476. get: function () {
  477. return this._scrollDownOnLoad;
  478. },
  479. set: function (val) {
  480. this._scrollDownOnLoad = isTrueProperty(val);
  481. },
  482. enumerable: true,
  483. configurable: true
  484. });
  485. /**
  486. * @private
  487. */
  488. Content.prototype.addImg = function (img) {
  489. this._imgs.push(img);
  490. };
  491. /**
  492. * @hidden
  493. */
  494. Content.prototype.removeImg = function (img) {
  495. removeArrayItem(this._imgs, img);
  496. };
  497. /**
  498. * @hidden
  499. * DOM WRITE
  500. */
  501. Content.prototype.setScrollElementStyle = function (prop, val) {
  502. var scrollEle = this.getScrollElement();
  503. if (scrollEle) {
  504. this._dom.write(function () {
  505. scrollEle.style[prop] = val;
  506. });
  507. }
  508. };
  509. /**
  510. * Returns the content and scroll elements' dimensions.
  511. * @returns {object} dimensions The content and scroll elements' dimensions
  512. * {number} dimensions.contentHeight content offsetHeight
  513. * {number} dimensions.contentTop content offsetTop
  514. * {number} dimensions.contentBottom content offsetTop+offsetHeight
  515. * {number} dimensions.contentWidth content offsetWidth
  516. * {number} dimensions.contentLeft content offsetLeft
  517. * {number} dimensions.contentRight content offsetLeft + offsetWidth
  518. * {number} dimensions.scrollHeight scroll scrollHeight
  519. * {number} dimensions.scrollTop scroll scrollTop
  520. * {number} dimensions.scrollBottom scroll scrollTop + scrollHeight
  521. * {number} dimensions.scrollWidth scroll scrollWidth
  522. * {number} dimensions.scrollLeft scroll scrollLeft
  523. * {number} dimensions.scrollRight scroll scrollLeft + scrollWidth
  524. */
  525. Content.prototype.getContentDimensions = function () {
  526. var scrollEle = this.getScrollElement();
  527. var parentElement = scrollEle.parentElement;
  528. return {
  529. contentHeight: parentElement.offsetHeight - this._cTop - this._cBottom,
  530. contentTop: this._cTop,
  531. contentBottom: this._cBottom,
  532. contentWidth: parentElement.offsetWidth,
  533. contentLeft: parentElement.offsetLeft,
  534. scrollHeight: scrollEle.scrollHeight,
  535. scrollTop: scrollEle.scrollTop,
  536. scrollWidth: scrollEle.scrollWidth,
  537. scrollLeft: scrollEle.scrollLeft,
  538. };
  539. };
  540. /**
  541. * @hidden
  542. * DOM WRITE
  543. * Adds padding to the bottom of the scroll element when the keyboard is open
  544. * so content below the keyboard can be scrolled into view.
  545. */
  546. Content.prototype.addScrollPadding = function (newPadding) {
  547. (void 0) /* assert */;
  548. if (newPadding === 0) {
  549. this._inputPolling = false;
  550. this._scrollPadding = -1;
  551. }
  552. if (newPadding > this._scrollPadding) {
  553. (void 0) /* console.debug */;
  554. this._scrollPadding = newPadding;
  555. var scrollEle = this.getScrollElement();
  556. if (scrollEle) {
  557. this._dom.write(function () {
  558. scrollEle.style.paddingBottom = (newPadding > 0) ? newPadding + 'px' : '';
  559. });
  560. }
  561. }
  562. };
  563. /**
  564. * @hidden
  565. * DOM WRITE
  566. */
  567. Content.prototype.clearScrollPaddingFocusOut = function () {
  568. var _this = this;
  569. if (!this._inputPolling) {
  570. (void 0) /* console.debug */;
  571. this._inputPolling = true;
  572. this._keyboard.onClose(function () {
  573. (void 0) /* console.debug */;
  574. _this.addScrollPadding(0);
  575. }, 200, 3000);
  576. }
  577. };
  578. /**
  579. * Tell the content to recalculate its dimensions. This should be called
  580. * after dynamically adding/removing headers, footers, or tabs.
  581. */
  582. Content.prototype.resize = function () {
  583. this._dom.read(this._readDimensions.bind(this));
  584. this._dom.write(this._writeDimensions.bind(this));
  585. };
  586. /**
  587. * @hidden
  588. * DOM READ
  589. */
  590. Content.prototype._readDimensions = function () {
  591. var cachePaddingTop = this._pTop;
  592. var cachePaddingRight = this._pRight;
  593. var cachePaddingBottom = this._pBottom;
  594. var cachePaddingLeft = this._pLeft;
  595. var cacheHeaderHeight = this._hdrHeight;
  596. var cacheFooterHeight = this._ftrHeight;
  597. var cacheTabsPlacement = this._tabsPlacement;
  598. var tabsTop = 0;
  599. var scrollEvent;
  600. this._pTop = 0;
  601. this._pRight = 0;
  602. this._pBottom = 0;
  603. this._pLeft = 0;
  604. this._hdrHeight = 0;
  605. this._ftrHeight = 0;
  606. this._tabsPlacement = null;
  607. this._tTop = 0;
  608. this._fTop = 0;
  609. this._fBottom = 0;
  610. // In certain cases this._scroll is undefined
  611. // if that is the case then we should just return
  612. if (!this._scroll) {
  613. return;
  614. }
  615. scrollEvent = this._scroll.ev;
  616. var ele = this.getNativeElement();
  617. if (!ele) {
  618. (void 0) /* assert */;
  619. return;
  620. }
  621. var computedStyle;
  622. var tagName;
  623. var parentEle = ele.parentElement;
  624. var children = parentEle.children;
  625. for (var i = children.length - 1; i >= 0; i--) {
  626. ele = children[i];
  627. tagName = ele.tagName;
  628. if (tagName === 'ION-CONTENT') {
  629. scrollEvent.contentElement = ele;
  630. if (this._fullscreen) {
  631. // ******** DOM READ ****************
  632. computedStyle = getComputedStyle(ele);
  633. this._pTop = parsePxUnit(computedStyle.paddingTop);
  634. this._pBottom = parsePxUnit(computedStyle.paddingBottom);
  635. this._pRight = parsePxUnit(computedStyle.paddingRight);
  636. this._pLeft = parsePxUnit(computedStyle.paddingLeft);
  637. }
  638. }
  639. else if (tagName === 'ION-HEADER') {
  640. scrollEvent.headerElement = ele;
  641. // ******** DOM READ ****************
  642. this._hdrHeight = ele.clientHeight;
  643. }
  644. else if (tagName === 'ION-FOOTER') {
  645. scrollEvent.footerElement = ele;
  646. // ******** DOM READ ****************
  647. this._ftrHeight = ele.clientHeight;
  648. this._footerEle = ele;
  649. }
  650. }
  651. ele = parentEle;
  652. var tabbarEle;
  653. while (ele && ele.tagName !== 'ION-MODAL' && !ele.classList.contains('tab-subpage')) {
  654. if (ele.tagName === 'ION-TABS') {
  655. tabbarEle = ele.firstElementChild;
  656. // ******** DOM READ ****************
  657. this._tabbarHeight = tabbarEle.clientHeight;
  658. if (this._tabsPlacement === null) {
  659. // this is the first tabbar found, remember it's position
  660. this._tabsPlacement = ele.getAttribute('tabsplacement');
  661. }
  662. }
  663. ele = ele.parentElement;
  664. }
  665. // Tabs top
  666. if (this._tabs && this._tabsPlacement === 'top') {
  667. this._tTop = this._hdrHeight;
  668. tabsTop = this._tabs._top;
  669. }
  670. // Toolbar height
  671. this._cTop = this._hdrHeight;
  672. this._cBottom = this._ftrHeight;
  673. // Tabs height
  674. if (this._tabsPlacement === 'top') {
  675. this._cTop += this._tabbarHeight;
  676. }
  677. else if (this._tabsPlacement === 'bottom') {
  678. this._cBottom += this._tabbarHeight;
  679. }
  680. // Refresher uses a border which should be hidden unless pulled
  681. if (this._hasRefresher) {
  682. this._cTop -= 1;
  683. }
  684. // Fixed content shouldn't include content padding
  685. this._fTop = this._cTop;
  686. this._fBottom = this._cBottom;
  687. // Handle fullscreen viewport (padding vs margin)
  688. if (this._fullscreen) {
  689. this._cTop += this._pTop;
  690. this._cBottom += this._pBottom;
  691. }
  692. // ******** DOM READ ****************
  693. var contentDimensions = this.getContentDimensions();
  694. scrollEvent.scrollHeight = contentDimensions.scrollHeight;
  695. scrollEvent.scrollWidth = contentDimensions.scrollWidth;
  696. scrollEvent.contentHeight = contentDimensions.contentHeight;
  697. scrollEvent.contentWidth = contentDimensions.contentWidth;
  698. scrollEvent.contentTop = contentDimensions.contentTop;
  699. scrollEvent.contentBottom = contentDimensions.contentBottom;
  700. this._dirty = (cachePaddingTop !== this._pTop ||
  701. cachePaddingBottom !== this._pBottom ||
  702. cachePaddingLeft !== this._pLeft ||
  703. cachePaddingRight !== this._pRight ||
  704. cacheHeaderHeight !== this._hdrHeight ||
  705. cacheFooterHeight !== this._ftrHeight ||
  706. cacheTabsPlacement !== this._tabsPlacement ||
  707. tabsTop !== this._tTop ||
  708. this._cTop !== this.contentTop ||
  709. this._cBottom !== this.contentBottom);
  710. this._scroll.init(this.getScrollElement(), this._cTop, this._cBottom);
  711. // initial imgs refresh
  712. this.imgsUpdate();
  713. };
  714. /**
  715. * @hidden
  716. * DOM WRITE
  717. */
  718. Content.prototype._writeDimensions = function () {
  719. if (!this._dirty) {
  720. (void 0) /* console.debug */;
  721. return;
  722. }
  723. var scrollEle = this.getScrollElement();
  724. if (!scrollEle) {
  725. (void 0) /* assert */;
  726. return;
  727. }
  728. var fixedEle = this.getFixedElement();
  729. if (!fixedEle) {
  730. (void 0) /* assert */;
  731. return;
  732. }
  733. // Tabs height
  734. if (this._tabsPlacement === 'bottom' && this._cBottom > 0 && this._footerEle) {
  735. var footerPos = this._cBottom - this._ftrHeight;
  736. (void 0) /* assert */;
  737. // ******** DOM WRITE ****************
  738. this._footerEle.style.bottom = cssFormat(footerPos);
  739. }
  740. // Handle fullscreen viewport (padding vs margin)
  741. var topProperty = 'marginTop';
  742. var bottomProperty = 'marginBottom';
  743. var fixedTop = this._fTop;
  744. var fixedBottom = this._fBottom;
  745. if (this._fullscreen) {
  746. (void 0) /* assert */;
  747. (void 0) /* assert */;
  748. // adjust the content with padding, allowing content to scroll under headers/footers
  749. // however, on iOS you cannot control the margins of the scrollbar (last tested iOS9.2)
  750. // only add inline padding styles if the computed padding value, which would
  751. // have come from the app's css, is different than the new padding value
  752. topProperty = 'paddingTop';
  753. bottomProperty = 'paddingBottom';
  754. }
  755. // Only update top margin if value changed
  756. if (this._cTop !== this.contentTop) {
  757. (void 0) /* assert */;
  758. (void 0) /* assert */;
  759. // ******** DOM WRITE ****************
  760. scrollEle.style[topProperty] = cssFormat(this._cTop);
  761. // ******** DOM WRITE ****************
  762. fixedEle.style.marginTop = cssFormat(fixedTop);
  763. this.contentTop = this._cTop;
  764. }
  765. // Only update bottom margin if value changed
  766. if (this._cBottom !== this.contentBottom) {
  767. (void 0) /* assert */;
  768. (void 0) /* assert */;
  769. // ******** DOM WRITE ****************
  770. scrollEle.style[bottomProperty] = cssFormat(this._cBottom);
  771. // ******** DOM WRITE ****************
  772. fixedEle.style.marginBottom = cssFormat(fixedBottom);
  773. this.contentBottom = this._cBottom;
  774. }
  775. if (this._tabsPlacement !== null && this._tabs) {
  776. // set the position of the tabbar
  777. if (this._tabsPlacement === 'top') {
  778. // ******** DOM WRITE ****************
  779. this._tabs.setTabbarPosition(this._tTop, -1);
  780. }
  781. else {
  782. (void 0) /* assert */;
  783. // ******** DOM WRITE ****************
  784. this._tabs.setTabbarPosition(-1, 0);
  785. }
  786. }
  787. // Scroll the page all the way down after setting dimensions
  788. if (this._scrollDownOnLoad) {
  789. this.scrollToBottom(0);
  790. this._scrollDownOnLoad = false;
  791. }
  792. };
  793. /**
  794. * @hidden
  795. */
  796. Content.prototype.imgsUpdate = function () {
  797. if (this._scroll.initialized && this._imgs.length && this.isImgsUpdatable()) {
  798. updateImgs(this._imgs, this.scrollTop, this.contentHeight, this.directionY, this._imgReqBfr, this._imgRndBfr);
  799. }
  800. };
  801. /**
  802. * @hidden
  803. */
  804. Content.prototype.isImgsUpdatable = function () {
  805. // an image is only "updatable" if the content isn't scrolling too fast
  806. // if scroll speed is above the maximum velocity, then let current
  807. // requests finish, but do not start new requets or render anything
  808. // if scroll speed is below the maximum velocity, then it's ok
  809. // to start new requests and render images
  810. return Math.abs(this._scroll.ev.velocityY) < this._imgVelMax;
  811. };
  812. Content.decorators = [
  813. { type: Component, args: [{
  814. selector: 'ion-content',
  815. template: '<div class="fixed-content" #fixedContent>' +
  816. '<ng-content select="[ion-fixed],ion-fab"></ng-content>' +
  817. '</div>' +
  818. '<div class="scroll-content" #scrollContent>' +
  819. '<ng-content></ng-content>' +
  820. '</div>' +
  821. '<ng-content select="ion-refresher"></ng-content>',
  822. host: {
  823. '[class.statusbar-padding]': 'statusbarPadding',
  824. '[class.has-refresher]': '_hasRefresher'
  825. },
  826. changeDetection: ChangeDetectionStrategy.OnPush,
  827. encapsulation: ViewEncapsulation.None
  828. },] },
  829. ];
  830. /** @nocollapse */
  831. Content.ctorParameters = function () { return [
  832. { type: Config, },
  833. { type: Platform, },
  834. { type: DomController, },
  835. { type: ElementRef, },
  836. { type: Renderer, },
  837. { type: App, },
  838. { type: Keyboard, },
  839. { type: NgZone, },
  840. { type: ViewController, decorators: [{ type: Optional },] },
  841. { type: NavController, decorators: [{ type: Optional },] },
  842. ]; };
  843. Content.propDecorators = {
  844. '_fixedContent': [{ type: ViewChild, args: ['fixedContent', { read: ElementRef },] },],
  845. '_scrollContent': [{ type: ViewChild, args: ['scrollContent', { read: ElementRef },] },],
  846. 'ionScrollStart': [{ type: Output },],
  847. 'ionScroll': [{ type: Output },],
  848. 'ionScrollEnd': [{ type: Output },],
  849. 'fullscreen': [{ type: Input },],
  850. 'scrollDownOnLoad': [{ type: Input },],
  851. };
  852. return Content;
  853. }(Ion));
  854. export { Content };
  855. export function updateImgs(imgs, viewableTop, contentHeight, scrollDirectionY, requestableBuffer, renderableBuffer) {
  856. // ok, so it's time to see which images, if any, should be requested and rendered
  857. // ultimately, if we're scrolling fast then don't bother requesting or rendering
  858. // when scrolling is done, then it needs to do a check to see which images are
  859. // important to request and render, and which image requests should be aborted.
  860. // Additionally, images which are not near the viewable area should not be
  861. // rendered at all in order to save browser resources.
  862. var viewableBottom = (viewableTop + contentHeight);
  863. var priority1 = [];
  864. var priority2 = [];
  865. var img;
  866. // all images should be paused
  867. for (var i = 0, ilen = imgs.length; i < ilen; i++) {
  868. img = imgs[i];
  869. if (scrollDirectionY === 'up') {
  870. // scrolling up
  871. if (img.top < viewableBottom && img.bottom > viewableTop - renderableBuffer) {
  872. // scrolling up, img is within viewable area
  873. // or about to be viewable area
  874. img.canRequest = img.canRender = true;
  875. priority1.push(img);
  876. continue;
  877. }
  878. if (img.bottom <= viewableTop && img.bottom > viewableTop - requestableBuffer) {
  879. // scrolling up, img is within requestable area
  880. img.canRequest = true;
  881. img.canRender = false;
  882. priority2.push(img);
  883. continue;
  884. }
  885. if (img.top >= viewableBottom && img.top < viewableBottom + renderableBuffer) {
  886. // scrolling up, img below viewable area
  887. // but it's still within renderable area
  888. // don't allow a reset
  889. img.canRequest = img.canRender = false;
  890. continue;
  891. }
  892. }
  893. else {
  894. // scrolling down
  895. if (img.bottom > viewableTop && img.top < viewableBottom + renderableBuffer) {
  896. // scrolling down, img is within viewable area
  897. // or about to be viewable area
  898. img.canRequest = img.canRender = true;
  899. priority1.push(img);
  900. continue;
  901. }
  902. if (img.top >= viewableBottom && img.top < viewableBottom + requestableBuffer) {
  903. // scrolling down, img is within requestable area
  904. img.canRequest = true;
  905. img.canRender = false;
  906. priority2.push(img);
  907. continue;
  908. }
  909. if (img.bottom <= viewableTop && img.bottom > viewableTop - renderableBuffer) {
  910. // scrolling down, img above viewable area
  911. // but it's still within renderable area
  912. // don't allow a reset
  913. img.canRequest = img.canRender = false;
  914. continue;
  915. }
  916. }
  917. img.canRequest = img.canRender = false;
  918. img.reset();
  919. }
  920. // update all imgs which are viewable
  921. priority1.sort(sortTopToBottom).forEach(function (i) { return i.update(); });
  922. if (scrollDirectionY === 'up') {
  923. // scrolling up
  924. priority2.sort(sortTopToBottom).reverse().forEach(function (i) { return i.update(); });
  925. }
  926. else {
  927. // scrolling down
  928. priority2.sort(sortTopToBottom).forEach(function (i) { return i.update(); });
  929. }
  930. }
  931. function sortTopToBottom(a, b) {
  932. if (a.top < b.top) {
  933. return -1;
  934. }
  935. if (a.top > b.top) {
  936. return 1;
  937. }
  938. return 0;
  939. }
  940. function parsePxUnit(val) {
  941. return (val.indexOf('px') > 0) ? parseInt(val, 10) : 0;
  942. }
  943. function cssFormat(val) {
  944. return (val > 0 ? val + 'px' : '');
  945. }
  946. //# sourceMappingURL=content.js.map