watch.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import {ElementRef} from '@angular/core';
  2. import extend from 'lodash-es/extend';
  3. import {IncrementalStackManager} from '@ex-helpers/stack';
  4. import {bounds} from './bounds';
  5. declare module '@angular/core' {
  6. class ElementRef<T = any> {
  7. private _watchSizeCollection: any;
  8. nativeElement: T;
  9. constructor(nativeElement: T);
  10. watchSize: (callback: (height: number, width: number) => void,
  11. options?: { attributes: boolean, childList: boolean, characterData: boolean },
  12. params?: { legacy: boolean, timeout?: number }) => () => void;
  13. watchChanges: (callback: MutationCallback, options: MutationObserverInit) => () => void;
  14. triggerSizeCheck: () => void;
  15. }
  16. }
  17. interface SizeCollectionItem {
  18. triggerCheck: () => void;
  19. startCountdown: () => void;
  20. callback: (height: number, width: number) => void;
  21. observer?: MutationObserver;
  22. id?: number;
  23. legacy?: boolean;
  24. }
  25. const DEFAULT_OPTIONS = {
  26. attributes: true,
  27. childList: true,
  28. characterData: true
  29. };
  30. ElementRef.prototype.watchSize = function
  31. (callback: (height: number, width: number) => void,
  32. options?: { attributes?: boolean, childList?: boolean, characterData?: boolean },
  33. params: { timeout?: number, legacy: boolean } = {legacy: false}) {
  34. if (!this._watchSizeCollection) {
  35. Object.defineProperty(this, '_watchSizeCollection', {
  36. enumerable: false,
  37. configurable: true,
  38. writable: false,
  39. value: new IncrementalStackManager<SizeCollectionItem>('id')
  40. });
  41. }
  42. options = extend(DEFAULT_OPTIONS, options);
  43. let timeout: any;
  44. let lastHeight: number;
  45. let lastWidth: number;
  46. const triggerCheck = () => {
  47. const sizes = bounds(this.nativeElement).size;
  48. if (lastWidth === sizes.width && lastHeight === sizes.height) {
  49. return;
  50. }
  51. lastHeight = sizes.height;
  52. lastWidth = sizes.width;
  53. callback(sizes.height, sizes.width);
  54. };
  55. const startCountdown = () => {
  56. clearTimeout(timeout);
  57. timeout = setTimeout(() => {
  58. triggerCheck();
  59. }, params.timeout || 100);
  60. };
  61. const item = this._watchSizeCollection.add({
  62. callback,
  63. startCountdown,
  64. triggerCheck
  65. });
  66. if (MutationObserver && params.legacy === false) {
  67. const observer = new MutationObserver(mutations => {
  68. startCountdown();
  69. });
  70. item.observer = observer;
  71. item.legacy = false;
  72. startCountdown();
  73. observer.observe(this.nativeElement, options);
  74. return () => observer.disconnect();
  75. } else {
  76. item.legacy = true;
  77. const checkInterval = setInterval(() => {
  78. triggerCheck();
  79. }, 200);
  80. startCountdown();
  81. return () => clearInterval(checkInterval);
  82. }
  83. };
  84. ElementRef.prototype.triggerSizeCheck = function () {
  85. if (this._watchSizeCollection) {
  86. this._watchSizeCollection.execute('triggerCheck');
  87. }
  88. };
  89. ElementRef.prototype.watchChanges = function (callback: MutationCallback, options: MutationObserverInit) {
  90. if (MutationObserver) {
  91. const observer = new MutationObserver(callback);
  92. observer.observe(this.nativeElement, options);
  93. return () => observer.disconnect();
  94. }
  95. return () => {
  96. };
  97. };