@lenne.tech/ng-base 0.3.0 → 0.3.4

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.
Files changed (36) hide show
  1. package/bundles/lenne.tech-ng-base-src-lib-base.umd.js +600 -414
  2. package/bundles/lenne.tech-ng-base-src-lib-base.umd.js.map +1 -1
  3. package/bundles/lenne.tech-ng-base.umd.js +600 -414
  4. package/bundles/lenne.tech-ng-base.umd.js.map +1 -1
  5. package/esm2015/lib/base/classes/helper.class.js +19 -1
  6. package/esm2015/lib/base/directives/match-height.directive.js +58 -25
  7. package/esm2015/lib/base/factories/apollo-options.factory.js +3 -2
  8. package/esm2015/lib/base/public-api.js +2 -1
  9. package/esm2015/lib/base/services/image.service.js +117 -0
  10. package/esm2015/lib/base/services/scroll.service.js +9 -84
  11. package/esm2015/lib/base/services/seo.service.js +70 -14
  12. package/esm2015/src/lib/base/classes/helper.class.js +19 -1
  13. package/esm2015/src/lib/base/directives/match-height.directive.js +58 -25
  14. package/esm2015/src/lib/base/factories/apollo-options.factory.js +3 -2
  15. package/esm2015/src/lib/base/public-api.js +2 -1
  16. package/esm2015/src/lib/base/services/image.service.js +117 -0
  17. package/esm2015/src/lib/base/services/scroll.service.js +9 -84
  18. package/esm2015/src/lib/base/services/seo.service.js +70 -14
  19. package/fesm2015/lenne.tech-ng-base-src-lib-base.js +513 -371
  20. package/fesm2015/lenne.tech-ng-base-src-lib-base.js.map +1 -1
  21. package/fesm2015/lenne.tech-ng-base.js +513 -371
  22. package/fesm2015/lenne.tech-ng-base.js.map +1 -1
  23. package/lib/base/classes/helper.class.d.ts +7 -0
  24. package/lib/base/directives/match-height.directive.d.ts +7 -2
  25. package/lib/base/public-api.d.ts +1 -0
  26. package/lib/base/services/image.service.d.ts +25 -0
  27. package/lib/base/services/scroll.service.d.ts +5 -21
  28. package/lib/base/services/seo.service.d.ts +36 -3
  29. package/package.json +3 -3
  30. package/src/lib/base/classes/helper.class.d.ts +7 -0
  31. package/src/lib/base/directives/match-height.directive.d.ts +7 -2
  32. package/src/lib/base/lenne.tech-ng-base-src-lib-base.metadata.json +1 -1
  33. package/src/lib/base/public-api.d.ts +1 -0
  34. package/src/lib/base/services/image.service.d.ts +25 -0
  35. package/src/lib/base/services/scroll.service.d.ts +5 -21
  36. package/src/lib/base/services/seo.service.d.ts +36 -3
@@ -2,19 +2,20 @@ import * as i1 from 'apollo-angular';
2
2
  import { APOLLO_OPTIONS, gql, Apollo } from 'apollo-angular';
3
3
  import { HttpLink } from 'apollo-angular/http';
4
4
  import * as i0 from '@angular/core';
5
- import { InjectionToken, Injectable, Inject, Directive, ElementRef, Input, Output, HostBinding, HostListener, Pipe, NgModule } from '@angular/core';
5
+ import { InjectionToken, Injectable, Inject, Directive, ElementRef, Input, Output, HostBinding, PLATFORM_ID, HostListener, Pipe, NgModule } from '@angular/core';
6
6
  import { BehaviorSubject, Observable, of, throwError } from 'rxjs';
7
7
  import { ApolloLink, split, concat } from '@apollo/client/core';
8
8
  import { InMemoryCache } from '@apollo/client/cache';
9
9
  import { WebSocketLink } from '@apollo/client/link/ws';
10
10
  import { getMainDefinition } from '@apollo/client/utilities';
11
+ import { __awaiter } from 'tslib';
12
+ import { isPlatformBrowser } from '@angular/common';
11
13
  import * as i1$2 from '@angular/platform-browser';
12
14
  import { DomSanitizer, Title, Meta } from '@angular/platform-browser';
13
15
  import * as i1$1 from '@angular/router';
14
16
  import { Router } from '@angular/router';
15
17
  import { buildClientSchema, getIntrospectionQuery } from 'graphql';
16
18
  import { map } from 'rxjs/operators';
17
- import { __awaiter } from 'tslib';
18
19
 
19
20
  const BASE_MODULE_CONFIG = new InjectionToken('BASE_MODULE_CONFIG');
20
21
 
@@ -212,8 +213,9 @@ AuthService.ctorParameters = () => [
212
213
  */
213
214
  function apolloOptionsFactory(baseModuleConfig, httpLink, authService) {
214
215
  const links = [];
216
+ const defaultUrl = 'api.' + window.location.href + '/graphql';
215
217
  const http = httpLink.create({
216
- uri: baseModuleConfig.apiUrl,
218
+ uri: baseModuleConfig.apiUrl ? baseModuleConfig.apiUrl : 'https://' + defaultUrl,
217
219
  });
218
220
  const authMiddleware = new ApolloLink((operation, forward) => {
219
221
  const headers = {};
@@ -418,238 +420,6 @@ LazyLoadDirective.propDecorators = {
418
420
  src: [{ type: Input }]
419
421
  };
420
422
 
421
- /**
422
- * Set same height (maximum) to different elements
423
- */
424
- class MatchHeightDirective {
425
- constructor(el) {
426
- this.el = el;
427
- }
428
- onResize() {
429
- this.matchHeight(this.el.nativeElement, this.ltMatchHeight);
430
- }
431
- ngAfterViewChecked() {
432
- this.matchHeight(this.el.nativeElement, this.ltMatchHeight);
433
- }
434
- matchHeight(parent, target) {
435
- if (!parent) {
436
- return;
437
- }
438
- let classNames;
439
- if (!Array.isArray(target)) {
440
- classNames = [target];
441
- }
442
- else {
443
- classNames = target;
444
- }
445
- classNames.forEach((className) => {
446
- // find all child structureElements with the selected class name
447
- const children = parent.getElementsByClassName(className);
448
- if (!children) {
449
- return;
450
- }
451
- // reset all children height
452
- Array.from(children).forEach((x) => {
453
- x.style.height = 'initial';
454
- });
455
- // get all the child structureElements heights
456
- const itemHeights = Array.from(children).map((x) => x.getBoundingClientRect().height);
457
- // find out the tallest one
458
- const maxHeight = itemHeights.reduce((prev, curr) => (curr > prev ? curr : prev), 0);
459
- // update the child structureElements height to the tallest one
460
- Array.from(children).forEach((x) => (x.style.height = `${maxHeight}px`));
461
- });
462
- }
463
- }
464
- MatchHeightDirective.decorators = [
465
- { type: Directive, args: [{
466
- selector: '[ltMatchHeight]',
467
- },] }
468
- ];
469
- MatchHeightDirective.ctorParameters = () => [
470
- { type: ElementRef }
471
- ];
472
- MatchHeightDirective.propDecorators = {
473
- ltMatchHeight: [{ type: Input }],
474
- onResize: [{ type: HostListener, args: ['window:resize',] }]
475
- };
476
-
477
- /**
478
- * Reszise detection
479
- * (inpsired by: https://stackblitz.com/edit/angular-resizable)
480
- */
481
- class ResizableDirective {
482
- constructor(el) {
483
- this.el = el;
484
- this.resizableGrabWidth = 8;
485
- this.resizableMinWidth = 10;
486
- this.dragging = false;
487
- }
488
- ngOnInit() {
489
- this.addListenerToDocument();
490
- this.addListenerToElement();
491
- }
492
- mouseMoveG(evt) {
493
- if (!this.dragging) {
494
- return;
495
- }
496
- this.newWidth(evt.clientX - this.el.nativeElement.offsetLeft);
497
- evt.stopPropagation();
498
- }
499
- newWidth(wid) {
500
- const result = Math.max(this.resizableMinWidth, wid);
501
- this.el.nativeElement.style.width = result + 'px';
502
- }
503
- mouseDown(evt) {
504
- if (this.inDragRegion(evt)) {
505
- this.dragging = true;
506
- this.preventGlobalMouseEvents();
507
- evt.stopPropagation();
508
- }
509
- }
510
- restoreGlobalMouseEvents() {
511
- document.body.style['pointer-events'] = 'auto';
512
- }
513
- mouseUpG(evt) {
514
- if (!this.dragging) {
515
- return;
516
- }
517
- this.restoreGlobalMouseEvents();
518
- this.dragging = false;
519
- evt.stopPropagation();
520
- }
521
- mouseMove(evt) {
522
- if (this.inDragRegion(evt) || this.dragging) {
523
- this.el.nativeElement.style.cursor = 'col-resize';
524
- }
525
- else {
526
- this.el.nativeElement.style.cursor = 'default';
527
- }
528
- }
529
- preventGlobalMouseEvents() {
530
- document.body.style['pointer-events'] = 'none';
531
- }
532
- inDragRegion(evt) {
533
- return this.el.nativeElement.clientWidth - evt.clientX + this.el.nativeElement.offsetLeft < this.resizableGrabWidth;
534
- }
535
- addListenerToDocument() {
536
- document.addEventListener('mousemove', (e) => {
537
- this.mouseMoveG(e);
538
- }, true);
539
- document.addEventListener('mouseup', (e) => {
540
- this.mouseUpG(e);
541
- }, true);
542
- }
543
- addListenerToElement() {
544
- this.el.nativeElement.addEventListener('mousedown', (e) => {
545
- this.mouseDown(e);
546
- }, true);
547
- this.el.nativeElement.addEventListener('mousemove', (e) => {
548
- this.mouseMove(e);
549
- }, true);
550
- }
551
- }
552
- ResizableDirective.decorators = [
553
- { type: Directive, args: [{
554
- selector: '[ltResizable]',
555
- },] }
556
- ];
557
- ResizableDirective.ctorParameters = () => [
558
- { type: ElementRef }
559
- ];
560
- ResizableDirective.propDecorators = {
561
- resizableGrabWidth: [{ type: Input }],
562
- resizableMinWidth: [{ type: Input }]
563
- };
564
-
565
- /**
566
- * Truncate string with ellipses
567
- */
568
- class EllipsesPipe {
569
- transform(value, limit) {
570
- if (!value) {
571
- return null;
572
- }
573
- return value.length > limit ? value.substring(0, limit) + '...' : value;
574
- }
575
- }
576
- EllipsesPipe.decorators = [
577
- { type: Pipe, args: [{
578
- name: 'ltEllipses',
579
- },] }
580
- ];
581
-
582
- /**
583
- * Declarate html as safe
584
- */
585
- class SafeHtmlPipe {
586
- constructor(sanitized) {
587
- this.sanitized = sanitized;
588
- }
589
- transform(value) {
590
- return this.sanitized.bypassSecurityTrustHtml(value);
591
- }
592
- }
593
- SafeHtmlPipe.decorators = [
594
- { type: Pipe, args: [{ name: 'ltSafeHtml' },] }
595
- ];
596
- SafeHtmlPipe.ctorParameters = () => [
597
- { type: DomSanitizer }
598
- ];
599
-
600
- // Imported and exported elements
601
- const elements = [
602
- // Directives
603
- ContextMenuDirective,
604
- LazyLoadDirective,
605
- MatchHeightDirective,
606
- ResizableDirective,
607
- // Pipes
608
- EllipsesPipe,
609
- SafeHtmlPipe,
610
- ];
611
- /**
612
- * Base module
613
- */
614
- class BaseModule {
615
- /**
616
- * Set configuration of base module in root module of the app
617
- */
618
- static forRoot(baseModuleConfig = {}) {
619
- // Default config
620
- const config = Object.assign({ apiUrl: 'localhost:3000', authGuardRedirectUrl: '/auth', logging: false, version: null, prefix: null, scrollDetectionOffset: 200, scrollOffset: 100, storageType: 'local' }, baseModuleConfig);
621
- // Prepare providers
622
- const providers = [
623
- {
624
- provide: BASE_MODULE_CONFIG,
625
- useValue: baseModuleConfig,
626
- },
627
- ];
628
- // Add apollo features if API URL is set
629
- if (baseModuleConfig.apiUrl) {
630
- providers.push({
631
- provide: APOLLO_OPTIONS,
632
- useFactory: apolloOptionsFactory,
633
- deps: [BASE_MODULE_CONFIG, HttpLink, AuthService],
634
- });
635
- }
636
- else if (config.logging) {
637
- console.log('apiUrl is missing, ApolloLink is not initialized');
638
- }
639
- // Return root module
640
- return {
641
- ngModule: BaseModule,
642
- providers,
643
- };
644
- }
645
- }
646
- BaseModule.decorators = [
647
- { type: NgModule, args: [{
648
- declarations: elements,
649
- exports: elements,
650
- },] }
651
- ];
652
-
653
423
  /**
654
424
  * Helper class
655
425
  */
@@ -872,55 +642,448 @@ class Helper {
872
642
  if (typeof a !== typeof b) {
873
643
  return false;
874
644
  }
875
- // Process array
876
- if (Array.isArray(a)) {
877
- for (const [key, value] of Object.entries(a)) {
878
- if (Helper.isSubset(value, b[key])) {
879
- return false;
880
- }
881
- }
882
- return true;
645
+ // Process array
646
+ if (Array.isArray(a)) {
647
+ for (const [key, value] of Object.entries(a)) {
648
+ if (Helper.isSubset(value, b[key])) {
649
+ return false;
650
+ }
651
+ }
652
+ return true;
653
+ }
654
+ // Process object
655
+ if (typeof a === 'object') {
656
+ const plain = JSON.parse(JSON.stringify(a));
657
+ for (const [key, value] of Object.entries(plain)) {
658
+ if (Helper.isSubset(value, b[key])) {
659
+ return false;
660
+ }
661
+ }
662
+ return true;
663
+ }
664
+ // Else
665
+ return true;
666
+ }
667
+ /**
668
+ * Whether parameters are equal (have equal properties)
669
+ * Hint: functions will be ignored
670
+ */
671
+ static isEqual(a, b) {
672
+ return Helper.isSubset(a, b) && Helper.isSubset(b, a);
673
+ }
674
+ /**
675
+ * First level difference of two objects
676
+ * Hint: functions will be ignored and when an array or an object is different the hole array or object will used as property value
677
+ *
678
+ * @returns Record<string, any> Object with properties from first object
679
+ */
680
+ static getDiff(a, b, clone = true) {
681
+ const result = {};
682
+ let firstObject = a;
683
+ if (clone) {
684
+ firstObject = JSON.parse(JSON.stringify(a));
685
+ }
686
+ for (const [key, value] of Object.entries(firstObject)) {
687
+ if (!Helper.isSubset(value, b[key])) {
688
+ result[key] = value;
689
+ }
690
+ }
691
+ return result;
692
+ }
693
+ /**
694
+ * Check if propertie is type of HTMLCollection or NodeList
695
+ * See https://stackoverflow.com/a/7238344
696
+ *
697
+ * @param nodes
698
+ */
699
+ static isNodeList(nodes) {
700
+ try {
701
+ const stringRepr = Object.prototype.toString.call(nodes);
702
+ return (typeof nodes === 'object' &&
703
+ /^\[object (HTMLCollection|NodeList|Object)\]$/.test(stringRepr) &&
704
+ typeof nodes.length === 'number' &&
705
+ (nodes.length === 0 || (typeof nodes[0] === 'object' && nodes[0].nodeType > 0)));
706
+ }
707
+ catch (e) {
708
+ return false;
709
+ }
710
+ }
711
+ }
712
+
713
+ /**
714
+ * Image service
715
+ */
716
+ class ImageService {
717
+ /**
718
+ * Preaload images (for lazy handling)
719
+ *
720
+ * @param options
721
+ * @protected
722
+ */
723
+ preLoadImages(options) {
724
+ // Init configuration
725
+ const config = Object.assign({ doneFunnction: undefined, elements: document, regExp: undefined, timeout: undefined }, options);
726
+ return new Promise((resolve) => {
727
+ var _a;
728
+ // Init variables
729
+ let resolved = false;
730
+ let timeoutId;
731
+ // Convert element(s) into array
732
+ if (!Array.isArray(config.elements)) {
733
+ // NodeList or HTMLCollection
734
+ if (Helper.isNodeList(config.elements)) {
735
+ config.elements = Array.from(config.elements);
736
+ }
737
+ // Single element
738
+ else {
739
+ config.elements = [config.elements];
740
+ }
741
+ }
742
+ // Init loading
743
+ const promises = [];
744
+ // Get all images
745
+ let images = [];
746
+ config.elements.forEach((element) => {
747
+ images = images.concat(Array.from(element.getElementsByTagName('img')));
748
+ });
749
+ // Prepare images
750
+ for (const image of images) {
751
+ const src = image.getAttribute('src');
752
+ // Check if changes are necessary and possible
753
+ if ((image.complete && image.naturalHeight !== 0) || // already laoded
754
+ image.getAttribute('loading') !== 'lazy' || // loading attribute !== lazy
755
+ !src || // Image has no src
756
+ ((_a = config.regExp) === null || _a === void 0 ? void 0 : _a.test(src)) // Test if src matches regular expression
757
+ ) {
758
+ continue;
759
+ }
760
+ // Replace lazy loading image with immediately loading image
761
+ const newImage = document.createElement('img');
762
+ Array.from(image.attributes).forEach((attr) => {
763
+ if (attr.name !== 'loading' && attr.name !== 'src') {
764
+ newImage.setAttribute(attr.name, attr.value);
765
+ }
766
+ });
767
+ image.replaceWith(newImage);
768
+ // Wait for laoding
769
+ promises.push(this.loadImage(newImage, src));
770
+ }
771
+ if (config.timeout) {
772
+ timeoutId = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
773
+ resolved = true;
774
+ if (config.doneFunnction) {
775
+ yield config.doneFunction();
776
+ }
777
+ resolve(undefined);
778
+ }));
779
+ }
780
+ // Wait until all images loaded
781
+ Promise.all(promises)
782
+ .catch((e) => console.error('Error during image loading', e))
783
+ .finally(() => __awaiter(this, void 0, void 0, function* () {
784
+ // Check if already resolved
785
+ if (resolved) {
786
+ return;
787
+ }
788
+ // Stop timeout
789
+ if (timeoutId) {
790
+ clearTimeout(timeoutId);
791
+ }
792
+ // Return result
793
+ let result;
794
+ if (config.doneFunnction) {
795
+ result = yield config.doneFunction();
796
+ }
797
+ resolve(result);
798
+ }));
799
+ });
800
+ }
801
+ /**
802
+ * Load image for image element
803
+ *
804
+ * @param imageElement
805
+ * @param src
806
+ * @protected
807
+ */
808
+ loadImage(imageElement, src) {
809
+ return __awaiter(this, void 0, void 0, function* () {
810
+ src = src || imageElement.src;
811
+ return new Promise((resolve, reject) => {
812
+ imageElement.onload = () => resolve(imageElement);
813
+ imageElement.onerror = reject;
814
+ imageElement.src = src;
815
+ });
816
+ });
817
+ }
818
+ }
819
+ ImageService.ɵprov = i0.ɵɵdefineInjectable({ factory: function ImageService_Factory() { return new ImageService(); }, token: ImageService, providedIn: "root" });
820
+ ImageService.decorators = [
821
+ { type: Injectable, args: [{
822
+ providedIn: 'root',
823
+ },] }
824
+ ];
825
+
826
+ /**
827
+ * Set same height (maximum) to different elements
828
+ */
829
+ class MatchHeightDirective {
830
+ constructor(el, imageService, platformId) {
831
+ this.el = el;
832
+ this.imageService = imageService;
833
+ // Replace lazy loading images with immediate loading images
834
+ this.loadLazyImages = true;
835
+ this.isBrowser = isPlatformBrowser(platformId);
836
+ }
837
+ onResize() {
838
+ this.matchHeight(this.el.nativeElement, this.ltMatchHeight);
839
+ }
840
+ ngAfterViewChecked() {
841
+ this.matchHeight(this.el.nativeElement, this.ltMatchHeight);
842
+ }
843
+ matchHeight(parent, target) {
844
+ if (this.isBrowser) {
845
+ // Timeout is set to force Angular to wait for all actions and only continue once the process has run through.
846
+ // Otherwise, an infinite loop will occur.
847
+ setTimeout(() => {
848
+ this.matchHeightHelper(parent, target);
849
+ }, 1);
850
+ }
851
+ else {
852
+ this.matchHeightHelper(parent, target);
853
+ }
854
+ }
855
+ matchHeightHelper(parent, target) {
856
+ return __awaiter(this, void 0, void 0, function* () {
857
+ if (!parent) {
858
+ return;
859
+ }
860
+ let classNames;
861
+ if (!Array.isArray(target)) {
862
+ classNames = [target];
863
+ }
864
+ else {
865
+ classNames = target;
866
+ }
867
+ for (const className of classNames) {
868
+ // find all child structureElements with the selected class name
869
+ const children = parent.getElementsByClassName(className);
870
+ if (!children || children.length < 2) {
871
+ continue;
872
+ }
873
+ // Load images of children
874
+ if (this.loadLazyImages) {
875
+ yield this.imageService.preLoadImages({ elements: children });
876
+ }
877
+ // reset all children height
878
+ Array.from(children).forEach((element) => {
879
+ element.style.height = 'initial';
880
+ });
881
+ // get all the child structureElements heights
882
+ const itemHeights = Array.from(children).map((element) => {
883
+ if (element.getBoundingClientRect) {
884
+ return element.getBoundingClientRect().height;
885
+ }
886
+ return 0;
887
+ });
888
+ // find out the tallest one
889
+ const maxHeight = itemHeights.reduce((prev, curr) => (curr > prev ? curr : prev), 0);
890
+ // update the child structureElements height to the tallest one
891
+ Array.from(children).forEach((element) => (element.style.height = `${maxHeight}px`));
892
+ }
893
+ });
894
+ }
895
+ }
896
+ MatchHeightDirective.decorators = [
897
+ { type: Directive, args: [{
898
+ selector: '[ltMatchHeight]',
899
+ },] }
900
+ ];
901
+ MatchHeightDirective.ctorParameters = () => [
902
+ { type: ElementRef },
903
+ { type: ImageService },
904
+ { type: String, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }
905
+ ];
906
+ MatchHeightDirective.propDecorators = {
907
+ ltMatchHeight: [{ type: Input }],
908
+ loadLazyImages: [{ type: Input }],
909
+ onResize: [{ type: HostListener, args: ['window:resize',] }]
910
+ };
911
+
912
+ /**
913
+ * Reszise detection
914
+ * (inpsired by: https://stackblitz.com/edit/angular-resizable)
915
+ */
916
+ class ResizableDirective {
917
+ constructor(el) {
918
+ this.el = el;
919
+ this.resizableGrabWidth = 8;
920
+ this.resizableMinWidth = 10;
921
+ this.dragging = false;
922
+ }
923
+ ngOnInit() {
924
+ this.addListenerToDocument();
925
+ this.addListenerToElement();
926
+ }
927
+ mouseMoveG(evt) {
928
+ if (!this.dragging) {
929
+ return;
930
+ }
931
+ this.newWidth(evt.clientX - this.el.nativeElement.offsetLeft);
932
+ evt.stopPropagation();
933
+ }
934
+ newWidth(wid) {
935
+ const result = Math.max(this.resizableMinWidth, wid);
936
+ this.el.nativeElement.style.width = result + 'px';
937
+ }
938
+ mouseDown(evt) {
939
+ if (this.inDragRegion(evt)) {
940
+ this.dragging = true;
941
+ this.preventGlobalMouseEvents();
942
+ evt.stopPropagation();
943
+ }
944
+ }
945
+ restoreGlobalMouseEvents() {
946
+ document.body.style['pointer-events'] = 'auto';
947
+ }
948
+ mouseUpG(evt) {
949
+ if (!this.dragging) {
950
+ return;
951
+ }
952
+ this.restoreGlobalMouseEvents();
953
+ this.dragging = false;
954
+ evt.stopPropagation();
955
+ }
956
+ mouseMove(evt) {
957
+ if (this.inDragRegion(evt) || this.dragging) {
958
+ this.el.nativeElement.style.cursor = 'col-resize';
959
+ }
960
+ else {
961
+ this.el.nativeElement.style.cursor = 'default';
883
962
  }
884
- // Process object
885
- if (typeof a === 'object') {
886
- const plain = JSON.parse(JSON.stringify(a));
887
- for (const [key, value] of Object.entries(plain)) {
888
- if (Helper.isSubset(value, b[key])) {
889
- return false;
890
- }
891
- }
892
- return true;
963
+ }
964
+ preventGlobalMouseEvents() {
965
+ document.body.style['pointer-events'] = 'none';
966
+ }
967
+ inDragRegion(evt) {
968
+ return this.el.nativeElement.clientWidth - evt.clientX + this.el.nativeElement.offsetLeft < this.resizableGrabWidth;
969
+ }
970
+ addListenerToDocument() {
971
+ document.addEventListener('mousemove', (e) => {
972
+ this.mouseMoveG(e);
973
+ }, true);
974
+ document.addEventListener('mouseup', (e) => {
975
+ this.mouseUpG(e);
976
+ }, true);
977
+ }
978
+ addListenerToElement() {
979
+ this.el.nativeElement.addEventListener('mousedown', (e) => {
980
+ this.mouseDown(e);
981
+ }, true);
982
+ this.el.nativeElement.addEventListener('mousemove', (e) => {
983
+ this.mouseMove(e);
984
+ }, true);
985
+ }
986
+ }
987
+ ResizableDirective.decorators = [
988
+ { type: Directive, args: [{
989
+ selector: '[ltResizable]',
990
+ },] }
991
+ ];
992
+ ResizableDirective.ctorParameters = () => [
993
+ { type: ElementRef }
994
+ ];
995
+ ResizableDirective.propDecorators = {
996
+ resizableGrabWidth: [{ type: Input }],
997
+ resizableMinWidth: [{ type: Input }]
998
+ };
999
+
1000
+ /**
1001
+ * Truncate string with ellipses
1002
+ */
1003
+ class EllipsesPipe {
1004
+ transform(value, limit) {
1005
+ if (!value) {
1006
+ return null;
893
1007
  }
894
- // Else
895
- return true;
1008
+ return value.length > limit ? value.substring(0, limit) + '...' : value;
896
1009
  }
897
- /**
898
- * Whether parameters are equal (have equal properties)
899
- * Hint: functions will be ignored
900
- */
901
- static isEqual(a, b) {
902
- return Helper.isSubset(a, b) && Helper.isSubset(b, a);
1010
+ }
1011
+ EllipsesPipe.decorators = [
1012
+ { type: Pipe, args: [{
1013
+ name: 'ltEllipses',
1014
+ },] }
1015
+ ];
1016
+
1017
+ /**
1018
+ * Declarate html as safe
1019
+ */
1020
+ class SafeHtmlPipe {
1021
+ constructor(sanitized) {
1022
+ this.sanitized = sanitized;
1023
+ }
1024
+ transform(value) {
1025
+ return this.sanitized.bypassSecurityTrustHtml(value);
903
1026
  }
1027
+ }
1028
+ SafeHtmlPipe.decorators = [
1029
+ { type: Pipe, args: [{ name: 'ltSafeHtml' },] }
1030
+ ];
1031
+ SafeHtmlPipe.ctorParameters = () => [
1032
+ { type: DomSanitizer }
1033
+ ];
1034
+
1035
+ // Imported and exported elements
1036
+ const elements = [
1037
+ // Directives
1038
+ ContextMenuDirective,
1039
+ LazyLoadDirective,
1040
+ MatchHeightDirective,
1041
+ ResizableDirective,
1042
+ // Pipes
1043
+ EllipsesPipe,
1044
+ SafeHtmlPipe,
1045
+ ];
1046
+ /**
1047
+ * Base module
1048
+ */
1049
+ class BaseModule {
904
1050
  /**
905
- * First level difference of two objects
906
- * Hint: functions will be ignored and when an array or an object is different the hole array or object will used as property value
907
- *
908
- * @returns Record<string, any> Object with properties from first object
1051
+ * Set configuration of base module in root module of the app
909
1052
  */
910
- static getDiff(a, b, clone = true) {
911
- const result = {};
912
- let firstObject = a;
913
- if (clone) {
914
- firstObject = JSON.parse(JSON.stringify(a));
1053
+ static forRoot(baseModuleConfig = {}) {
1054
+ // Default config
1055
+ const config = Object.assign({ apiUrl: 'localhost:3000', authGuardRedirectUrl: '/auth', logging: false, version: null, prefix: null, scrollDetectionOffset: 200, scrollOffset: 100, storageType: 'local' }, baseModuleConfig);
1056
+ // Prepare providers
1057
+ const providers = [
1058
+ {
1059
+ provide: BASE_MODULE_CONFIG,
1060
+ useValue: baseModuleConfig,
1061
+ },
1062
+ ];
1063
+ // Add apollo features if API URL is set
1064
+ if (baseModuleConfig.apiUrl) {
1065
+ providers.push({
1066
+ provide: APOLLO_OPTIONS,
1067
+ useFactory: apolloOptionsFactory,
1068
+ deps: [BASE_MODULE_CONFIG, HttpLink, AuthService],
1069
+ });
915
1070
  }
916
- for (const [key, value] of Object.entries(firstObject)) {
917
- if (!Helper.isSubset(value, b[key])) {
918
- result[key] = value;
919
- }
1071
+ else if (config.logging) {
1072
+ console.log('apiUrl is missing, ApolloLink is not initialized');
920
1073
  }
921
- return result;
1074
+ // Return root module
1075
+ return {
1076
+ ngModule: BaseModule,
1077
+ providers,
1078
+ };
922
1079
  }
923
1080
  }
1081
+ BaseModule.decorators = [
1082
+ { type: NgModule, args: [{
1083
+ declarations: elements,
1084
+ exports: elements,
1085
+ },] }
1086
+ ];
924
1087
 
925
1088
  /**
926
1089
  * Standard class
@@ -2001,9 +2164,10 @@ class ScrollService {
2001
2164
  /**
2002
2165
  * Initializer
2003
2166
  */
2004
- constructor(router, moduleConfig) {
2167
+ constructor(router, moduleConfig, imageService) {
2005
2168
  this.router = router;
2006
2169
  this.moduleConfig = moduleConfig;
2170
+ this.imageService = imageService;
2007
2171
  /**
2008
2172
  * Is a scroll listener set
2009
2173
  *
@@ -2053,7 +2217,7 @@ class ScrollService {
2053
2217
  }
2054
2218
  // Load images before scrolling (once)
2055
2219
  if (config.loadImagesBefore) {
2056
- yield this.preLoadImages();
2220
+ yield this.imageService.preLoadImages();
2057
2221
  }
2058
2222
  // Get get bounding rect of target element
2059
2223
  const cords = el.getBoundingClientRect();
@@ -2164,87 +2328,8 @@ class ScrollService {
2164
2328
  // Return promise
2165
2329
  return this.scrollPromise;
2166
2330
  }
2167
- /**
2168
- * Preaload images (for lazy handling)
2169
- *
2170
- * @param options
2171
- * @protected
2172
- */
2173
- preLoadImages(options) {
2174
- // Init configuration
2175
- const config = Object.assign({ doneFunnction: undefined, timeout: undefined }, options);
2176
- return new Promise((resolve) => {
2177
- // Init variables
2178
- let resolved = false;
2179
- let timeoutId;
2180
- // Init loading
2181
- const images = Array.from(document.getElementsByTagName('img'));
2182
- const promises = [];
2183
- // Prepare images
2184
- for (const image of images) {
2185
- const src = image.getAttribute('src');
2186
- // Check if changes are necessary and possible
2187
- if ((image.complete && image.naturalHeight !== 0) || image.getAttribute('loading') !== 'lazy' || !src) {
2188
- continue;
2189
- }
2190
- const newImage = document.createElement('img');
2191
- Array.from(image.attributes).forEach((attr) => {
2192
- if (attr.name !== 'loading' && attr.name !== 'src') {
2193
- newImage.setAttribute(attr.name, attr.value);
2194
- }
2195
- });
2196
- image.replaceWith(newImage);
2197
- promises.push(this.loadImage(newImage, src));
2198
- }
2199
- if (config.timeout) {
2200
- timeoutId = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
2201
- resolved = true;
2202
- if (config.doneFunnction) {
2203
- yield config.doneFunction();
2204
- }
2205
- resolve(undefined);
2206
- }));
2207
- }
2208
- // Wait until all images loaded
2209
- Promise.all(promises)
2210
- .catch((e) => console.error('Error during image loading', e))
2211
- .finally(() => __awaiter(this, void 0, void 0, function* () {
2212
- // Check if already resolved
2213
- if (resolved) {
2214
- return;
2215
- }
2216
- // Stop timeout
2217
- if (timeoutId) {
2218
- clearTimeout(timeoutId);
2219
- }
2220
- // Return result
2221
- let result;
2222
- if (config.doneFunnction) {
2223
- result = yield config.doneFunction();
2224
- }
2225
- resolve(result);
2226
- }));
2227
- });
2228
- }
2229
- /**
2230
- * Load image for image element
2231
- *
2232
- * @param imageElement
2233
- * @param src
2234
- * @protected
2235
- */
2236
- loadImage(imageElement, src) {
2237
- return __awaiter(this, void 0, void 0, function* () {
2238
- src = src || imageElement.src;
2239
- return new Promise((resolve, reject) => {
2240
- imageElement.onload = () => resolve(imageElement);
2241
- imageElement.onerror = reject;
2242
- imageElement.src = src;
2243
- });
2244
- });
2245
- }
2246
2331
  }
2247
- ScrollService.ɵprov = i0.ɵɵdefineInjectable({ factory: function ScrollService_Factory() { return new ScrollService(i0.ɵɵinject(i1$1.Router), i0.ɵɵinject(BASE_MODULE_CONFIG)); }, token: ScrollService, providedIn: "root" });
2332
+ ScrollService.ɵprov = i0.ɵɵdefineInjectable({ factory: function ScrollService_Factory() { return new ScrollService(i0.ɵɵinject(i1$1.Router), i0.ɵɵinject(BASE_MODULE_CONFIG), i0.ɵɵinject(ImageService)); }, token: ScrollService, providedIn: "root" });
2248
2333
  ScrollService.decorators = [
2249
2334
  { type: Injectable, args: [{
2250
2335
  providedIn: 'root',
@@ -2252,7 +2337,8 @@ ScrollService.decorators = [
2252
2337
  ];
2253
2338
  ScrollService.ctorParameters = () => [
2254
2339
  { type: Router },
2255
- { type: undefined, decorators: [{ type: Inject, args: [BASE_MODULE_CONFIG,] }] }
2340
+ { type: undefined, decorators: [{ type: Inject, args: [BASE_MODULE_CONFIG,] }] },
2341
+ { type: ImageService }
2256
2342
  ];
2257
2343
 
2258
2344
  /**
@@ -2263,23 +2349,79 @@ class SEOService {
2263
2349
  this.titleService = titleService;
2264
2350
  this.metaTagService = metaTagService;
2265
2351
  }
2266
- initPageForSEO(title, description, keywords) {
2267
- this.setPageTitle(title);
2268
- this.setPageDescription(description);
2269
- if (keywords) {
2270
- this.setPageKeywords(keywords);
2352
+ initPageForSEO(input) {
2353
+ this.setGeneralData(input);
2354
+ this.setTwitterData(input);
2355
+ this.setTwitterData(input);
2356
+ this.setFacebookData(input);
2357
+ if (input.keywords) {
2358
+ this.setPageKeywords(input.keywords);
2271
2359
  }
2272
2360
  }
2273
- setPageTitle(title) {
2274
- this.titleService.setTitle(title);
2275
- this.metaTagService.updateTag({ property: 'og:title', content: title });
2276
- this.metaTagService.updateTag({ name: 'twitter:title', content: title });
2361
+ /**
2362
+ * Set general metadata
2363
+ *
2364
+ * @param data
2365
+ * @private
2366
+ */
2367
+ setGeneralData(data) {
2368
+ this.titleService.setTitle(data.title);
2369
+ this.metaTagService.updateTag({ name: 'description', content: data.description });
2370
+ }
2371
+ /**
2372
+ * Set metadata for twitter
2373
+ *
2374
+ * @param data
2375
+ * @private
2376
+ */
2377
+ setTwitterData(data) {
2378
+ this.metaTagService.updateTag({ name: 'twitter:title', content: data.title });
2379
+ this.metaTagService.updateTag({ name: 'twitter:description', content: data.description });
2380
+ this.metaTagService.updateTag({
2381
+ property: 'twitter:url',
2382
+ content: data.url ? data.url : window.location.href,
2383
+ });
2384
+ if (data.image) {
2385
+ this.metaTagService.updateTag({
2386
+ property: 'twitter:image',
2387
+ content: data.image,
2388
+ });
2389
+ this.metaTagService.updateTag({
2390
+ property: 'twitter:card',
2391
+ content: 'summary_large_image',
2392
+ });
2393
+ }
2277
2394
  }
2278
- setPageDescription(description) {
2279
- this.metaTagService.updateTag({ name: 'description', content: description });
2280
- this.metaTagService.updateTag({ property: 'og:description', content: description });
2281
- this.metaTagService.updateTag({ name: 'twitter:description', content: description });
2395
+ /**
2396
+ * Set metadata for facebook
2397
+ *
2398
+ * @param data
2399
+ * @private
2400
+ */
2401
+ setFacebookData(data) {
2402
+ this.metaTagService.updateTag({ property: 'og:title', content: data.title });
2403
+ this.metaTagService.updateTag({ property: 'og:description', content: data.description });
2404
+ this.metaTagService.updateTag({
2405
+ property: 'og:type',
2406
+ content: 'website',
2407
+ });
2408
+ this.metaTagService.updateTag({
2409
+ property: 'og:url',
2410
+ content: data.url ? data.url : window.location.href,
2411
+ });
2412
+ if (data.image) {
2413
+ this.metaTagService.updateTag({
2414
+ property: 'og:image',
2415
+ content: data.image,
2416
+ });
2417
+ }
2282
2418
  }
2419
+ /**
2420
+ * Set page keywords
2421
+ *
2422
+ * @param keywords
2423
+ * @private
2424
+ */
2283
2425
  setPageKeywords(keywords) {
2284
2426
  this.metaTagService.updateTag({ name: 'keywords', content: keywords });
2285
2427
  }
@@ -2327,5 +2469,5 @@ function MustMatch(controlName, matchingControlName) {
2327
2469
  * Generated bundle index. Do not edit.
2328
2470
  */
2329
2471
 
2330
- export { AuthGuard, AuthService, BASE_MODULE_CONFIG, BaseModule, BasicUser, CanDeactivateGuard, ComparisonOperatorEnum, ContextMenuDirective, EllipsesPipe, FullscreenService, GraphQLEnum, GraphQLMeta, GraphQLMetaService, GraphQLPlusService, GraphQLRequestType, GraphQLService, GraphQLType, Helper, LazyLoadDirective, LoaderService, LogicalOperatorEnum, LogoutGuard, MatchHeightDirective, MustMatch, ResizableDirective, SEOService, SafeHtmlPipe, ScrollService, SortOrderEnum, Standard, StorageService, apolloOptionsFactory };
2472
+ export { AuthGuard, AuthService, BASE_MODULE_CONFIG, BaseModule, BasicUser, CanDeactivateGuard, ComparisonOperatorEnum, ContextMenuDirective, EllipsesPipe, FullscreenService, GraphQLEnum, GraphQLMeta, GraphQLMetaService, GraphQLPlusService, GraphQLRequestType, GraphQLService, GraphQLType, Helper, ImageService, LazyLoadDirective, LoaderService, LogicalOperatorEnum, LogoutGuard, MatchHeightDirective, MustMatch, ResizableDirective, SEOService, SafeHtmlPipe, ScrollService, SortOrderEnum, Standard, StorageService, apolloOptionsFactory };
2331
2473
  //# sourceMappingURL=lenne.tech-ng-base.js.map