@lenne.tech/ng-base 0.2.2 → 0.3.3

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 (32) hide show
  1. package/bundles/lenne.tech-ng-base-src-lib-base.umd.js +308 -159
  2. package/bundles/lenne.tech-ng-base-src-lib-base.umd.js.map +1 -1
  3. package/bundles/lenne.tech-ng-base.umd.js +308 -159
  4. package/bundles/lenne.tech-ng-base.umd.js.map +1 -1
  5. package/esm2015/lib/base/directives/match-height.directive.js +45 -29
  6. package/esm2015/lib/base/factories/apollo-options.factory.js +3 -2
  7. package/esm2015/lib/base/public-api.js +2 -1
  8. package/esm2015/lib/base/services/image.service.js +113 -0
  9. package/esm2015/lib/base/services/scroll.service.js +9 -84
  10. package/esm2015/lib/base/services/seo.service.js +70 -14
  11. package/esm2015/src/lib/base/directives/match-height.directive.js +45 -29
  12. package/esm2015/src/lib/base/factories/apollo-options.factory.js +3 -2
  13. package/esm2015/src/lib/base/public-api.js +2 -1
  14. package/esm2015/src/lib/base/services/image.service.js +113 -0
  15. package/esm2015/src/lib/base/services/scroll.service.js +9 -84
  16. package/esm2015/src/lib/base/services/seo.service.js +70 -14
  17. package/fesm2015/lenne.tech-ng-base-src-lib-base.js +231 -127
  18. package/fesm2015/lenne.tech-ng-base-src-lib-base.js.map +1 -1
  19. package/fesm2015/lenne.tech-ng-base.js +231 -127
  20. package/fesm2015/lenne.tech-ng-base.js.map +1 -1
  21. package/lib/base/directives/match-height.directive.d.ts +7 -3
  22. package/lib/base/public-api.d.ts +1 -0
  23. package/lib/base/services/image.service.d.ts +25 -0
  24. package/lib/base/services/scroll.service.d.ts +5 -21
  25. package/lib/base/services/seo.service.d.ts +36 -3
  26. package/package.json +12 -11
  27. package/src/lib/base/directives/match-height.directive.d.ts +7 -3
  28. package/src/lib/base/lenne.tech-ng-base-src-lib-base.metadata.json +1 -1
  29. package/src/lib/base/public-api.d.ts +1 -0
  30. package/src/lib/base/services/image.service.d.ts +25 -0
  31. package/src/lib/base/services/scroll.service.d.ts +5 -21
  32. package/src/lib/base/services/seo.service.d.ts +36 -3
@@ -2,19 +2,19 @@ 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, NgZone, 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';
11
12
  import * as i1$2 from '@angular/platform-browser';
12
13
  import { DomSanitizer, Title, Meta } from '@angular/platform-browser';
13
14
  import * as i1$1 from '@angular/router';
14
15
  import { Router } from '@angular/router';
15
16
  import { buildClientSchema, getIntrospectionQuery } from 'graphql';
16
17
  import { map } from 'rxjs/operators';
17
- import { __awaiter } from 'tslib';
18
18
 
19
19
  const BASE_MODULE_CONFIG = new InjectionToken('BASE_MODULE_CONFIG');
20
20
 
@@ -212,8 +212,9 @@ AuthService.ctorParameters = () => [
212
212
  */
213
213
  function apolloOptionsFactory(baseModuleConfig, httpLink, authService) {
214
214
  const links = [];
215
+ const defaultUrl = 'api.' + window.location.href + '/graphql';
215
216
  const http = httpLink.create({
216
- uri: baseModuleConfig.apiUrl,
217
+ uri: baseModuleConfig.apiUrl ? baseModuleConfig.apiUrl : 'https://' + defaultUrl,
217
218
  });
218
219
  const authMiddleware = new ApolloLink((operation, forward) => {
219
220
  const headers = {};
@@ -418,12 +419,125 @@ LazyLoadDirective.propDecorators = {
418
419
  src: [{ type: Input }]
419
420
  };
420
421
 
422
+ /**
423
+ * Image service
424
+ */
425
+ class ImageService {
426
+ /**
427
+ * Preaload images (for lazy handling)
428
+ *
429
+ * @param options
430
+ * @protected
431
+ */
432
+ preLoadImages(options) {
433
+ // Init configuration
434
+ const config = Object.assign({ doneFunnction: undefined, elements: document, regExp: undefined, timeout: undefined }, options);
435
+ return new Promise((resolve) => {
436
+ var _a;
437
+ // Init variables
438
+ let resolved = false;
439
+ let timeoutId;
440
+ // HTMLCollection to array
441
+ if (config.elements instanceof HTMLCollection) {
442
+ config.elements = Array.from(config.elements);
443
+ }
444
+ // Single element to array
445
+ if (!Array.isArray(config.elements)) {
446
+ config.elements = [config.elements];
447
+ }
448
+ // Init loading
449
+ const promises = [];
450
+ // Get all images
451
+ let images = [];
452
+ config.elements.forEach((element) => {
453
+ images = images.concat(Array.from(element.getElementsByTagName('img')));
454
+ });
455
+ // Prepare images
456
+ for (const image of images) {
457
+ const src = image.getAttribute('src');
458
+ // Check if changes are necessary and possible
459
+ if ((image.complete && image.naturalHeight !== 0) || // already laoded
460
+ image.getAttribute('loading') !== 'lazy' || // loading attribute !== lazy
461
+ !src || // Image has no src
462
+ ((_a = config.regExp) === null || _a === void 0 ? void 0 : _a.test(src)) // Test if src matches regular expression
463
+ ) {
464
+ continue;
465
+ }
466
+ // Replace lazy loading image with immediately loading image
467
+ const newImage = document.createElement('img');
468
+ Array.from(image.attributes).forEach((attr) => {
469
+ if (attr.name !== 'loading' && attr.name !== 'src') {
470
+ newImage.setAttribute(attr.name, attr.value);
471
+ }
472
+ });
473
+ image.replaceWith(newImage);
474
+ // Wait for laoding
475
+ promises.push(this.loadImage(newImage, src));
476
+ }
477
+ if (config.timeout) {
478
+ timeoutId = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
479
+ resolved = true;
480
+ if (config.doneFunnction) {
481
+ yield config.doneFunction();
482
+ }
483
+ resolve(undefined);
484
+ }));
485
+ }
486
+ // Wait until all images loaded
487
+ Promise.all(promises)
488
+ .catch((e) => console.error('Error during image loading', e))
489
+ .finally(() => __awaiter(this, void 0, void 0, function* () {
490
+ // Check if already resolved
491
+ if (resolved) {
492
+ return;
493
+ }
494
+ // Stop timeout
495
+ if (timeoutId) {
496
+ clearTimeout(timeoutId);
497
+ }
498
+ // Return result
499
+ let result;
500
+ if (config.doneFunnction) {
501
+ result = yield config.doneFunction();
502
+ }
503
+ resolve(result);
504
+ }));
505
+ });
506
+ }
507
+ /**
508
+ * Load image for image element
509
+ *
510
+ * @param imageElement
511
+ * @param src
512
+ * @protected
513
+ */
514
+ loadImage(imageElement, src) {
515
+ return __awaiter(this, void 0, void 0, function* () {
516
+ src = src || imageElement.src;
517
+ return new Promise((resolve, reject) => {
518
+ imageElement.onload = () => resolve(imageElement);
519
+ imageElement.onerror = reject;
520
+ imageElement.src = src;
521
+ });
522
+ });
523
+ }
524
+ }
525
+ ImageService.ɵprov = i0.ɵɵdefineInjectable({ factory: function ImageService_Factory() { return new ImageService(); }, token: ImageService, providedIn: "root" });
526
+ ImageService.decorators = [
527
+ { type: Injectable, args: [{
528
+ providedIn: 'root',
529
+ },] }
530
+ ];
531
+
421
532
  /**
422
533
  * Set same height (maximum) to different elements
423
534
  */
424
535
  class MatchHeightDirective {
425
- constructor(el) {
536
+ constructor(el, imageService, zone) {
426
537
  this.el = el;
538
+ this.imageService = imageService;
539
+ this.zone = zone;
540
+ this.loadLazyImages = true;
427
541
  }
428
542
  onResize() {
429
543
  this.matchHeight(this.el.nativeElement, this.ltMatchHeight);
@@ -432,33 +546,41 @@ class MatchHeightDirective {
432
546
  this.matchHeight(this.el.nativeElement, this.ltMatchHeight);
433
547
  }
434
548
  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) {
549
+ // Timeout is set to force Angular to wait for all actions and only continue once the process has run through.
550
+ // Otherwise, an infinite loop will occur.
551
+ setTimeout(() => __awaiter(this, void 0, void 0, function* () {
552
+ if (!parent) {
449
553
  return;
450
554
  }
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
- });
555
+ let classNames;
556
+ if (!Array.isArray(target)) {
557
+ classNames = [target];
558
+ }
559
+ else {
560
+ classNames = target;
561
+ }
562
+ for (const className of classNames) {
563
+ // find all child structureElements with the selected class name
564
+ const children = parent.getElementsByClassName(className);
565
+ if (!children || children.length < 2) {
566
+ continue;
567
+ }
568
+ // Load images of children
569
+ if (this.loadLazyImages) {
570
+ yield this.imageService.preLoadImages({ elements: children });
571
+ }
572
+ // reset all children height
573
+ Array.from(children).forEach((element) => {
574
+ element.style.height = 'initial';
575
+ });
576
+ // get all the child structureElements heights
577
+ const itemHeights = Array.from(children).map((x) => x.getBoundingClientRect().height);
578
+ // find out the tallest one
579
+ const maxHeight = itemHeights.reduce((prev, curr) => (curr > prev ? curr : prev), 0);
580
+ // update the child structureElements height to the tallest one
581
+ Array.from(children).forEach((element) => (element.style.height = `${maxHeight}px`));
582
+ }
583
+ }), 1);
462
584
  }
463
585
  }
464
586
  MatchHeightDirective.decorators = [
@@ -467,10 +589,13 @@ MatchHeightDirective.decorators = [
467
589
  },] }
468
590
  ];
469
591
  MatchHeightDirective.ctorParameters = () => [
470
- { type: ElementRef }
592
+ { type: ElementRef },
593
+ { type: ImageService },
594
+ { type: NgZone }
471
595
  ];
472
596
  MatchHeightDirective.propDecorators = {
473
597
  ltMatchHeight: [{ type: Input }],
598
+ loadLazyImages: [{ type: Input }],
474
599
  onResize: [{ type: HostListener, args: ['window:resize',] }]
475
600
  };
476
601
 
@@ -2001,9 +2126,10 @@ class ScrollService {
2001
2126
  /**
2002
2127
  * Initializer
2003
2128
  */
2004
- constructor(router, moduleConfig) {
2129
+ constructor(router, moduleConfig, imageService) {
2005
2130
  this.router = router;
2006
2131
  this.moduleConfig = moduleConfig;
2132
+ this.imageService = imageService;
2007
2133
  /**
2008
2134
  * Is a scroll listener set
2009
2135
  *
@@ -2053,7 +2179,7 @@ class ScrollService {
2053
2179
  }
2054
2180
  // Load images before scrolling (once)
2055
2181
  if (config.loadImagesBefore) {
2056
- yield this.preLoadImages();
2182
+ yield this.imageService.preLoadImages();
2057
2183
  }
2058
2184
  // Get get bounding rect of target element
2059
2185
  const cords = el.getBoundingClientRect();
@@ -2164,87 +2290,8 @@ class ScrollService {
2164
2290
  // Return promise
2165
2291
  return this.scrollPromise;
2166
2292
  }
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
2293
  }
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" });
2294
+ 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
2295
  ScrollService.decorators = [
2249
2296
  { type: Injectable, args: [{
2250
2297
  providedIn: 'root',
@@ -2252,7 +2299,8 @@ ScrollService.decorators = [
2252
2299
  ];
2253
2300
  ScrollService.ctorParameters = () => [
2254
2301
  { type: Router },
2255
- { type: undefined, decorators: [{ type: Inject, args: [BASE_MODULE_CONFIG,] }] }
2302
+ { type: undefined, decorators: [{ type: Inject, args: [BASE_MODULE_CONFIG,] }] },
2303
+ { type: ImageService }
2256
2304
  ];
2257
2305
 
2258
2306
  /**
@@ -2263,23 +2311,79 @@ class SEOService {
2263
2311
  this.titleService = titleService;
2264
2312
  this.metaTagService = metaTagService;
2265
2313
  }
2266
- initPageForSEO(title, description, keywords) {
2267
- this.setPageTitle(title);
2268
- this.setPageDescription(description);
2269
- if (keywords) {
2270
- this.setPageKeywords(keywords);
2314
+ initPageForSEO(input) {
2315
+ this.setGeneralData(input);
2316
+ this.setTwitterData(input);
2317
+ this.setTwitterData(input);
2318
+ this.setFacebookData(input);
2319
+ if (input.keywords) {
2320
+ this.setPageKeywords(input.keywords);
2271
2321
  }
2272
2322
  }
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 });
2323
+ /**
2324
+ * Set general metadata
2325
+ *
2326
+ * @param data
2327
+ * @private
2328
+ */
2329
+ setGeneralData(data) {
2330
+ this.titleService.setTitle(data.title);
2331
+ this.metaTagService.updateTag({ name: 'description', content: data.description });
2277
2332
  }
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 });
2333
+ /**
2334
+ * Set metadata for twitter
2335
+ *
2336
+ * @param data
2337
+ * @private
2338
+ */
2339
+ setTwitterData(data) {
2340
+ this.metaTagService.updateTag({ name: 'twitter:title', content: data.title });
2341
+ this.metaTagService.updateTag({ name: 'twitter:description', content: data.description });
2342
+ this.metaTagService.updateTag({
2343
+ property: 'twitter:url',
2344
+ content: data.url ? data.url : window.location.href,
2345
+ });
2346
+ if (data.image) {
2347
+ this.metaTagService.updateTag({
2348
+ property: 'twitter:image',
2349
+ content: data.image,
2350
+ });
2351
+ this.metaTagService.updateTag({
2352
+ property: 'twitter:card',
2353
+ content: 'summary_large_image',
2354
+ });
2355
+ }
2356
+ }
2357
+ /**
2358
+ * Set metadata for facebook
2359
+ *
2360
+ * @param data
2361
+ * @private
2362
+ */
2363
+ setFacebookData(data) {
2364
+ this.metaTagService.updateTag({ property: 'og:title', content: data.title });
2365
+ this.metaTagService.updateTag({ property: 'og:description', content: data.description });
2366
+ this.metaTagService.updateTag({
2367
+ property: 'og:type',
2368
+ content: 'website',
2369
+ });
2370
+ this.metaTagService.updateTag({
2371
+ property: 'og:url',
2372
+ content: data.url ? data.url : window.location.href,
2373
+ });
2374
+ if (data.image) {
2375
+ this.metaTagService.updateTag({
2376
+ property: 'og:image',
2377
+ content: data.image,
2378
+ });
2379
+ }
2282
2380
  }
2381
+ /**
2382
+ * Set page keywords
2383
+ *
2384
+ * @param keywords
2385
+ * @private
2386
+ */
2283
2387
  setPageKeywords(keywords) {
2284
2388
  this.metaTagService.updateTag({ name: 'keywords', content: keywords });
2285
2389
  }
@@ -2325,5 +2429,5 @@ function MustMatch(controlName, matchingControlName) {
2325
2429
  * Generated bundle index. Do not edit.
2326
2430
  */
2327
2431
 
2328
- 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 };
2432
+ 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 };
2329
2433
  //# sourceMappingURL=lenne.tech-ng-base-src-lib-base.js.map