@lenne.tech/ng-base 0.3.2 → 0.3.6
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.
- package/bundles/lenne.tech-ng-base-src-lib-base.umd.js +781 -749
- package/bundles/lenne.tech-ng-base-src-lib-base.umd.js.map +1 -1
- package/bundles/lenne.tech-ng-base.umd.js +781 -749
- package/bundles/lenne.tech-ng-base.umd.js.map +1 -1
- package/esm2015/lib/base/classes/helper.class.js +19 -1
- package/esm2015/lib/base/directives/match-height.directive.js +19 -14
- package/esm2015/lib/base/factories/apollo-options.factory.js +3 -2
- package/esm2015/lib/base/services/image.service.js +24 -38
- package/esm2015/lib/base/services/scroll.service.js +8 -29
- package/esm2015/lib/base/services/seo.service.js +70 -14
- package/esm2015/src/lib/base/classes/helper.class.js +19 -1
- package/esm2015/src/lib/base/directives/match-height.directive.js +19 -14
- package/esm2015/src/lib/base/factories/apollo-options.factory.js +3 -2
- package/esm2015/src/lib/base/services/image.service.js +24 -38
- package/esm2015/src/lib/base/services/scroll.service.js +8 -29
- package/esm2015/src/lib/base/services/seo.service.js +70 -14
- package/fesm2015/lenne.tech-ng-base-src-lib-base.js +517 -473
- package/fesm2015/lenne.tech-ng-base-src-lib-base.js.map +1 -1
- package/fesm2015/lenne.tech-ng-base.js +517 -473
- package/fesm2015/lenne.tech-ng-base.js.map +1 -1
- package/lib/base/classes/helper.class.d.ts +7 -0
- package/lib/base/directives/match-height.directive.d.ts +7 -7
- package/lib/base/services/image.service.d.ts +1 -2
- package/lib/base/services/scroll.service.d.ts +1 -2
- package/lib/base/services/seo.service.d.ts +36 -3
- package/package.json +1 -1
- package/src/lib/base/classes/helper.class.d.ts +7 -0
- package/src/lib/base/directives/match-height.directive.d.ts +7 -7
- package/src/lib/base/lenne.tech-ng-base-src-lib-base.metadata.json +1 -1
- package/src/lib/base/services/image.service.d.ts +1 -2
- package/src/lib/base/services/scroll.service.d.ts +1 -2
- package/src/lib/base/services/seo.service.d.ts +36 -3
|
@@ -2,13 +2,14 @@ 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,
|
|
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
11
|
import { __awaiter } from 'tslib';
|
|
12
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
12
13
|
import * as i1$2 from '@angular/platform-browser';
|
|
13
14
|
import { DomSanitizer, Title, Meta } from '@angular/platform-browser';
|
|
14
15
|
import * as i1$1 from '@angular/router';
|
|
@@ -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,362 +420,6 @@ LazyLoadDirective.propDecorators = {
|
|
|
418
420
|
src: [{ type: Input }]
|
|
419
421
|
};
|
|
420
422
|
|
|
421
|
-
/**
|
|
422
|
-
* Image service
|
|
423
|
-
*/
|
|
424
|
-
class ImageService {
|
|
425
|
-
/**
|
|
426
|
-
* Preaload images (for lazy handling)
|
|
427
|
-
*
|
|
428
|
-
* @param options
|
|
429
|
-
* @protected
|
|
430
|
-
*/
|
|
431
|
-
preLoadImages(options) {
|
|
432
|
-
// Init configuration
|
|
433
|
-
const config = Object.assign({ doneFunnction: undefined, elements: document, regExp: undefined, timeout: undefined }, options);
|
|
434
|
-
return new Promise((resolve) => {
|
|
435
|
-
var _a;
|
|
436
|
-
// Init variables
|
|
437
|
-
let resolved = false;
|
|
438
|
-
let timeoutId;
|
|
439
|
-
// HTMLCollection to array
|
|
440
|
-
if (config.elements instanceof HTMLCollection) {
|
|
441
|
-
config.elements = Array.from(config.elements);
|
|
442
|
-
}
|
|
443
|
-
// Single element to array
|
|
444
|
-
if (!Array.isArray(config.elements)) {
|
|
445
|
-
config.elements = [config.elements];
|
|
446
|
-
}
|
|
447
|
-
// Init loading
|
|
448
|
-
const promises = [];
|
|
449
|
-
// Get all images
|
|
450
|
-
let images = [];
|
|
451
|
-
config.elements.forEach((element) => {
|
|
452
|
-
images = images.concat(Array.from(element.getElementsByTagName('img')));
|
|
453
|
-
});
|
|
454
|
-
// Prepare images
|
|
455
|
-
for (const image of images) {
|
|
456
|
-
const src = image.getAttribute('src');
|
|
457
|
-
// Check if changes are necessary and possible
|
|
458
|
-
if ((image.complete && image.naturalHeight !== 0) || // already laoded
|
|
459
|
-
image.getAttribute('loading') !== 'lazy' || // loading attribute !== lazy
|
|
460
|
-
!src || // Image has no src
|
|
461
|
-
((_a = config.regExp) === null || _a === void 0 ? void 0 : _a.test(src)) // Test if src matches regular expression
|
|
462
|
-
) {
|
|
463
|
-
continue;
|
|
464
|
-
}
|
|
465
|
-
// Replace lazy loading image with immediately loading image
|
|
466
|
-
const newImage = document.createElement('img');
|
|
467
|
-
Array.from(image.attributes).forEach((attr) => {
|
|
468
|
-
if (attr.name !== 'loading' && attr.name !== 'src') {
|
|
469
|
-
newImage.setAttribute(attr.name, attr.value);
|
|
470
|
-
}
|
|
471
|
-
});
|
|
472
|
-
image.replaceWith(newImage);
|
|
473
|
-
// Wait for laoding
|
|
474
|
-
promises.push(this.loadImage(newImage, src));
|
|
475
|
-
}
|
|
476
|
-
if (config.timeout) {
|
|
477
|
-
timeoutId = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
|
|
478
|
-
resolved = true;
|
|
479
|
-
if (config.doneFunnction) {
|
|
480
|
-
yield config.doneFunction();
|
|
481
|
-
}
|
|
482
|
-
resolve(undefined);
|
|
483
|
-
}));
|
|
484
|
-
}
|
|
485
|
-
// Wait until all images loaded
|
|
486
|
-
Promise.all(promises)
|
|
487
|
-
.catch((e) => console.error('Error during image loading', e))
|
|
488
|
-
.finally(() => __awaiter(this, void 0, void 0, function* () {
|
|
489
|
-
// Check if already resolved
|
|
490
|
-
if (resolved) {
|
|
491
|
-
return;
|
|
492
|
-
}
|
|
493
|
-
// Stop timeout
|
|
494
|
-
if (timeoutId) {
|
|
495
|
-
clearTimeout(timeoutId);
|
|
496
|
-
}
|
|
497
|
-
// Return result
|
|
498
|
-
let result;
|
|
499
|
-
if (config.doneFunnction) {
|
|
500
|
-
result = yield config.doneFunction();
|
|
501
|
-
}
|
|
502
|
-
resolve(result);
|
|
503
|
-
}));
|
|
504
|
-
});
|
|
505
|
-
}
|
|
506
|
-
/**
|
|
507
|
-
* Load image for image element
|
|
508
|
-
*
|
|
509
|
-
* @param imageElement
|
|
510
|
-
* @param src
|
|
511
|
-
* @protected
|
|
512
|
-
*/
|
|
513
|
-
loadImage(imageElement, src) {
|
|
514
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
515
|
-
src = src || imageElement.src;
|
|
516
|
-
return new Promise((resolve, reject) => {
|
|
517
|
-
imageElement.onload = () => resolve(imageElement);
|
|
518
|
-
imageElement.onerror = reject;
|
|
519
|
-
imageElement.src = src;
|
|
520
|
-
});
|
|
521
|
-
});
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
ImageService.ɵprov = i0.ɵɵdefineInjectable({ factory: function ImageService_Factory() { return new ImageService(); }, token: ImageService, providedIn: "root" });
|
|
525
|
-
ImageService.decorators = [
|
|
526
|
-
{ type: Injectable, args: [{
|
|
527
|
-
providedIn: 'root',
|
|
528
|
-
},] }
|
|
529
|
-
];
|
|
530
|
-
|
|
531
|
-
/**
|
|
532
|
-
* Set same height (maximum) to different elements
|
|
533
|
-
*/
|
|
534
|
-
class MatchHeightDirective {
|
|
535
|
-
constructor(el, imageService, zone) {
|
|
536
|
-
this.el = el;
|
|
537
|
-
this.imageService = imageService;
|
|
538
|
-
this.zone = zone;
|
|
539
|
-
this.loadLazyImages = true;
|
|
540
|
-
}
|
|
541
|
-
onResize() {
|
|
542
|
-
this.matchHeight(this.el.nativeElement, this.ltMatchHeight);
|
|
543
|
-
}
|
|
544
|
-
ngAfterViewChecked() {
|
|
545
|
-
this.matchHeight(this.el.nativeElement, this.ltMatchHeight);
|
|
546
|
-
}
|
|
547
|
-
matchHeight(parent, target) {
|
|
548
|
-
// Timeout is set to force Angular to wait for all actions and only continue once the process has run through.
|
|
549
|
-
// Otherwise, an infinite loop will occur.
|
|
550
|
-
setTimeout(() => __awaiter(this, void 0, void 0, function* () {
|
|
551
|
-
if (!parent) {
|
|
552
|
-
return;
|
|
553
|
-
}
|
|
554
|
-
let classNames;
|
|
555
|
-
if (!Array.isArray(target)) {
|
|
556
|
-
classNames = [target];
|
|
557
|
-
}
|
|
558
|
-
else {
|
|
559
|
-
classNames = target;
|
|
560
|
-
}
|
|
561
|
-
for (const className of classNames) {
|
|
562
|
-
// find all child structureElements with the selected class name
|
|
563
|
-
const children = parent.getElementsByClassName(className);
|
|
564
|
-
if (!children || children.length < 2) {
|
|
565
|
-
continue;
|
|
566
|
-
}
|
|
567
|
-
// Load images of children
|
|
568
|
-
if (this.loadLazyImages) {
|
|
569
|
-
yield this.imageService.preLoadImages({ elements: children });
|
|
570
|
-
}
|
|
571
|
-
// reset all children height
|
|
572
|
-
Array.from(children).forEach((element) => {
|
|
573
|
-
element.style.height = 'initial';
|
|
574
|
-
});
|
|
575
|
-
// get all the child structureElements heights
|
|
576
|
-
const itemHeights = Array.from(children).map((x) => x.getBoundingClientRect().height);
|
|
577
|
-
// find out the tallest one
|
|
578
|
-
const maxHeight = itemHeights.reduce((prev, curr) => (curr > prev ? curr : prev), 0);
|
|
579
|
-
// update the child structureElements height to the tallest one
|
|
580
|
-
Array.from(children).forEach((element) => (element.style.height = `${maxHeight}px`));
|
|
581
|
-
}
|
|
582
|
-
}), 1);
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
MatchHeightDirective.decorators = [
|
|
586
|
-
{ type: Directive, args: [{
|
|
587
|
-
selector: '[ltMatchHeight]',
|
|
588
|
-
},] }
|
|
589
|
-
];
|
|
590
|
-
MatchHeightDirective.ctorParameters = () => [
|
|
591
|
-
{ type: ElementRef },
|
|
592
|
-
{ type: ImageService },
|
|
593
|
-
{ type: NgZone }
|
|
594
|
-
];
|
|
595
|
-
MatchHeightDirective.propDecorators = {
|
|
596
|
-
ltMatchHeight: [{ type: Input }],
|
|
597
|
-
loadLazyImages: [{ type: Input }],
|
|
598
|
-
onResize: [{ type: HostListener, args: ['window:resize',] }]
|
|
599
|
-
};
|
|
600
|
-
|
|
601
|
-
/**
|
|
602
|
-
* Reszise detection
|
|
603
|
-
* (inpsired by: https://stackblitz.com/edit/angular-resizable)
|
|
604
|
-
*/
|
|
605
|
-
class ResizableDirective {
|
|
606
|
-
constructor(el) {
|
|
607
|
-
this.el = el;
|
|
608
|
-
this.resizableGrabWidth = 8;
|
|
609
|
-
this.resizableMinWidth = 10;
|
|
610
|
-
this.dragging = false;
|
|
611
|
-
}
|
|
612
|
-
ngOnInit() {
|
|
613
|
-
this.addListenerToDocument();
|
|
614
|
-
this.addListenerToElement();
|
|
615
|
-
}
|
|
616
|
-
mouseMoveG(evt) {
|
|
617
|
-
if (!this.dragging) {
|
|
618
|
-
return;
|
|
619
|
-
}
|
|
620
|
-
this.newWidth(evt.clientX - this.el.nativeElement.offsetLeft);
|
|
621
|
-
evt.stopPropagation();
|
|
622
|
-
}
|
|
623
|
-
newWidth(wid) {
|
|
624
|
-
const result = Math.max(this.resizableMinWidth, wid);
|
|
625
|
-
this.el.nativeElement.style.width = result + 'px';
|
|
626
|
-
}
|
|
627
|
-
mouseDown(evt) {
|
|
628
|
-
if (this.inDragRegion(evt)) {
|
|
629
|
-
this.dragging = true;
|
|
630
|
-
this.preventGlobalMouseEvents();
|
|
631
|
-
evt.stopPropagation();
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
restoreGlobalMouseEvents() {
|
|
635
|
-
document.body.style['pointer-events'] = 'auto';
|
|
636
|
-
}
|
|
637
|
-
mouseUpG(evt) {
|
|
638
|
-
if (!this.dragging) {
|
|
639
|
-
return;
|
|
640
|
-
}
|
|
641
|
-
this.restoreGlobalMouseEvents();
|
|
642
|
-
this.dragging = false;
|
|
643
|
-
evt.stopPropagation();
|
|
644
|
-
}
|
|
645
|
-
mouseMove(evt) {
|
|
646
|
-
if (this.inDragRegion(evt) || this.dragging) {
|
|
647
|
-
this.el.nativeElement.style.cursor = 'col-resize';
|
|
648
|
-
}
|
|
649
|
-
else {
|
|
650
|
-
this.el.nativeElement.style.cursor = 'default';
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
preventGlobalMouseEvents() {
|
|
654
|
-
document.body.style['pointer-events'] = 'none';
|
|
655
|
-
}
|
|
656
|
-
inDragRegion(evt) {
|
|
657
|
-
return this.el.nativeElement.clientWidth - evt.clientX + this.el.nativeElement.offsetLeft < this.resizableGrabWidth;
|
|
658
|
-
}
|
|
659
|
-
addListenerToDocument() {
|
|
660
|
-
document.addEventListener('mousemove', (e) => {
|
|
661
|
-
this.mouseMoveG(e);
|
|
662
|
-
}, true);
|
|
663
|
-
document.addEventListener('mouseup', (e) => {
|
|
664
|
-
this.mouseUpG(e);
|
|
665
|
-
}, true);
|
|
666
|
-
}
|
|
667
|
-
addListenerToElement() {
|
|
668
|
-
this.el.nativeElement.addEventListener('mousedown', (e) => {
|
|
669
|
-
this.mouseDown(e);
|
|
670
|
-
}, true);
|
|
671
|
-
this.el.nativeElement.addEventListener('mousemove', (e) => {
|
|
672
|
-
this.mouseMove(e);
|
|
673
|
-
}, true);
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
ResizableDirective.decorators = [
|
|
677
|
-
{ type: Directive, args: [{
|
|
678
|
-
selector: '[ltResizable]',
|
|
679
|
-
},] }
|
|
680
|
-
];
|
|
681
|
-
ResizableDirective.ctorParameters = () => [
|
|
682
|
-
{ type: ElementRef }
|
|
683
|
-
];
|
|
684
|
-
ResizableDirective.propDecorators = {
|
|
685
|
-
resizableGrabWidth: [{ type: Input }],
|
|
686
|
-
resizableMinWidth: [{ type: Input }]
|
|
687
|
-
};
|
|
688
|
-
|
|
689
|
-
/**
|
|
690
|
-
* Truncate string with ellipses
|
|
691
|
-
*/
|
|
692
|
-
class EllipsesPipe {
|
|
693
|
-
transform(value, limit) {
|
|
694
|
-
if (!value) {
|
|
695
|
-
return null;
|
|
696
|
-
}
|
|
697
|
-
return value.length > limit ? value.substring(0, limit) + '...' : value;
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
EllipsesPipe.decorators = [
|
|
701
|
-
{ type: Pipe, args: [{
|
|
702
|
-
name: 'ltEllipses',
|
|
703
|
-
},] }
|
|
704
|
-
];
|
|
705
|
-
|
|
706
|
-
/**
|
|
707
|
-
* Declarate html as safe
|
|
708
|
-
*/
|
|
709
|
-
class SafeHtmlPipe {
|
|
710
|
-
constructor(sanitized) {
|
|
711
|
-
this.sanitized = sanitized;
|
|
712
|
-
}
|
|
713
|
-
transform(value) {
|
|
714
|
-
return this.sanitized.bypassSecurityTrustHtml(value);
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
SafeHtmlPipe.decorators = [
|
|
718
|
-
{ type: Pipe, args: [{ name: 'ltSafeHtml' },] }
|
|
719
|
-
];
|
|
720
|
-
SafeHtmlPipe.ctorParameters = () => [
|
|
721
|
-
{ type: DomSanitizer }
|
|
722
|
-
];
|
|
723
|
-
|
|
724
|
-
// Imported and exported elements
|
|
725
|
-
const elements = [
|
|
726
|
-
// Directives
|
|
727
|
-
ContextMenuDirective,
|
|
728
|
-
LazyLoadDirective,
|
|
729
|
-
MatchHeightDirective,
|
|
730
|
-
ResizableDirective,
|
|
731
|
-
// Pipes
|
|
732
|
-
EllipsesPipe,
|
|
733
|
-
SafeHtmlPipe,
|
|
734
|
-
];
|
|
735
|
-
/**
|
|
736
|
-
* Base module
|
|
737
|
-
*/
|
|
738
|
-
class BaseModule {
|
|
739
|
-
/**
|
|
740
|
-
* Set configuration of base module in root module of the app
|
|
741
|
-
*/
|
|
742
|
-
static forRoot(baseModuleConfig = {}) {
|
|
743
|
-
// Default config
|
|
744
|
-
const config = Object.assign({ apiUrl: 'localhost:3000', authGuardRedirectUrl: '/auth', logging: false, version: null, prefix: null, scrollDetectionOffset: 200, scrollOffset: 100, storageType: 'local' }, baseModuleConfig);
|
|
745
|
-
// Prepare providers
|
|
746
|
-
const providers = [
|
|
747
|
-
{
|
|
748
|
-
provide: BASE_MODULE_CONFIG,
|
|
749
|
-
useValue: baseModuleConfig,
|
|
750
|
-
},
|
|
751
|
-
];
|
|
752
|
-
// Add apollo features if API URL is set
|
|
753
|
-
if (baseModuleConfig.apiUrl) {
|
|
754
|
-
providers.push({
|
|
755
|
-
provide: APOLLO_OPTIONS,
|
|
756
|
-
useFactory: apolloOptionsFactory,
|
|
757
|
-
deps: [BASE_MODULE_CONFIG, HttpLink, AuthService],
|
|
758
|
-
});
|
|
759
|
-
}
|
|
760
|
-
else if (config.logging) {
|
|
761
|
-
console.log('apiUrl is missing, ApolloLink is not initialized');
|
|
762
|
-
}
|
|
763
|
-
// Return root module
|
|
764
|
-
return {
|
|
765
|
-
ngModule: BaseModule,
|
|
766
|
-
providers,
|
|
767
|
-
};
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
BaseModule.decorators = [
|
|
771
|
-
{ type: NgModule, args: [{
|
|
772
|
-
declarations: elements,
|
|
773
|
-
exports: elements,
|
|
774
|
-
},] }
|
|
775
|
-
];
|
|
776
|
-
|
|
777
423
|
/**
|
|
778
424
|
* Helper class
|
|
779
425
|
*/
|
|
@@ -956,95 +602,458 @@ class Helper {
|
|
|
956
602
|
}
|
|
957
603
|
return dateString;
|
|
958
604
|
}
|
|
959
|
-
/**
|
|
960
|
-
* Get browser name and version
|
|
961
|
-
*/
|
|
962
|
-
static getBrowser() {
|
|
963
|
-
const userAgent = navigator.userAgent;
|
|
964
|
-
let data = userAgent.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
|
|
965
|
-
let version;
|
|
966
|
-
if (/trident/i.test(data[1])) {
|
|
967
|
-
version = /\brv[ :]+(\d+)/g.exec(userAgent) || [];
|
|
968
|
-
return { name: 'IE', version: version[1] || '' };
|
|
969
|
-
}
|
|
970
|
-
if (data[1] === 'Chrome') {
|
|
971
|
-
version = userAgent.match(/\bOPR|Edge\/(\d+)/);
|
|
972
|
-
if (version != null) {
|
|
973
|
-
return { name: 'Opera', version: version[1] };
|
|
974
|
-
}
|
|
605
|
+
/**
|
|
606
|
+
* Get browser name and version
|
|
607
|
+
*/
|
|
608
|
+
static getBrowser() {
|
|
609
|
+
const userAgent = navigator.userAgent;
|
|
610
|
+
let data = userAgent.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
|
|
611
|
+
let version;
|
|
612
|
+
if (/trident/i.test(data[1])) {
|
|
613
|
+
version = /\brv[ :]+(\d+)/g.exec(userAgent) || [];
|
|
614
|
+
return { name: 'IE', version: version[1] || '' };
|
|
615
|
+
}
|
|
616
|
+
if (data[1] === 'Chrome') {
|
|
617
|
+
version = userAgent.match(/\bOPR|Edge\/(\d+)/);
|
|
618
|
+
if (version != null) {
|
|
619
|
+
return { name: 'Opera', version: version[1] };
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
data = data[2] ? [data[1], data[2]] : [navigator.appName, navigator.appVersion, '-?'];
|
|
623
|
+
version = userAgent.match(/version\/(\d+)/i);
|
|
624
|
+
if (version !== null) {
|
|
625
|
+
data.splice(1, 1, version[1]);
|
|
626
|
+
}
|
|
627
|
+
return {
|
|
628
|
+
name: data[0],
|
|
629
|
+
version: data[1],
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Whether first parameter is a deep subset of second parameter
|
|
634
|
+
* Hint: functions will be ignored
|
|
635
|
+
*/
|
|
636
|
+
static isSubset(a, b) {
|
|
637
|
+
// Equal
|
|
638
|
+
if (a === b) {
|
|
639
|
+
return true;
|
|
640
|
+
}
|
|
641
|
+
// Different type
|
|
642
|
+
if (typeof a !== typeof b) {
|
|
643
|
+
return false;
|
|
644
|
+
}
|
|
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 }, options);
|
|
726
|
+
return new Promise((resolve) => {
|
|
727
|
+
var _a;
|
|
728
|
+
// Convert element(s) into array
|
|
729
|
+
if (!Array.isArray(config.elements)) {
|
|
730
|
+
// NodeList or HTMLCollection
|
|
731
|
+
if (Helper.isNodeList(config.elements)) {
|
|
732
|
+
config.elements = Array.from(config.elements);
|
|
733
|
+
}
|
|
734
|
+
// Single element
|
|
735
|
+
else {
|
|
736
|
+
config.elements = [config.elements];
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
// Init loading
|
|
740
|
+
const promises = [];
|
|
741
|
+
// Get all images
|
|
742
|
+
let images = [];
|
|
743
|
+
config.elements.forEach((element) => {
|
|
744
|
+
images = images.concat(Array.from(element.getElementsByTagName('img')));
|
|
745
|
+
});
|
|
746
|
+
// Prepare images
|
|
747
|
+
for (let image of images) {
|
|
748
|
+
const src = image.getAttribute('src');
|
|
749
|
+
// Check if changes are necessary and possible
|
|
750
|
+
if ((image.complete && image.naturalHeight !== 0) || // already laoded
|
|
751
|
+
!src || // Image has no src
|
|
752
|
+
((_a = config.regExp) === null || _a === void 0 ? void 0 : _a.test(src)) // Test if src matches regular expression
|
|
753
|
+
) {
|
|
754
|
+
continue;
|
|
755
|
+
}
|
|
756
|
+
// Replace lazy loading image with immediately loading image
|
|
757
|
+
if (image.getAttribute('loading') === 'lazy') {
|
|
758
|
+
const newImage = document.createElement('img');
|
|
759
|
+
Array.from(image.attributes).forEach((attr) => {
|
|
760
|
+
if (attr.name !== 'loading' && attr.name !== 'src') {
|
|
761
|
+
newImage.setAttribute(attr.name, attr.value);
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
image.replaceWith(newImage);
|
|
765
|
+
image = newImage;
|
|
766
|
+
}
|
|
767
|
+
// Wait for laoding
|
|
768
|
+
promises.push(this.loadImage(image, src));
|
|
769
|
+
}
|
|
770
|
+
// Wait until all images loaded
|
|
771
|
+
Promise.all(promises)
|
|
772
|
+
.catch((e) => console.error('Error during image loading', e))
|
|
773
|
+
.finally(() => __awaiter(this, void 0, void 0, function* () {
|
|
774
|
+
// Return result
|
|
775
|
+
let result;
|
|
776
|
+
if (config.doneFunnction) {
|
|
777
|
+
result = yield config.doneFunction();
|
|
778
|
+
}
|
|
779
|
+
resolve(result);
|
|
780
|
+
}));
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* Load image for image element
|
|
785
|
+
*
|
|
786
|
+
* @param imageElement
|
|
787
|
+
* @param src
|
|
788
|
+
* @protected
|
|
789
|
+
*/
|
|
790
|
+
loadImage(imageElement, src) {
|
|
791
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
792
|
+
src = src || imageElement.src;
|
|
793
|
+
return new Promise((resolve, reject) => {
|
|
794
|
+
imageElement.onload = () => resolve(imageElement);
|
|
795
|
+
imageElement.onerror = reject;
|
|
796
|
+
imageElement.src = src;
|
|
797
|
+
});
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
ImageService.ɵprov = i0.ɵɵdefineInjectable({ factory: function ImageService_Factory() { return new ImageService(); }, token: ImageService, providedIn: "root" });
|
|
802
|
+
ImageService.decorators = [
|
|
803
|
+
{ type: Injectable, args: [{
|
|
804
|
+
providedIn: 'root',
|
|
805
|
+
},] }
|
|
806
|
+
];
|
|
807
|
+
|
|
808
|
+
/**
|
|
809
|
+
* Set same height (maximum) to different elements
|
|
810
|
+
*/
|
|
811
|
+
class MatchHeightDirective {
|
|
812
|
+
constructor(el, imageService, platformId) {
|
|
813
|
+
this.el = el;
|
|
814
|
+
this.imageService = imageService;
|
|
815
|
+
// Replace lazy loading images with immediate loading images
|
|
816
|
+
this.loadImages = true;
|
|
817
|
+
this.isBrowser = isPlatformBrowser(platformId);
|
|
818
|
+
}
|
|
819
|
+
onResize() {
|
|
820
|
+
this.matchHeight(this.el.nativeElement, this.ltMatchHeight);
|
|
821
|
+
}
|
|
822
|
+
ngOnInit() {
|
|
823
|
+
this.matchHeight(this.el.nativeElement, this.ltMatchHeight);
|
|
824
|
+
}
|
|
825
|
+
matchHeight(parent, target) {
|
|
826
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
827
|
+
if (!parent) {
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
let classNames;
|
|
831
|
+
if (!Array.isArray(target)) {
|
|
832
|
+
classNames = [target];
|
|
833
|
+
}
|
|
834
|
+
else {
|
|
835
|
+
classNames = target;
|
|
836
|
+
}
|
|
837
|
+
for (const className of classNames) {
|
|
838
|
+
// find all child structureElements with the selected class name
|
|
839
|
+
const children = parent.getElementsByClassName(className);
|
|
840
|
+
if (!children || children.length < 2) {
|
|
841
|
+
continue;
|
|
842
|
+
}
|
|
843
|
+
// Load images of children
|
|
844
|
+
if (this.loadImages) {
|
|
845
|
+
yield this.imageService.preLoadImages({ elements: children });
|
|
846
|
+
}
|
|
847
|
+
// reset all children height
|
|
848
|
+
Array.from(children).forEach((element) => {
|
|
849
|
+
element.style.height = 'initial';
|
|
850
|
+
});
|
|
851
|
+
// get all the child structureElements heights
|
|
852
|
+
const itemHeights = Array.from(children).map((element) => {
|
|
853
|
+
if (element.getBoundingClientRect) {
|
|
854
|
+
return element.getBoundingClientRect().height;
|
|
855
|
+
}
|
|
856
|
+
return 0;
|
|
857
|
+
});
|
|
858
|
+
// find out the tallest one
|
|
859
|
+
const maxHeight = itemHeights.reduce((prev, curr) => (curr > prev ? curr : prev), 0);
|
|
860
|
+
// update the child structureElements height to the tallest one
|
|
861
|
+
Array.from(children).forEach((element) => (element.style.height = `${maxHeight}px`));
|
|
862
|
+
}
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
MatchHeightDirective.decorators = [
|
|
867
|
+
{ type: Directive, args: [{
|
|
868
|
+
selector: '[ltMatchHeight]',
|
|
869
|
+
},] }
|
|
870
|
+
];
|
|
871
|
+
MatchHeightDirective.ctorParameters = () => [
|
|
872
|
+
{ type: ElementRef },
|
|
873
|
+
{ type: ImageService },
|
|
874
|
+
{ type: String, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }
|
|
875
|
+
];
|
|
876
|
+
MatchHeightDirective.propDecorators = {
|
|
877
|
+
ltMatchHeight: [{ type: Input }],
|
|
878
|
+
loadImages: [{ type: Input }],
|
|
879
|
+
onResize: [{ type: HostListener, args: ['window:resize',] }]
|
|
880
|
+
};
|
|
881
|
+
|
|
882
|
+
/**
|
|
883
|
+
* Reszise detection
|
|
884
|
+
* (inpsired by: https://stackblitz.com/edit/angular-resizable)
|
|
885
|
+
*/
|
|
886
|
+
class ResizableDirective {
|
|
887
|
+
constructor(el) {
|
|
888
|
+
this.el = el;
|
|
889
|
+
this.resizableGrabWidth = 8;
|
|
890
|
+
this.resizableMinWidth = 10;
|
|
891
|
+
this.dragging = false;
|
|
892
|
+
}
|
|
893
|
+
ngOnInit() {
|
|
894
|
+
this.addListenerToDocument();
|
|
895
|
+
this.addListenerToElement();
|
|
896
|
+
}
|
|
897
|
+
mouseMoveG(evt) {
|
|
898
|
+
if (!this.dragging) {
|
|
899
|
+
return;
|
|
975
900
|
}
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
901
|
+
this.newWidth(evt.clientX - this.el.nativeElement.offsetLeft);
|
|
902
|
+
evt.stopPropagation();
|
|
903
|
+
}
|
|
904
|
+
newWidth(wid) {
|
|
905
|
+
const result = Math.max(this.resizableMinWidth, wid);
|
|
906
|
+
this.el.nativeElement.style.width = result + 'px';
|
|
907
|
+
}
|
|
908
|
+
mouseDown(evt) {
|
|
909
|
+
if (this.inDragRegion(evt)) {
|
|
910
|
+
this.dragging = true;
|
|
911
|
+
this.preventGlobalMouseEvents();
|
|
912
|
+
evt.stopPropagation();
|
|
980
913
|
}
|
|
981
|
-
return {
|
|
982
|
-
name: data[0],
|
|
983
|
-
version: data[1],
|
|
984
|
-
};
|
|
985
914
|
}
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
if (a === b) {
|
|
993
|
-
return true;
|
|
915
|
+
restoreGlobalMouseEvents() {
|
|
916
|
+
document.body.style['pointer-events'] = 'auto';
|
|
917
|
+
}
|
|
918
|
+
mouseUpG(evt) {
|
|
919
|
+
if (!this.dragging) {
|
|
920
|
+
return;
|
|
994
921
|
}
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
922
|
+
this.restoreGlobalMouseEvents();
|
|
923
|
+
this.dragging = false;
|
|
924
|
+
evt.stopPropagation();
|
|
925
|
+
}
|
|
926
|
+
mouseMove(evt) {
|
|
927
|
+
if (this.inDragRegion(evt) || this.dragging) {
|
|
928
|
+
this.el.nativeElement.style.cursor = 'col-resize';
|
|
998
929
|
}
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
for (const [key, value] of Object.entries(a)) {
|
|
1002
|
-
if (Helper.isSubset(value, b[key])) {
|
|
1003
|
-
return false;
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
return true;
|
|
930
|
+
else {
|
|
931
|
+
this.el.nativeElement.style.cursor = 'default';
|
|
1007
932
|
}
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
933
|
+
}
|
|
934
|
+
preventGlobalMouseEvents() {
|
|
935
|
+
document.body.style['pointer-events'] = 'none';
|
|
936
|
+
}
|
|
937
|
+
inDragRegion(evt) {
|
|
938
|
+
return this.el.nativeElement.clientWidth - evt.clientX + this.el.nativeElement.offsetLeft < this.resizableGrabWidth;
|
|
939
|
+
}
|
|
940
|
+
addListenerToDocument() {
|
|
941
|
+
document.addEventListener('mousemove', (e) => {
|
|
942
|
+
this.mouseMoveG(e);
|
|
943
|
+
}, true);
|
|
944
|
+
document.addEventListener('mouseup', (e) => {
|
|
945
|
+
this.mouseUpG(e);
|
|
946
|
+
}, true);
|
|
947
|
+
}
|
|
948
|
+
addListenerToElement() {
|
|
949
|
+
this.el.nativeElement.addEventListener('mousedown', (e) => {
|
|
950
|
+
this.mouseDown(e);
|
|
951
|
+
}, true);
|
|
952
|
+
this.el.nativeElement.addEventListener('mousemove', (e) => {
|
|
953
|
+
this.mouseMove(e);
|
|
954
|
+
}, true);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
ResizableDirective.decorators = [
|
|
958
|
+
{ type: Directive, args: [{
|
|
959
|
+
selector: '[ltResizable]',
|
|
960
|
+
},] }
|
|
961
|
+
];
|
|
962
|
+
ResizableDirective.ctorParameters = () => [
|
|
963
|
+
{ type: ElementRef }
|
|
964
|
+
];
|
|
965
|
+
ResizableDirective.propDecorators = {
|
|
966
|
+
resizableGrabWidth: [{ type: Input }],
|
|
967
|
+
resizableMinWidth: [{ type: Input }]
|
|
968
|
+
};
|
|
969
|
+
|
|
970
|
+
/**
|
|
971
|
+
* Truncate string with ellipses
|
|
972
|
+
*/
|
|
973
|
+
class EllipsesPipe {
|
|
974
|
+
transform(value, limit) {
|
|
975
|
+
if (!value) {
|
|
976
|
+
return null;
|
|
1017
977
|
}
|
|
1018
|
-
|
|
1019
|
-
return true;
|
|
978
|
+
return value.length > limit ? value.substring(0, limit) + '...' : value;
|
|
1020
979
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
980
|
+
}
|
|
981
|
+
EllipsesPipe.decorators = [
|
|
982
|
+
{ type: Pipe, args: [{
|
|
983
|
+
name: 'ltEllipses',
|
|
984
|
+
},] }
|
|
985
|
+
];
|
|
986
|
+
|
|
987
|
+
/**
|
|
988
|
+
* Declarate html as safe
|
|
989
|
+
*/
|
|
990
|
+
class SafeHtmlPipe {
|
|
991
|
+
constructor(sanitized) {
|
|
992
|
+
this.sanitized = sanitized;
|
|
993
|
+
}
|
|
994
|
+
transform(value) {
|
|
995
|
+
return this.sanitized.bypassSecurityTrustHtml(value);
|
|
1027
996
|
}
|
|
997
|
+
}
|
|
998
|
+
SafeHtmlPipe.decorators = [
|
|
999
|
+
{ type: Pipe, args: [{ name: 'ltSafeHtml' },] }
|
|
1000
|
+
];
|
|
1001
|
+
SafeHtmlPipe.ctorParameters = () => [
|
|
1002
|
+
{ type: DomSanitizer }
|
|
1003
|
+
];
|
|
1004
|
+
|
|
1005
|
+
// Imported and exported elements
|
|
1006
|
+
const elements = [
|
|
1007
|
+
// Directives
|
|
1008
|
+
ContextMenuDirective,
|
|
1009
|
+
LazyLoadDirective,
|
|
1010
|
+
MatchHeightDirective,
|
|
1011
|
+
ResizableDirective,
|
|
1012
|
+
// Pipes
|
|
1013
|
+
EllipsesPipe,
|
|
1014
|
+
SafeHtmlPipe,
|
|
1015
|
+
];
|
|
1016
|
+
/**
|
|
1017
|
+
* Base module
|
|
1018
|
+
*/
|
|
1019
|
+
class BaseModule {
|
|
1028
1020
|
/**
|
|
1029
|
-
*
|
|
1030
|
-
* Hint: functions will be ignored and when an array or an object is different the hole array or object will used as property value
|
|
1031
|
-
*
|
|
1032
|
-
* @returns Record<string, any> Object with properties from first object
|
|
1021
|
+
* Set configuration of base module in root module of the app
|
|
1033
1022
|
*/
|
|
1034
|
-
static
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1023
|
+
static forRoot(baseModuleConfig = {}) {
|
|
1024
|
+
// Default config
|
|
1025
|
+
const config = Object.assign({ apiUrl: 'localhost:3000', authGuardRedirectUrl: '/auth', logging: false, version: null, prefix: null, scrollDetectionOffset: 200, scrollOffset: 100, storageType: 'local' }, baseModuleConfig);
|
|
1026
|
+
// Prepare providers
|
|
1027
|
+
const providers = [
|
|
1028
|
+
{
|
|
1029
|
+
provide: BASE_MODULE_CONFIG,
|
|
1030
|
+
useValue: baseModuleConfig,
|
|
1031
|
+
},
|
|
1032
|
+
];
|
|
1033
|
+
// Add apollo features if API URL is set
|
|
1034
|
+
if (baseModuleConfig.apiUrl) {
|
|
1035
|
+
providers.push({
|
|
1036
|
+
provide: APOLLO_OPTIONS,
|
|
1037
|
+
useFactory: apolloOptionsFactory,
|
|
1038
|
+
deps: [BASE_MODULE_CONFIG, HttpLink, AuthService],
|
|
1039
|
+
});
|
|
1039
1040
|
}
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
result[key] = value;
|
|
1043
|
-
}
|
|
1041
|
+
else if (config.logging) {
|
|
1042
|
+
console.log('apiUrl is missing, ApolloLink is not initialized');
|
|
1044
1043
|
}
|
|
1045
|
-
|
|
1044
|
+
// Return root module
|
|
1045
|
+
return {
|
|
1046
|
+
ngModule: BaseModule,
|
|
1047
|
+
providers,
|
|
1048
|
+
};
|
|
1046
1049
|
}
|
|
1047
1050
|
}
|
|
1051
|
+
BaseModule.decorators = [
|
|
1052
|
+
{ type: NgModule, args: [{
|
|
1053
|
+
declarations: elements,
|
|
1054
|
+
exports: elements,
|
|
1055
|
+
},] }
|
|
1056
|
+
];
|
|
1048
1057
|
|
|
1049
1058
|
/**
|
|
1050
1059
|
* Standard class
|
|
@@ -2230,37 +2239,16 @@ class ScrollService {
|
|
|
2230
2239
|
* Scroll done promise
|
|
2231
2240
|
*/
|
|
2232
2241
|
scrollDone(options = {}) {
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
2237
|
-
// Init variables
|
|
2238
|
-
let rejected = false;
|
|
2239
|
-
let timeoutId;
|
|
2240
|
-
// Set timeout handling if necessary
|
|
2241
|
-
if (config.timeout) {
|
|
2242
|
-
timeoutId = window.setTimeout(() => {
|
|
2243
|
-
rejected = true;
|
|
2244
|
-
reject(new Error('Timeout for scrollDone after:' + config.timeout));
|
|
2245
|
-
}, config.timeout);
|
|
2246
|
-
}
|
|
2242
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2243
|
+
// Init configuration
|
|
2244
|
+
const config = Object.assign({ doneFunction: undefined }, options);
|
|
2247
2245
|
// Wait for scroll done
|
|
2248
2246
|
yield this.scrollDoneDetection();
|
|
2249
|
-
//
|
|
2250
|
-
if (
|
|
2251
|
-
|
|
2252
|
-
if (timeoutId) {
|
|
2253
|
-
window.clearTimeout(timeoutId);
|
|
2254
|
-
}
|
|
2255
|
-
// Get result (if doneFunction is set)
|
|
2256
|
-
let result;
|
|
2257
|
-
if (config.doneFunction) {
|
|
2258
|
-
result = yield config.doneFunction();
|
|
2259
|
-
}
|
|
2260
|
-
// Scroll done
|
|
2261
|
-
resolve(result);
|
|
2247
|
+
// Get result
|
|
2248
|
+
if (config.doneFunction) {
|
|
2249
|
+
return config.doneFunction();
|
|
2262
2250
|
}
|
|
2263
|
-
})
|
|
2251
|
+
});
|
|
2264
2252
|
}
|
|
2265
2253
|
/**
|
|
2266
2254
|
* Scroll done detecton
|
|
@@ -2310,23 +2298,79 @@ class SEOService {
|
|
|
2310
2298
|
this.titleService = titleService;
|
|
2311
2299
|
this.metaTagService = metaTagService;
|
|
2312
2300
|
}
|
|
2313
|
-
initPageForSEO(
|
|
2314
|
-
this.
|
|
2315
|
-
this.
|
|
2316
|
-
|
|
2317
|
-
|
|
2301
|
+
initPageForSEO(input) {
|
|
2302
|
+
this.setGeneralData(input);
|
|
2303
|
+
this.setTwitterData(input);
|
|
2304
|
+
this.setTwitterData(input);
|
|
2305
|
+
this.setFacebookData(input);
|
|
2306
|
+
if (input.keywords) {
|
|
2307
|
+
this.setPageKeywords(input.keywords);
|
|
2318
2308
|
}
|
|
2319
2309
|
}
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2310
|
+
/**
|
|
2311
|
+
* Set general metadata
|
|
2312
|
+
*
|
|
2313
|
+
* @param data
|
|
2314
|
+
* @private
|
|
2315
|
+
*/
|
|
2316
|
+
setGeneralData(data) {
|
|
2317
|
+
this.titleService.setTitle(data.title);
|
|
2318
|
+
this.metaTagService.updateTag({ name: 'description', content: data.description });
|
|
2319
|
+
}
|
|
2320
|
+
/**
|
|
2321
|
+
* Set metadata for twitter
|
|
2322
|
+
*
|
|
2323
|
+
* @param data
|
|
2324
|
+
* @private
|
|
2325
|
+
*/
|
|
2326
|
+
setTwitterData(data) {
|
|
2327
|
+
this.metaTagService.updateTag({ name: 'twitter:title', content: data.title });
|
|
2328
|
+
this.metaTagService.updateTag({ name: 'twitter:description', content: data.description });
|
|
2329
|
+
this.metaTagService.updateTag({
|
|
2330
|
+
property: 'twitter:url',
|
|
2331
|
+
content: data.url ? data.url : window.location.href,
|
|
2332
|
+
});
|
|
2333
|
+
if (data.image) {
|
|
2334
|
+
this.metaTagService.updateTag({
|
|
2335
|
+
property: 'twitter:image',
|
|
2336
|
+
content: data.image,
|
|
2337
|
+
});
|
|
2338
|
+
this.metaTagService.updateTag({
|
|
2339
|
+
property: 'twitter:card',
|
|
2340
|
+
content: 'summary_large_image',
|
|
2341
|
+
});
|
|
2342
|
+
}
|
|
2324
2343
|
}
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2344
|
+
/**
|
|
2345
|
+
* Set metadata for facebook
|
|
2346
|
+
*
|
|
2347
|
+
* @param data
|
|
2348
|
+
* @private
|
|
2349
|
+
*/
|
|
2350
|
+
setFacebookData(data) {
|
|
2351
|
+
this.metaTagService.updateTag({ property: 'og:title', content: data.title });
|
|
2352
|
+
this.metaTagService.updateTag({ property: 'og:description', content: data.description });
|
|
2353
|
+
this.metaTagService.updateTag({
|
|
2354
|
+
property: 'og:type',
|
|
2355
|
+
content: 'website',
|
|
2356
|
+
});
|
|
2357
|
+
this.metaTagService.updateTag({
|
|
2358
|
+
property: 'og:url',
|
|
2359
|
+
content: data.url ? data.url : window.location.href,
|
|
2360
|
+
});
|
|
2361
|
+
if (data.image) {
|
|
2362
|
+
this.metaTagService.updateTag({
|
|
2363
|
+
property: 'og:image',
|
|
2364
|
+
content: data.image,
|
|
2365
|
+
});
|
|
2366
|
+
}
|
|
2329
2367
|
}
|
|
2368
|
+
/**
|
|
2369
|
+
* Set page keywords
|
|
2370
|
+
*
|
|
2371
|
+
* @param keywords
|
|
2372
|
+
* @private
|
|
2373
|
+
*/
|
|
2330
2374
|
setPageKeywords(keywords) {
|
|
2331
2375
|
this.metaTagService.updateTag({ name: 'keywords', content: keywords });
|
|
2332
2376
|
}
|