@lenne.tech/ng-base 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2606,32 +2606,80 @@
2606
2606
  this.router = router;
2607
2607
  this.moduleConfig = moduleConfig;
2608
2608
  /**
2609
- * Scroll offset
2609
+ * Is a scroll listener set
2610
+ *
2611
+ * @protected
2610
2612
  */
2611
- this.scrollOffset = 100;
2613
+ this.scrollListener = false;
2612
2614
  /**
2613
- * Detection offset
2614
- * Should be >= scrollOffset
2615
+ * Current scroll timer;
2616
+ *
2617
+ * @protected
2615
2618
  */
2616
- this.detectionOffset = 200;
2617
- var config = Object.assign({ scrollDetectionOffset: 200, scrollOffset: 100 }, moduleConfig);
2619
+ this.scrollTimer = -1;
2620
+ var config = Object.assign({ scrollDetectionOffset: 200, scrollOffset: 100, scrollSamplingRate: 100 }, moduleConfig);
2618
2621
  this.detectionOffset = config.scrollDetectionOffset;
2619
2622
  this.scrollOffset = config.scrollOffset;
2623
+ this.scrollSamplingRate = config.scrollSamplingRate;
2620
2624
  }
2621
2625
  /**
2622
2626
  * Scroll to structureElement with specific ID
2623
2627
  */
2624
2628
  ScrollService.prototype.scrollTo = function (id, options) {
2625
2629
  if (options === void 0) { options = {}; }
2626
- options = Object.assign({ stopPropagation: true }, options);
2627
- if (this.router.url !== '/' && !this.router.url.startsWith('/#')) {
2628
- this.router.navigate(['/'], { fragment: id });
2629
- return options.stopPropagation ? false : true;
2630
- }
2631
- var el = document.getElementById(id);
2632
- var cords = el.getBoundingClientRect();
2633
- window.scrollBy({ top: cords.top - this.scrollOffset, behavior: 'smooth' });
2634
- return options.stopPropagation ? false : true;
2630
+ return __awaiter(this, void 0, void 0, function () {
2631
+ var config, el, body, undoOverflowChanges, scrollBodyStyles, cords;
2632
+ return __generator(this, function (_a) {
2633
+ switch (_a.label) {
2634
+ case 0:
2635
+ config = Object.assign({ checkUrl: true, loadImagesBefore: true, resetStyles: false, setOverflow: true, stopPropagation: true }, options);
2636
+ if (!(config.checkUrl && this.router.url !== '/' && !this.router.url.startsWith('/#'))) return [3 /*break*/, 2];
2637
+ return [4 /*yield*/, this.router.navigate(['/'], { fragment: id })];
2638
+ case 1:
2639
+ _a.sent();
2640
+ return [2 /*return*/, !config.stopPropagation];
2641
+ case 2:
2642
+ el = document.getElementById(id);
2643
+ if (!el) {
2644
+ console.error('Missing scroll element with ID:', id);
2645
+ return [2 /*return*/, !config.stopPropagation];
2646
+ }
2647
+ body = document.querySelector('body');
2648
+ undoOverflowChanges = false;
2649
+ scrollBodyStyles = JSON.parse(JSON.stringify(window.getComputedStyle(body)));
2650
+ if (config.setOverflow && (scrollBodyStyles.overflowX !== 'visible' || scrollBodyStyles.overflowY !== 'visible')) {
2651
+ // Set body overflow to visible
2652
+ console.warn('Style of body element for overflowX and overflowY will be set to "visible" for scrolling!');
2653
+ body.style.overflowX = 'visible';
2654
+ body.style.overflowY = 'visible';
2655
+ undoOverflowChanges = true;
2656
+ }
2657
+ if (!config.loadImagesBefore) return [3 /*break*/, 4];
2658
+ return [4 /*yield*/, this.preLoadImages()];
2659
+ case 3:
2660
+ _a.sent();
2661
+ _a.label = 4;
2662
+ case 4:
2663
+ cords = el.getBoundingClientRect();
2664
+ // Scroll to element
2665
+ window.scrollBy({ top: cords.top - this.scrollOffset, behavior: 'smooth' });
2666
+ return [4 /*yield*/, this.scrollDone({
2667
+ doneFunction: function () {
2668
+ // Undo changes
2669
+ if (undoOverflowChanges && config.resetStyles) {
2670
+ body.style.overflowX = scrollBodyStyles.overflowX;
2671
+ body.style.overflowY = scrollBodyStyles.overflowY;
2672
+ console.warn('Original style of body element for overflowX and overflowY is set.');
2673
+ }
2674
+ },
2675
+ })];
2676
+ case 5:
2677
+ _a.sent();
2678
+ // Return stop propagation configuration
2679
+ return [2 /*return*/, !config.stopPropagation];
2680
+ }
2681
+ });
2682
+ });
2635
2683
  };
2636
2684
  /**
2637
2685
  * Get last active structureElement
@@ -2662,6 +2710,194 @@
2662
2710
  var lastActiveElement = this.getLastActiveElement(list);
2663
2711
  return id === lastActiveElement || (lastActiveElement === null && isFirst);
2664
2712
  };
2713
+ /**
2714
+ * Scroll done promise
2715
+ */
2716
+ ScrollService.prototype.scrollDone = function (options) {
2717
+ var _this = this;
2718
+ if (options === void 0) { options = {}; }
2719
+ // Init configuration
2720
+ var config = Object.assign({ doneFunction: undefined, timeout: undefined }, options);
2721
+ // Return promise for scroll done
2722
+ return new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
2723
+ var rejected, timeoutId, result;
2724
+ return __generator(this, function (_a) {
2725
+ switch (_a.label) {
2726
+ case 0:
2727
+ rejected = false;
2728
+ // Set timeout handling if necessary
2729
+ if (config.timeout) {
2730
+ timeoutId = window.setTimeout(function () {
2731
+ rejected = true;
2732
+ reject(new Error('Timeout for scrollDone after:' + config.timeout));
2733
+ }, config.timeout);
2734
+ }
2735
+ // Wait for scroll done
2736
+ return [4 /*yield*/, this.scrollDoneDetection()];
2737
+ case 1:
2738
+ // Wait for scroll done
2739
+ _a.sent();
2740
+ if (!!rejected) return [3 /*break*/, 4];
2741
+ // Stop timeout if set
2742
+ if (timeoutId) {
2743
+ window.clearTimeout(timeoutId);
2744
+ }
2745
+ result = void 0;
2746
+ if (!config.doneFunction) return [3 /*break*/, 3];
2747
+ return [4 /*yield*/, config.doneFunction()];
2748
+ case 2:
2749
+ result = _a.sent();
2750
+ _a.label = 3;
2751
+ case 3:
2752
+ // Scroll done
2753
+ resolve(result);
2754
+ _a.label = 4;
2755
+ case 4: return [2 /*return*/];
2756
+ }
2757
+ });
2758
+ }); });
2759
+ };
2760
+ /**
2761
+ * Scroll done detecton
2762
+ *
2763
+ * @protected
2764
+ */
2765
+ ScrollService.prototype.scrollDoneDetection = function () {
2766
+ var _this = this;
2767
+ // Return current scroll promise (Singelton)
2768
+ if (this.scrollPromise) {
2769
+ return this.scrollPromise;
2770
+ }
2771
+ // Create current scroll promise
2772
+ this.scrollPromise = new Promise(function (resolve) {
2773
+ _this.scrollPromiseResolve = resolve;
2774
+ if (_this.scrollTimer !== -1) {
2775
+ window.clearTimeout(_this.scrollTimer);
2776
+ }
2777
+ _this.scrollTimer = window.setTimeout(function () {
2778
+ window.removeEventListener('scroll', _this.scrollDoneDetection.bind(_this));
2779
+ _this.scrollPromise = undefined;
2780
+ resolve();
2781
+ }, _this.scrollSamplingRate);
2782
+ });
2783
+ // Lisitening to scroll event;
2784
+ window.addEventListener('scroll', this.scrollDoneDetection.bind(this));
2785
+ // Return promise
2786
+ return this.scrollPromise;
2787
+ };
2788
+ /**
2789
+ * Preaload images (for lazy handling)
2790
+ *
2791
+ * @param options
2792
+ * @protected
2793
+ */
2794
+ ScrollService.prototype.preLoadImages = function (options) {
2795
+ var _this = this;
2796
+ // Init configuration
2797
+ var config = Object.assign({ doneFunnction: undefined, timeout: undefined }, options);
2798
+ return new Promise(function (resolve) {
2799
+ var e_1, _a;
2800
+ // Init variables
2801
+ var resolved = false;
2802
+ var timeoutId;
2803
+ // Init loading
2804
+ var images = Array.from(document.getElementsByTagName('img'));
2805
+ var promises = [];
2806
+ var _loop_1 = function (image) {
2807
+ var src = image.getAttribute('src');
2808
+ // Check if changes are necessary and possible
2809
+ if ((image.complete && image.naturalHeight !== 0) || image.getAttribute('loading') !== 'lazy' || !src) {
2810
+ return "continue";
2811
+ }
2812
+ var newImage = document.createElement('img');
2813
+ Array.from(image.attributes).forEach(function (attr) {
2814
+ if (attr.name !== 'loading' && attr.name !== 'src') {
2815
+ newImage.setAttribute(attr.name, attr.value);
2816
+ }
2817
+ });
2818
+ image.replaceWith(newImage);
2819
+ promises.push(_this.loadImage(newImage, src));
2820
+ };
2821
+ try {
2822
+ // Prepare images
2823
+ for (var images_1 = __values(images), images_1_1 = images_1.next(); !images_1_1.done; images_1_1 = images_1.next()) {
2824
+ var image = images_1_1.value;
2825
+ _loop_1(image);
2826
+ }
2827
+ }
2828
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
2829
+ finally {
2830
+ try {
2831
+ if (images_1_1 && !images_1_1.done && (_a = images_1.return)) _a.call(images_1);
2832
+ }
2833
+ finally { if (e_1) throw e_1.error; }
2834
+ }
2835
+ if (config.timeout) {
2836
+ timeoutId = setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
2837
+ return __generator(this, function (_a) {
2838
+ switch (_a.label) {
2839
+ case 0:
2840
+ resolved = true;
2841
+ if (!config.doneFunnction) return [3 /*break*/, 2];
2842
+ return [4 /*yield*/, config.doneFunction()];
2843
+ case 1:
2844
+ _a.sent();
2845
+ _a.label = 2;
2846
+ case 2:
2847
+ resolve(undefined);
2848
+ return [2 /*return*/];
2849
+ }
2850
+ });
2851
+ }); });
2852
+ }
2853
+ // Wait until all images loaded
2854
+ Promise.all(promises)
2855
+ .catch(function (e) { return console.error('Error during image loading', e); })
2856
+ .finally(function () { return __awaiter(_this, void 0, void 0, function () {
2857
+ var result;
2858
+ return __generator(this, function (_a) {
2859
+ switch (_a.label) {
2860
+ case 0:
2861
+ // Check if already resolved
2862
+ if (resolved) {
2863
+ return [2 /*return*/];
2864
+ }
2865
+ // Stop timeout
2866
+ if (timeoutId) {
2867
+ clearTimeout(timeoutId);
2868
+ }
2869
+ if (!config.doneFunnction) return [3 /*break*/, 2];
2870
+ return [4 /*yield*/, config.doneFunction()];
2871
+ case 1:
2872
+ result = _a.sent();
2873
+ _a.label = 2;
2874
+ case 2:
2875
+ resolve(result);
2876
+ return [2 /*return*/];
2877
+ }
2878
+ });
2879
+ }); });
2880
+ });
2881
+ };
2882
+ /**
2883
+ * Load image for image element
2884
+ *
2885
+ * @param imageElement
2886
+ * @param src
2887
+ * @protected
2888
+ */
2889
+ ScrollService.prototype.loadImage = function (imageElement, src) {
2890
+ return __awaiter(this, void 0, void 0, function () {
2891
+ return __generator(this, function (_a) {
2892
+ src = src || imageElement.src;
2893
+ return [2 /*return*/, new Promise(function (resolve, reject) {
2894
+ imageElement.onload = function () { return resolve(imageElement); };
2895
+ imageElement.onerror = reject;
2896
+ imageElement.src = src;
2897
+ })];
2898
+ });
2899
+ });
2900
+ };
2665
2901
  return ScrollService;
2666
2902
  }());
2667
2903
  ScrollService.ɵprov = i0__namespace.ɵɵdefineInjectable({ factory: function ScrollService_Factory() { return new ScrollService(i0__namespace.ɵɵinject(i1__namespace$1.Router), i0__namespace.ɵɵinject(BASE_MODULE_CONFIG)); }, token: ScrollService, providedIn: "root" });