@sumaris-net/ngx-components 18.14.15 → 18.14.16

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.
@@ -1,6 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { InjectionToken, Directive, Pipe, Injectable, EventEmitter, Output, Optional, Inject, inject, NgModule, forwardRef, booleanAttribute, Component, ChangeDetectionStrategy, Input, ViewChildren, HostBinding, HostListener, ElementRef, numberAttribute, ViewChild, ANIMATION_MODULE_TYPE, RendererStyleFlags2, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectorRef, Self, ViewEncapsulation, APP_INITIALIZER, SecurityContext, viewChild, signal, input, model, computed, effect, untracked } from '@angular/core';
3
- import { firstValueFrom, shareReplay, tap, of, timer, Subject, merge, delay, isObservable, from, Subscription, BehaviorSubject, fromEvent, noop as noop$9, Observable, forkJoin, timeout, defer, combineLatest, debounceTime as debounceTime$1, distinctUntilChanged as distinctUntilChanged$1, interval, mergeMap as mergeMap$1, EMPTY, switchMap as switchMap$1 } from 'rxjs';
3
+ import { firstValueFrom, shareReplay, tap, of, timer, Subject, merge, delay, isObservable, from, Subscription, BehaviorSubject, fromEvent, noop as noop$9, Observable, forkJoin, timeout, defer, combineLatest, debounceTime as debounceTime$1, distinctUntilChanged as distinctUntilChanged$1, interval, mergeMap as mergeMap$1, switchMap as switchMap$1, EMPTY } from 'rxjs';
4
4
  import { catchError, map, filter, takeUntil, first, switchMap, tap as tap$1, throttleTime, debounceTime, startWith, distinctUntilChanged, mergeMap, skip, finalize, bufferWhen, distinctUntilKeyChanged, take } from 'rxjs/operators';
5
5
  import * as cloneImported from 'clone';
6
6
  import * as i3$1 from '@angular/common';
@@ -155,8 +155,6 @@ import { Camera, CameraResultType } from '@capacitor/camera';
155
155
  import { Geolocation } from '@capacitor/geolocation';
156
156
  import * as i1$8 from '@e-is/ngx-material-table';
157
157
  import { ValidatorService, TableDataSource, AsyncTableDataSource } from '@e-is/ngx-material-table';
158
- import DiscourseAPI from 'discourse2';
159
- import { Promise as Promise$1 } from '@rx-angular/cdk/zone-less/browser';
160
158
  import 'moment-timezone';
161
159
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
162
160
 
@@ -12899,8 +12897,10 @@ const environment = Object.freeze({
12899
12897
  jsonFeed: {
12900
12898
  fr: [
12901
12899
  'https://gitlab.ifremer.fr/sih-public/sumaris/ngx-sumaris-components/-/raw/master/doc/feed/feed-fr.json',
12902
- //'https://raw.githubusercontent.com/duniter/cesium/master/doc/feed/1.1/feed-fr-FR.json',
12900
+ // Example with JsonFeed version 1 (and not 1.1)
12903
12901
  //'https://raw.githubusercontent.com/duniter/cesium/master/doc/feed/feed-fr.json',
12902
+ // Example with discourse API :
12903
+ //'https://raw.githubusercontent.com/duniter/cesium/master/doc/feed/1.1/feed-fr-FR.json',
12904
12904
  ],
12905
12905
  en: ['https://gitlab.ifremer.fr/sih-public/sumaris/ngx-sumaris-components/-/raw/master/doc/feed/feed-en.json'],
12906
12906
  },
@@ -33357,169 +33357,151 @@ class JsonFeedUtils {
33357
33357
  }
33358
33358
  }
33359
33359
 
33360
- class DiscourseUtils {
33361
- static _logPrefix = '[discourse-utils]';
33362
- static removeJsonExtension = JsonFeedUtils.removeJsonExtension;
33363
- static isDiscourseObject(json) {
33364
- return this.isDiscourseTopic(json) || this.isDiscourseCategory(json);
33365
- }
33366
- static isDiscourseTopic(json) {
33367
- return (json && !!json.post_stream?.posts && json.fancy_title && json.slug && json.details?.created_by && true) || false;
33360
+ const APP_FEED_SERVICE = new InjectionToken('FeeService');
33361
+ class FeedService extends StartableService {
33362
+ settings;
33363
+ environment;
33364
+ _logPrefix = '[feed-service] ';
33365
+ _state = new RxState();
33366
+ network = inject(NetworkService);
33367
+ locale$ = this._state.select('locale');
33368
+ feedUrls$ = this._state.select('feedUrls');
33369
+ get feedUrls() {
33370
+ return this._state.get('feedUrls');
33368
33371
  }
33369
- static isDiscourseCategory(json) {
33370
- return (json && json.topic_list?.topics && json.posters && true) || false;
33372
+ set feedUrls(urls) {
33373
+ this._state.set('feedUrls', () => urls);
33371
33374
  }
33372
- static getDiscourseBaseUrl(url) {
33373
- return UrlUtils.getRootUrl(url);
33375
+ constructor(settings, environment) {
33376
+ super(settings);
33377
+ this.settings = settings;
33378
+ this.environment = environment;
33379
+ this._state.connect('locale', this.settings.locale$);
33380
+ this._state.connect('feedUrls', this.locale$.pipe(filter(isNotNilOrBlank), map((locale) => (locale && environment.feed?.jsonFeed?.[locale]) ?? [])));
33381
+ // DEBUG
33382
+ this._debug = !environment.production;
33383
+ if (this._debug)
33384
+ console.debug(`${this._logPrefix}created`);
33374
33385
  }
33375
- static isDiscourseCategoryUrl(url) {
33376
- const baseUrl = this.getDiscourseBaseUrl(url);
33377
- return baseUrl && url.substring(baseUrl.length).match(/^\/c\//);
33386
+ async ngOnStart() {
33387
+ await this.settings.ready();
33388
+ return {
33389
+ locale: this.settings.locale,
33390
+ };
33378
33391
  }
33379
- static extractCategoryIdFromUrl(url) {
33380
- const match = this.removeJsonExtension(url).match(/\/(\d+)$/);
33381
- return match ? parseInt(match[1], 10) : null;
33392
+ watchAll(opts) {
33393
+ if (!this.started) {
33394
+ return from(this.start()).pipe(switchMap$1(() => this.watchAll(opts)));
33395
+ }
33396
+ if (isNotEmptyArray(opts?.urls)) {
33397
+ return this.locale$.pipe(mergeMap((locale) => this.loadAll(opts.urls, { locale, ...opts })));
33398
+ }
33399
+ return this.feedUrls$.pipe(filter(isNotEmptyArray), mergeMap((urls) => this.loadAll(urls, opts)));
33382
33400
  }
33383
- static extractCategorySlugFromUrl(url) {
33384
- const match = this.removeJsonExtension(url).match(/\/c\/([\w/-]+)\/\d+$/);
33385
- return match ? match[1] : null;
33401
+ getHomeUrl(feed) {
33402
+ const feedUrl = feed?.feed_url ?? firstArrayValue(this.feedUrls);
33403
+ return feedUrl ? UrlUtils.getRootUrl(feedUrl) : undefined;
33386
33404
  }
33387
- static extractTopicIdFromUrl(url) {
33388
- const match = url.match(/\/(\d+)(?:$|\/)/) || url.match(/\/(\d+)\.json$/);
33389
- return match ? parseInt(match[1], 10) : null;
33405
+ getTagUrl(feed, tag) {
33406
+ if (!feed || !tag)
33407
+ throw new Error("Missing 'feed' or 'tag' argument");
33408
+ const baseUrl = this.getHomeUrl(feed);
33409
+ return feed.tag_template?.replace('{tag}', tag) ?? baseUrl + '/tag/' + tag;
33390
33410
  }
33391
- static getLanguageFromTitle(title) {
33392
- if (!title)
33393
- return '';
33394
- const match = title.match('\\s\\(([a-z]{2}(?:-[A-Z]{2})?)\\)$');
33395
- return match && match[1];
33411
+ async load(url, opts) {
33412
+ const { data } = await this.loadAll([url], opts);
33413
+ return data?.[0];
33396
33414
  }
33397
- static async getFeedsByUrl(url, opts) {
33398
- try {
33399
- // Check a category
33400
- if (DiscourseUtils.isDiscourseCategoryUrl(url)) {
33401
- console.debug(`${this._logPrefix}Detected a Discourse category at: ${url}`);
33402
- return this.getFeedsByCategoryUrl(url, opts);
33415
+ async loadAll(urls, opts) {
33416
+ await this.ready();
33417
+ urls = urls ?? this.feedUrls;
33418
+ opts = {
33419
+ maxAgeInMonths: opts?.maxAgeInMonths ?? this.environment.feed?.maxAgeInMonths,
33420
+ maxContentLength: opts?.maxContentLength ?? this.environment.feed?.maxContentLength,
33421
+ locale: this.settings.locale,
33422
+ depth: 0,
33423
+ ...opts,
33424
+ };
33425
+ const feeds = await Promise.all((urls || []).map(async (url) => {
33426
+ try {
33427
+ // Get JSON
33428
+ const json = await this.network.fetch(url);
33429
+ console.debug(`${this._logPrefix}Loaded JSON from ${url}`, json);
33430
+ // Resolve feed
33431
+ return await this.resolveFeed(json, url, opts);
33403
33432
  }
33404
- // Or a topic
33405
- else {
33406
- const post = await this.getFeedByTopicUrl(url, opts);
33407
- return post ? [post] : [];
33433
+ catch (err) {
33434
+ if (err?.status === 404) {
33435
+ console.error(`${this._logPrefix} Error while fetching feeds at ${url}. 404 (Not found)`);
33436
+ }
33437
+ else {
33438
+ console.error(`${this._logPrefix} Error while fetching feeds at ${url}`, err);
33439
+ }
33440
+ return Promise.resolve([]);
33408
33441
  }
33442
+ }));
33443
+ const data = feeds.flat();
33444
+ // Close opened resources
33445
+ if (opts.depth === 0) {
33446
+ this.onAfterLoadAll();
33409
33447
  }
33410
- catch (err) {
33411
- console.error(`${this._logPrefix}`, err);
33412
- return [];
33413
- }
33448
+ return { data, total: data.length };
33414
33449
  }
33415
- static async getFeedsByCategoryUrl(url, opts) {
33416
- const categoryId = this.extractCategoryIdFromUrl(url);
33417
- const categorySlug = this.extractCategorySlugFromUrl(url);
33418
- const baseUrl = this.getDiscourseBaseUrl(url);
33419
- const api = opts?.api ?? new DiscourseAPI(baseUrl);
33420
- const category = await api.listCategoryTopics({ id: categoryId, slug: categorySlug });
33421
- const topics = (category?.topic_list?.topics || []).filter((topic) => {
33422
- const topicLocale = this.getLanguageFromTitle(topic.fancy_title);
33423
- return (topic.pinned &&
33424
- topic.visible &&
33425
- // Keep same locale, if exists
33426
- (!topicLocale || !opts?.locale || topicLocale === opts.locale));
33427
- });
33428
- const posts = (await Promise$1.all(topics.map(async (t) => {
33429
- const topic = await api.getTopic({ id: t.id.toString() });
33430
- // Ignore 'About' topics
33431
- if (topic.tags.includes('about-category'))
33432
- return undefined;
33433
- const posts = this.filterRecentPosts(topic.post_stream.posts, opts);
33434
- if (isEmptyArray(posts))
33435
- return undefined;
33436
- return this.toFeed(posts, topic, url, opts);
33437
- }))).filter(isNotNil);
33438
- if (isEmptyArray(posts)) {
33439
- console.warn(`${this._logPrefix}No recent post found on category #${categoryId}`);
33440
- }
33441
- return posts;
33450
+ async resolveFeed(json, url, opts) {
33451
+ // Check json is JsonFeed compatible
33452
+ if (JsonFeedUtils.isJsonFeed(json)) {
33453
+ // Migrate from old versions
33454
+ let feed = JsonFeedUtils.migrateFeed(json);
33455
+ // Resolve items (e.g. using feed.next_url)
33456
+ feed = await this.resolveFeedItems(feed, { ...opts, depth: opts?.depth ?? 0 });
33457
+ // Truncate html
33458
+ JsonFeedUtils.truncateFeedItemsHtml(feed, opts);
33459
+ return isNotEmptyArray(feed?.items) ? [feed] : [];
33460
+ }
33461
+ // not resolved (unknown format)
33462
+ return undefined;
33442
33463
  }
33443
- static async getFeedByTopicUrl(url, opts) {
33444
- const topicId = this.extractTopicIdFromUrl(url);
33445
- if (!topicId) {
33446
- console.error(`${this._logPrefix}Invalid URL`);
33447
- return undefined;
33448
- }
33449
- const api = opts?.api ?? new DiscourseAPI(this.getDiscourseBaseUrl(url));
33450
- const topic = await api.getTopic({ id: topicId.toString() });
33451
- // Ignore about category
33452
- if (topic.tags?.includes('about-category'))
33453
- return undefined;
33454
- const posts = this.filterRecentPosts(topic.post_stream.posts, opts);
33455
- if (isEmptyArray(posts)) {
33456
- console.warn(`${this._logPrefix}No recent posts found in topic #${topicId}`);
33457
- return undefined;
33464
+ async resolveFeedItems(json, opts) {
33465
+ if (!json)
33466
+ return json;
33467
+ // Load items
33468
+ if (isEmptyArray(json.items) && isNotNilOrBlank(json.next_url)) {
33469
+ const depth = opts?.depth ?? 0;
33470
+ if (depth >= 3) {
33471
+ console.warn(`${this._logPrefix}Max depth reached (${depth}) for ${json.feed_url}`);
33472
+ return json;
33473
+ }
33474
+ // Load items
33475
+ const feed = await this.load(json.next_url, { ...opts, depth: depth + 1 });
33476
+ if (isEmptyArray(feed?.items)) {
33477
+ return json;
33478
+ }
33479
+ // Merge with the input json
33480
+ return {
33481
+ ...json,
33482
+ title: json.title ?? feed.title,
33483
+ home_page_url: json.home_page_url ?? feed.home_page_url,
33484
+ authors: isNotEmptyArray(json.authors) ? json.authors : feed.authors,
33485
+ items: feed.items,
33486
+ tag_template: json.tag_template ?? feed.tag_template,
33487
+ };
33458
33488
  }
33459
- return this.toFeed(posts, topic, url, opts);
33460
- }
33461
- static filterRecentPosts(posts, opts) {
33462
- const maxAgeInMonths = opts?.maxAgeInMonths ?? JsonFeedUtils.DEFAULT_MAX_POST_AGE_IN_MONTHS;
33463
- if (maxAgeInMonths <= 0)
33464
- return posts; // Accept all
33465
- const minDate = maxAgeInMonths > 0 ? DateUtils.moment().subtract(maxAgeInMonths, 'month').startOf('day').utc() : undefined;
33466
- return (posts || []).filter((post) => post && DateUtils.moment(post.created_at).isSameOrAfter(minDate));
33467
- }
33468
- static toFeed(posts, topic, url, opts) {
33469
- const baseUrl = this.getDiscourseBaseUrl(url);
33470
- const title = this.cleanTitle(topic.fancy_title ?? topic.title);
33471
- const items = (posts || []).map((post) => this.toFeedItem(post, topic, url, opts));
33472
- const firstItem = items?.[0];
33473
- if (firstItem)
33474
- firstItem.title = title;
33475
- const authorName = topic?.details?.created_by && (topic.details.created_by.name || topic.details.created_by.username);
33476
- const authorAvatar = baseUrl + topic.details.created_by.avatar_template.replace('{size}', '48');
33477
- return {
33478
- version: JsonFeedUtils.VERSION_1_1,
33479
- feed_url: url,
33480
- title: this.cleanTitle(topic.fancy_title),
33481
- expired: topic.archived,
33482
- authors: [
33483
- {
33484
- name: authorName,
33485
- avatar: authorAvatar,
33486
- },
33487
- ],
33488
- items,
33489
- tag_template: baseUrl + '/tag/{tag}',
33490
- };
33491
- }
33492
- static toFeedItem(post, topic, url, opts) {
33493
- const baseUrl = this.getDiscourseBaseUrl(url);
33494
- url = post.post_url ? baseUrl + post.post_url : url;
33495
- const id = post.post_url ? baseUrl + post.post_url : post.id;
33496
- const html = JsonFeedUtils.truncateHtml(post.cooked, opts);
33497
- const truncated = html?.length !== post.cooked?.length;
33498
- const authorName = post.name || post.username;
33499
- const authorAvatar = baseUrl + (post.avatar_template.replace('{size}', '48') ?? topic.details.last_poster.avatar_template.replace('{size}', '48'));
33500
- return {
33501
- id,
33502
- url,
33503
- authors: [
33504
- {
33505
- name: authorName,
33506
- avatar: authorAvatar,
33507
- },
33508
- ],
33509
- content_html: html,
33510
- date_published: post.created_at,
33511
- tags: topic.tags,
33512
- truncated,
33513
- };
33489
+ return json;
33514
33490
  }
33515
- static cleanTitle(title) {
33516
- if (!title)
33517
- return undefined;
33518
- return title.replace(/\s\([a-z]{2}(:?-[A-Z]{2})?\)$/, '');
33491
+ onAfterLoadAll() {
33492
+ console.debug(`${this._logPrefix}Feeds loaded`);
33519
33493
  }
33494
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FeedService, deps: [{ token: LocalSettingsService }, { token: ENVIRONMENT, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
33495
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FeedService });
33520
33496
  }
33521
-
33522
- const APP_FEED_SERVICE = new InjectionToken('FeeService');
33497
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FeedService, decorators: [{
33498
+ type: Injectable
33499
+ }], ctorParameters: () => [{ type: LocalSettingsService }, { type: Environment, decorators: [{
33500
+ type: Optional
33501
+ }, {
33502
+ type: Inject,
33503
+ args: [ENVIRONMENT]
33504
+ }] }] });
33523
33505
 
33524
33506
  class FeedDirective {
33525
33507
  element;
@@ -33533,7 +33515,7 @@ class FeedDirective {
33533
33515
  _baseUrl;
33534
33516
  set feedUrl(value) {
33535
33517
  this._feedUrl = value;
33536
- this._baseUrl = value && DiscourseUtils.removeJsonExtension(value);
33518
+ this._baseUrl = value && JsonFeedUtils.removeJsonExtension(value);
33537
33519
  }
33538
33520
  get feedUrl() {
33539
33521
  return this._feedUrl;
@@ -33659,7 +33641,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
33659
33641
  }]
33660
33642
  }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { feedUrl: [{
33661
33643
  type: Input,
33662
- args: ['feed']
33644
+ args: [{ alias: 'feed', required: true }]
33663
33645
  }] } });
33664
33646
 
33665
33647
  class FeedsComponent {
@@ -33741,7 +33723,7 @@ class FeedsComponent {
33741
33723
  this.feeds?.forEach((f) => this.openFeedHome(f));
33742
33724
  return;
33743
33725
  }
33744
- const url = feed.home_page_url ?? DiscourseUtils.removeJsonExtension(feed.feed_url) ?? this.feedService.getHomeUrl();
33726
+ const url = feed.home_page_url ?? JsonFeedUtils.removeJsonExtension(feed.feed_url) ?? this.feedService.getHomeUrl();
33745
33727
  if (!url)
33746
33728
  return;
33747
33729
  return this.platform.open(url);
@@ -33749,7 +33731,7 @@ class FeedsComponent {
33749
33731
  openUrl(url) {
33750
33732
  if (!url)
33751
33733
  return;
33752
- const fixedUrl = DiscourseUtils.removeJsonExtension(url);
33734
+ const fixedUrl = JsonFeedUtils.removeJsonExtension(url);
33753
33735
  return this.platform.open(fixedUrl);
33754
33736
  }
33755
33737
  openTag(feed, tag) {
@@ -44063,7 +44045,7 @@ const MessageTypeList = Object.freeze([
44063
44045
  },
44064
44046
  {
44065
44047
  id: MessageTypes.FEED,
44066
- icon: 'paper',
44048
+ icon: 'megaphone',
44067
44049
  label: 'SOCIAL.MESSAGE.TYPE_ENUM.FEED',
44068
44050
  },
44069
44051
  ]);
@@ -44208,11 +44190,11 @@ class MessageForm extends AppForm {
44208
44190
  this.cd.markForCheck();
44209
44191
  }
44210
44192
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessageForm, deps: [{ token: i0.Injector }, { token: i1$3.UntypedFormBuilder }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
44211
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: MessageForm, selector: "app-message-form", inputs: { suggestFn: "suggestFn", subjectMinLength: "subjectMinLength", subjectMaxLength: "subjectMaxLength", bodyMaxLength: "bodyMaxLength", bodyAutoHeight: "bodyAutoHeight", canSelectType: "canSelectType", canRecipientFilter: "canRecipientFilter", recipientFilterCount: "recipientFilterCount" }, usesInheritance: true, ngImport: i0, template: "<form [formGroup]=\"form\" class=\"form-container\">\n <!-- type -->\n <mat-form-field *ngIf=\"canSelectType\">\n <mat-label>{{ 'SOCIAL.MESSAGE.TYPE' | translate }}</mat-label>\n <mat-select formControlName=\"type\">\n <ng-container *ngFor=\"let item of types\">\n <mat-option [value]=\"item.id\" *ngIf=\"item.id !== 'FEED' || canRecipientFilter\">\n <ion-icon [name]=\"item.icon\"></ion-icon>\n {{ item.label | translate }}\n </mat-option>\n </ng-container>\n </mat-select>\n </mat-form-field>\n\n <!-- Recipients -->\n <mat-chips-field\n *ngIf=\"(form.controls.type.valueChanges | async) !== 'FEED'; else recipientFilter\"\n formControlName=\"recipients\"\n chipColor=\"accent\"\n [placeholder]=\"'SOCIAL.MESSAGE.RECIPIENTS' | translate\"\n [config]=\"autocompleteFields.recipients\"\n [equals]=\"isSamePerson\"\n ></mat-chips-field>\n <ng-template #recipientFilter>\n <mat-form-field>\n <mat-chip-grid>\n <mat-chip-row>\n {{ 'SOCIAL.MESSAGE.RECIPIENT_FILTER_COUNT' | translate: { count: recipientFilterCount } }}\n </mat-chip-row>\n </mat-chip-grid>\n <input matInput hidden type=\"number\" />\n </mat-form-field>\n </ng-template>\n\n <!-- Subject -->\n <mat-form-field>\n <mat-label>{{ 'SOCIAL.MESSAGE.SUBJECT' | translate }}</mat-label>\n <input matInput type=\"text\" formControlName=\"subject\" autocomplete=\"off\" required />\n <mat-error *ngIf=\"form.controls.subject.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"form.controls.subject.hasError('minlength')\">\n {{ 'ERROR.FIELD_MIN_LENGTH_COMPACT' | translate }}\n </mat-error>\n <mat-error *ngIf=\"form.controls.subject.hasError('maxlength')\">\n {{ 'ERROR.FIELD_MAX_LENGTH_COMPACT' | translate }}\n </mat-error>\n <mat-hint *ngIf=\"subjectMaxLength\" align=\"end\">\n {{\n 'INFO.TEXT_PROGRESS' | translate: { current: form.controls.subject.value?.length || 0, max: subjectMaxLength }\n }}\n </mat-hint>\n </mat-form-field>\n\n <!-- Body -->\n <mat-form-field>\n <mat-label>{{ 'SOCIAL.MESSAGE.BODY_HELP' | translate }}</mat-label>\n <textarea\n matInput\n type=\"text\"\n formControlName=\"body\"\n [class.fixed-height]=\"!bodyAutoHeight\"\n [cdkTextareaAutosize]=\"bodyAutoHeight\"\n (keydown.control.enter)=\"doSubmit($event)\"\n ></textarea>\n <mat-error *ngIf=\"form.controls.body.hasError('maxlength')\">\n {{ 'ERROR.FIELD_MAX_LENGTH' | translate: form.controls.body.errors.maxlength }}\n </mat-error>\n <mat-hint *ngIf=\"bodyMaxLength\" align=\"end\">\n {{ 'INFO.TEXT_PROGRESS' | translate: { current: form.controls.body.value?.length || 0, max: bodyMaxLength } }}\n </mat-hint>\n </mat-form-field>\n</form>\n", styles: ["textarea.fixed-height{height:11.5em}textarea{min-height:11.5em}\n"], dependencies: [{ kind: "directive", type: i3$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2$1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i3.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "directive", type: i1$4.CdkTextareaAutosize, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMinRows", "cdkAutosizeMaxRows", "cdkTextareaAutosize", "placeholder"], exportAs: ["cdkTextareaAutosize"] }, { kind: "component", type: i6$3.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: MatChipsField, selector: "mat-chips-field", inputs: ["equals", "logPrefix", "formControl", "formControlName", "floatLabel", "placeholder", "suggestFn", "required", "mobile", "readonly", "clearable", "debounceTime", "displaySeparator", "displayWith", "displayAttributes", "displayColumnSizes", "displayColumnNames", "highlightAccent", "showAllOnFocus", "showPanelOnFocus", "autofocus", "config", "i18nPrefix", "noResultMessage", "panelClass", "panelWidth", "disableRipple", "matAutocompletePosition", "itemSize", "fetchMoreThreshold", "suggestLengthThreshold", "showLoadingSpinner", "chipColor", "debug", "applyImplicitValue", "dropButtonTitle", "clearButtonTitle", "trimSearchText", "hideRequiredMarker", "colSizes", "separatorKeysCodes", "appearance", "subscriptSizing", "class", "filter", "tabindex", "items"], outputs: ["click", "blur", "focus", "dropButtonClick", "keydown.escape", "keyup.enter"] }, { kind: "directive", type: AutoResizeDirective, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMaxRows", "cdkAutosizeMinRows"] }, { kind: "component", type: i11$1.MatChipGrid, selector: "mat-chip-grid", inputs: ["disabled", "placeholder", "required", "value", "errorStateMatcher"], outputs: ["change", "valueChange"] }, { kind: "component", type: i11$1.MatChipRow, selector: "mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]", inputs: ["editable"], outputs: ["edited"] }, { kind: "pipe", type: i3$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
44193
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: MessageForm, selector: "app-message-form", inputs: { suggestFn: "suggestFn", subjectMinLength: "subjectMinLength", subjectMaxLength: "subjectMaxLength", bodyMaxLength: "bodyMaxLength", bodyAutoHeight: "bodyAutoHeight", canSelectType: "canSelectType", canRecipientFilter: "canRecipientFilter", recipientFilterCount: "recipientFilterCount" }, usesInheritance: true, ngImport: i0, template: "<form [formGroup]=\"form\" class=\"form-container\">\n <!-- type -->\n <mat-form-field *ngIf=\"canSelectType\">\n <mat-label>{{ 'SOCIAL.MESSAGE.TYPE' | translate }}</mat-label>\n <mat-select formControlName=\"type\">\n @for (item of types; track item.id) {\n @if (canRecipientFilter || item.id !== 'FEED') {\n <mat-option [value]=\"item.id\">\n <ion-icon [name]=\"item.icon\"></ion-icon>\n {{ item.label | translate }}\n </mat-option>\n }\n }\n </mat-select>\n </mat-form-field>\n\n <!-- Recipients -->\n @if ((form | formGetValue: 'type') !== 'FEED') {\n <mat-chips-field\n formControlName=\"recipients\"\n chipColor=\"accent\"\n [placeholder]=\"'SOCIAL.MESSAGE.RECIPIENTS' | translate\"\n [config]=\"autocompleteFields.recipients\"\n [equals]=\"isSamePerson\"\n ></mat-chips-field>\n } @else {\n <mat-form-field>\n <input matInput hidden formControlName=\"recipients\" type=\"text\" />\n <mat-chip-grid>\n <mat-chip-row>\n {{ 'SOCIAL.MESSAGE.RECIPIENT_FILTER_COUNT' | translate: { count: recipientFilterCount } }}\n </mat-chip-row>\n </mat-chip-grid>\n </mat-form-field>\n }\n\n <!-- Subject -->\n <mat-form-field>\n <mat-label>{{ 'SOCIAL.MESSAGE.SUBJECT' | translate }}</mat-label>\n <input matInput type=\"text\" formControlName=\"subject\" autocomplete=\"off\" required />\n <mat-error *ngIf=\"form.controls.subject.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"form.controls.subject.hasError('minlength')\">\n {{ 'ERROR.FIELD_MIN_LENGTH_COMPACT' | translate }}\n </mat-error>\n <mat-error *ngIf=\"form.controls.subject.hasError('maxlength')\">\n {{ 'ERROR.FIELD_MAX_LENGTH_COMPACT' | translate }}\n </mat-error>\n <mat-hint *ngIf=\"subjectMaxLength\" align=\"end\">\n {{\n 'INFO.TEXT_PROGRESS' | translate: { current: form.controls.subject.value?.length || 0, max: subjectMaxLength }\n }}\n </mat-hint>\n </mat-form-field>\n\n <!-- Body -->\n <mat-form-field>\n <mat-label>{{ 'SOCIAL.MESSAGE.BODY_HELP' | translate }}</mat-label>\n <textarea\n matInput\n type=\"text\"\n formControlName=\"body\"\n [class.fixed-height]=\"!bodyAutoHeight\"\n [cdkTextareaAutosize]=\"bodyAutoHeight\"\n (keydown.control.enter)=\"doSubmit($event)\"\n ></textarea>\n <mat-error *ngIf=\"form.controls.body.hasError('maxlength')\">\n {{ 'ERROR.FIELD_MAX_LENGTH' | translate: form.controls.body.errors.maxlength }}\n </mat-error>\n <mat-hint *ngIf=\"bodyMaxLength\" align=\"end\">\n {{ 'INFO.TEXT_PROGRESS' | translate: { current: form.controls.body.value?.length || 0, max: bodyMaxLength } }}\n </mat-hint>\n </mat-form-field>\n</form>\n", styles: ["textarea.fixed-height{height:11.5em}textarea{min-height:11.5em}\n"], dependencies: [{ kind: "directive", type: i3$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2$1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i3.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "directive", type: i1$4.CdkTextareaAutosize, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMinRows", "cdkAutosizeMaxRows", "cdkTextareaAutosize", "placeholder"], exportAs: ["cdkTextareaAutosize"] }, { kind: "component", type: i6$3.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: MatChipsField, selector: "mat-chips-field", inputs: ["equals", "logPrefix", "formControl", "formControlName", "floatLabel", "placeholder", "suggestFn", "required", "mobile", "readonly", "clearable", "debounceTime", "displaySeparator", "displayWith", "displayAttributes", "displayColumnSizes", "displayColumnNames", "highlightAccent", "showAllOnFocus", "showPanelOnFocus", "autofocus", "config", "i18nPrefix", "noResultMessage", "panelClass", "panelWidth", "disableRipple", "matAutocompletePosition", "itemSize", "fetchMoreThreshold", "suggestLengthThreshold", "showLoadingSpinner", "chipColor", "debug", "applyImplicitValue", "dropButtonTitle", "clearButtonTitle", "trimSearchText", "hideRequiredMarker", "colSizes", "separatorKeysCodes", "appearance", "subscriptSizing", "class", "filter", "tabindex", "items"], outputs: ["click", "blur", "focus", "dropButtonClick", "keydown.escape", "keyup.enter"] }, { kind: "directive", type: AutoResizeDirective, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMaxRows", "cdkAutosizeMinRows"] }, { kind: "component", type: i11$1.MatChipGrid, selector: "mat-chip-grid", inputs: ["disabled", "placeholder", "required", "value", "errorStateMatcher"], outputs: ["change", "valueChange"] }, { kind: "component", type: i11$1.MatChipRow, selector: "mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]", inputs: ["editable"], outputs: ["edited"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }, { kind: "pipe", type: FormGetValuePipe, name: "formGetValue" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
44212
44194
  }
44213
44195
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessageForm, decorators: [{
44214
44196
  type: Component,
44215
- args: [{ selector: 'app-message-form', changeDetection: ChangeDetectionStrategy.OnPush, template: "<form [formGroup]=\"form\" class=\"form-container\">\n <!-- type -->\n <mat-form-field *ngIf=\"canSelectType\">\n <mat-label>{{ 'SOCIAL.MESSAGE.TYPE' | translate }}</mat-label>\n <mat-select formControlName=\"type\">\n <ng-container *ngFor=\"let item of types\">\n <mat-option [value]=\"item.id\" *ngIf=\"item.id !== 'FEED' || canRecipientFilter\">\n <ion-icon [name]=\"item.icon\"></ion-icon>\n {{ item.label | translate }}\n </mat-option>\n </ng-container>\n </mat-select>\n </mat-form-field>\n\n <!-- Recipients -->\n <mat-chips-field\n *ngIf=\"(form.controls.type.valueChanges | async) !== 'FEED'; else recipientFilter\"\n formControlName=\"recipients\"\n chipColor=\"accent\"\n [placeholder]=\"'SOCIAL.MESSAGE.RECIPIENTS' | translate\"\n [config]=\"autocompleteFields.recipients\"\n [equals]=\"isSamePerson\"\n ></mat-chips-field>\n <ng-template #recipientFilter>\n <mat-form-field>\n <mat-chip-grid>\n <mat-chip-row>\n {{ 'SOCIAL.MESSAGE.RECIPIENT_FILTER_COUNT' | translate: { count: recipientFilterCount } }}\n </mat-chip-row>\n </mat-chip-grid>\n <input matInput hidden type=\"number\" />\n </mat-form-field>\n </ng-template>\n\n <!-- Subject -->\n <mat-form-field>\n <mat-label>{{ 'SOCIAL.MESSAGE.SUBJECT' | translate }}</mat-label>\n <input matInput type=\"text\" formControlName=\"subject\" autocomplete=\"off\" required />\n <mat-error *ngIf=\"form.controls.subject.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"form.controls.subject.hasError('minlength')\">\n {{ 'ERROR.FIELD_MIN_LENGTH_COMPACT' | translate }}\n </mat-error>\n <mat-error *ngIf=\"form.controls.subject.hasError('maxlength')\">\n {{ 'ERROR.FIELD_MAX_LENGTH_COMPACT' | translate }}\n </mat-error>\n <mat-hint *ngIf=\"subjectMaxLength\" align=\"end\">\n {{\n 'INFO.TEXT_PROGRESS' | translate: { current: form.controls.subject.value?.length || 0, max: subjectMaxLength }\n }}\n </mat-hint>\n </mat-form-field>\n\n <!-- Body -->\n <mat-form-field>\n <mat-label>{{ 'SOCIAL.MESSAGE.BODY_HELP' | translate }}</mat-label>\n <textarea\n matInput\n type=\"text\"\n formControlName=\"body\"\n [class.fixed-height]=\"!bodyAutoHeight\"\n [cdkTextareaAutosize]=\"bodyAutoHeight\"\n (keydown.control.enter)=\"doSubmit($event)\"\n ></textarea>\n <mat-error *ngIf=\"form.controls.body.hasError('maxlength')\">\n {{ 'ERROR.FIELD_MAX_LENGTH' | translate: form.controls.body.errors.maxlength }}\n </mat-error>\n <mat-hint *ngIf=\"bodyMaxLength\" align=\"end\">\n {{ 'INFO.TEXT_PROGRESS' | translate: { current: form.controls.body.value?.length || 0, max: bodyMaxLength } }}\n </mat-hint>\n </mat-form-field>\n</form>\n", styles: ["textarea.fixed-height{height:11.5em}textarea{min-height:11.5em}\n"] }]
44197
+ args: [{ selector: 'app-message-form', changeDetection: ChangeDetectionStrategy.OnPush, template: "<form [formGroup]=\"form\" class=\"form-container\">\n <!-- type -->\n <mat-form-field *ngIf=\"canSelectType\">\n <mat-label>{{ 'SOCIAL.MESSAGE.TYPE' | translate }}</mat-label>\n <mat-select formControlName=\"type\">\n @for (item of types; track item.id) {\n @if (canRecipientFilter || item.id !== 'FEED') {\n <mat-option [value]=\"item.id\">\n <ion-icon [name]=\"item.icon\"></ion-icon>\n {{ item.label | translate }}\n </mat-option>\n }\n }\n </mat-select>\n </mat-form-field>\n\n <!-- Recipients -->\n @if ((form | formGetValue: 'type') !== 'FEED') {\n <mat-chips-field\n formControlName=\"recipients\"\n chipColor=\"accent\"\n [placeholder]=\"'SOCIAL.MESSAGE.RECIPIENTS' | translate\"\n [config]=\"autocompleteFields.recipients\"\n [equals]=\"isSamePerson\"\n ></mat-chips-field>\n } @else {\n <mat-form-field>\n <input matInput hidden formControlName=\"recipients\" type=\"text\" />\n <mat-chip-grid>\n <mat-chip-row>\n {{ 'SOCIAL.MESSAGE.RECIPIENT_FILTER_COUNT' | translate: { count: recipientFilterCount } }}\n </mat-chip-row>\n </mat-chip-grid>\n </mat-form-field>\n }\n\n <!-- Subject -->\n <mat-form-field>\n <mat-label>{{ 'SOCIAL.MESSAGE.SUBJECT' | translate }}</mat-label>\n <input matInput type=\"text\" formControlName=\"subject\" autocomplete=\"off\" required />\n <mat-error *ngIf=\"form.controls.subject.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"form.controls.subject.hasError('minlength')\">\n {{ 'ERROR.FIELD_MIN_LENGTH_COMPACT' | translate }}\n </mat-error>\n <mat-error *ngIf=\"form.controls.subject.hasError('maxlength')\">\n {{ 'ERROR.FIELD_MAX_LENGTH_COMPACT' | translate }}\n </mat-error>\n <mat-hint *ngIf=\"subjectMaxLength\" align=\"end\">\n {{\n 'INFO.TEXT_PROGRESS' | translate: { current: form.controls.subject.value?.length || 0, max: subjectMaxLength }\n }}\n </mat-hint>\n </mat-form-field>\n\n <!-- Body -->\n <mat-form-field>\n <mat-label>{{ 'SOCIAL.MESSAGE.BODY_HELP' | translate }}</mat-label>\n <textarea\n matInput\n type=\"text\"\n formControlName=\"body\"\n [class.fixed-height]=\"!bodyAutoHeight\"\n [cdkTextareaAutosize]=\"bodyAutoHeight\"\n (keydown.control.enter)=\"doSubmit($event)\"\n ></textarea>\n <mat-error *ngIf=\"form.controls.body.hasError('maxlength')\">\n {{ 'ERROR.FIELD_MAX_LENGTH' | translate: form.controls.body.errors.maxlength }}\n </mat-error>\n <mat-hint *ngIf=\"bodyMaxLength\" align=\"end\">\n {{ 'INFO.TEXT_PROGRESS' | translate: { current: form.controls.body.value?.length || 0, max: bodyMaxLength } }}\n </mat-hint>\n </mat-form-field>\n</form>\n", styles: ["textarea.fixed-height{height:11.5em}textarea{min-height:11.5em}\n"] }]
44216
44198
  }], ctorParameters: () => [{ type: i0.Injector }, { type: i1$3.UntypedFormBuilder }, { type: i0.ChangeDetectorRef }], propDecorators: { suggestFn: [{
44217
44199
  type: Input
44218
44200
  }], subjectMinLength: [{
@@ -44861,160 +44843,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
44861
44843
  args: [ENVIRONMENT]
44862
44844
  }] }] });
44863
44845
 
44864
- class DiscourseFeedService extends StartableService {
44865
- settings;
44866
- environment;
44867
- discourseApis = new Map();
44868
- _logPrefix = '[discourse-feed-service] ';
44869
- _state = new RxState();
44870
- network = inject(NetworkService);
44871
- locale$ = this._state.select('locale');
44872
- feedUrls$ = this._state.select('feedUrls');
44873
- get feedUrls() {
44874
- return this._state.get('feedUrls');
44875
- }
44876
- set feedUrls(urls) {
44877
- this._state.set('feedUrls', () => urls);
44878
- }
44879
- constructor(settings, environment) {
44880
- super(settings);
44881
- this.settings = settings;
44882
- this.environment = environment;
44883
- this._debug = !environment.production;
44884
- if (this._debug)
44885
- console.debug('[discourse-feed-service] Creating service');
44886
- this._state.connect('locale', this.settings.locale$);
44887
- this._state.connect('feedUrls', this.locale$.pipe(filter(isNotNilOrBlank), map((locale) => (locale && environment.feed?.jsonFeed?.[locale]) ?? [])));
44888
- }
44889
- async ngOnStart() {
44890
- await this.settings.ready();
44891
- return {
44892
- locale: this.settings.locale,
44893
- };
44894
- }
44895
- watchAll(opts) {
44896
- if (!this.started) {
44897
- return from(this.start()).pipe(switchMap$1(() => this.watchAll(opts)));
44898
- }
44899
- if (isNotEmptyArray(opts?.urls)) {
44900
- return this.locale$.pipe(mergeMap((locale) => this.loadAll(opts.urls, { locale, ...opts })));
44901
- }
44902
- return this.feedUrls$.pipe(filter(isNotEmptyArray), mergeMap((urls) => this.loadAll(urls, opts)));
44903
- }
44904
- getHomeUrl(feed) {
44905
- const feedUrl = feed?.feed_url ?? firstArrayValue(this.feedUrls);
44906
- return feedUrl ? UrlUtils.getRootUrl(feedUrl) : undefined;
44907
- }
44908
- getTagUrl(feed, tag) {
44909
- if (!feed || !tag)
44910
- throw new Error("Missing 'feed' or 'tag' argument");
44911
- const baseUrl = this.getHomeUrl(feed);
44912
- return feed.tag_template?.replace('{tag}', tag) ?? baseUrl + '/tag/' + tag;
44913
- }
44914
- async load(url, opts) {
44915
- const { data } = await this.loadAll([url], opts);
44916
- return data?.[0];
44917
- }
44918
- async loadAll(urls, opts) {
44919
- await this.ready();
44920
- urls = urls ?? this.feedUrls;
44921
- opts = {
44922
- maxAgeInMonths: opts?.maxAgeInMonths ?? this.environment.feed?.maxAgeInMonths,
44923
- maxContentLength: opts?.maxContentLength ?? this.environment.feed?.maxContentLength,
44924
- locale: this.settings.locale,
44925
- depth: 0,
44926
- closeApis: true,
44927
- ...opts,
44928
- };
44929
- const feeds = await Promise$1.all((urls || []).map(async (url) => {
44930
- try {
44931
- // Get JSON
44932
- const json = await this.network.fetch(url);
44933
- console.debug(`${this._logPrefix}Loaded JSON from ${url}`, json);
44934
- if (JsonFeedUtils.isJsonFeed(json)) {
44935
- // Migrate old version
44936
- let feed = JsonFeedUtils.migrateFeed(json);
44937
- // Resolve items (e.g. using feed.next_url)
44938
- feed = await this.resolveFeedItems(feed, { ...opts, depth: opts?.depth ?? 0 });
44939
- // Truncate html
44940
- JsonFeedUtils.truncateFeedItemsHtml(feed, opts);
44941
- return isNotEmptyArray(feed?.items) ? [feed] : [];
44942
- }
44943
- // Get discourse
44944
- if (DiscourseUtils.isDiscourseObject(json)) {
44945
- const api = this.getOrCreateDiscourseApi(url);
44946
- return await DiscourseUtils.getFeedsByUrl(url, { ...opts, api });
44947
- }
44948
- return undefined;
44949
- }
44950
- catch (err) {
44951
- if (err?.status === 404) {
44952
- console.error(`${this._logPrefix} Error while fetching feed at ${url}. 404 (Not found)`);
44953
- }
44954
- else {
44955
- console.error(`${this._logPrefix} Error while fetching feed at ${url}`, err);
44956
- }
44957
- return Promise$1.resolve([]);
44958
- }
44959
- }));
44960
- if (opts?.closeApis !== false) {
44961
- this.closeApis();
44962
- }
44963
- const data = feeds.flat();
44964
- return { data, total: data.length };
44965
- }
44966
- getOrCreateDiscourseApi(url) {
44967
- const baseUrl = DiscourseUtils.getDiscourseBaseUrl(url);
44968
- let api = this.discourseApis.get(baseUrl);
44969
- if (!api) {
44970
- api = new DiscourseAPI(baseUrl);
44971
- this.discourseApis.set(baseUrl, api);
44972
- }
44973
- return api;
44974
- }
44975
- closeApis() {
44976
- this.discourseApis.clear();
44977
- }
44978
- async resolveFeedItems(json, opts) {
44979
- if (!json)
44980
- return json;
44981
- // Load items
44982
- if (isEmptyArray(json.items) && isNotNilOrBlank(json.next_url)) {
44983
- const depth = opts?.depth ?? 0;
44984
- if (depth >= 3) {
44985
- console.warn(`${this._logPrefix}Max depth reached (${depth}) for ${json.feed_url}`);
44986
- return json;
44987
- }
44988
- // Load items
44989
- const feed = await this.load(json.next_url, { ...opts, closeApis: false, depth: depth + 1 });
44990
- if (isEmptyArray(feed?.items)) {
44991
- return json;
44992
- }
44993
- // Merge with the input json
44994
- return {
44995
- ...json,
44996
- title: json.title ?? feed.title,
44997
- home_page_url: json.home_page_url ?? feed.home_page_url,
44998
- authors: isNotEmptyArray(json.authors) ? json.authors : feed.authors,
44999
- items: feed.items,
45000
- tag_template: json.tag_template ?? feed.tag_template,
45001
- };
45002
- }
45003
- return json;
45004
- }
45005
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DiscourseFeedService, deps: [{ token: LocalSettingsService }, { token: ENVIRONMENT, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
45006
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DiscourseFeedService, providedIn: 'root' });
45007
- }
45008
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DiscourseFeedService, decorators: [{
45009
- type: Injectable,
45010
- args: [{ providedIn: 'root' }]
45011
- }], ctorParameters: () => [{ type: LocalSettingsService }, { type: Environment, decorators: [{
45012
- type: Optional
45013
- }, {
45014
- type: Inject,
45015
- args: [ENVIRONMENT]
45016
- }] }] });
45017
-
45018
44846
  const PersonFragments = {
45019
44847
  person: gql$1 `
45020
44848
  fragment PersonFragment on PersonVO {
@@ -49898,5 +49726,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
49898
49726
  * Generated bundle index. Do not edit.
49899
49727
  */
49900
49728
 
49901
- export { APP_ABOUT_DEVELOPERS, APP_ABOUT_PARTNERS, APP_CONFIG_OPTIONS, APP_DEBUG_DATA_SERVICE, APP_FEED_SERVICE, APP_FORM_ERROR_I18N_KEYS, APP_GRAPHQL_FRAGMENTS, APP_GRAPHQL_TYPE_POLICIES, APP_HOME_BUTTONS, APP_HOME_CONFIG, APP_HOTKEYS_CONFIG, APP_JOB_PROGRESSION_SERVICE, APP_LOCALES, APP_LOCAL_SETTINGS, APP_LOCAL_SETTINGS_OPTIONS, APP_LOCAL_STORAGE_TYPE_POLICIES, APP_LOGGING_SERVICE, APP_MENU_ITEMS, APP_MENU_OPTIONS, APP_NAMED_FILTER_SERVICE, APP_PROGRESS_BAR_SERVICE, APP_SETTINGS_MENU_ITEMS, APP_STORAGE, APP_STORAGE_EXPLORER_PROTECTED_KEYS, APP_TESTING_PAGES, APP_USER_EVENT_LIST_INFINITE_SCROLL_THRESHOLD, APP_USER_EVENT_SERVICE, APP_USER_SETTINGS_OPTIONS, APP_USER_TOKEN_SCOPES, AboutModal, AbstractNamedFilterService, AbstractSelectionModelPipe, AbstractTableSelectionPipe, AbstractUserEventService, Account, AccountPage, AccountService, AccountToStringPipe, AccountUtils, ActionsColumnComponent, AdminModule, AdminRoutingModule, AdminUsersModule, Alerts, AndroidOsEnvironment, AppAboutModalModule, AppAccountModule, AppAsyncTable, AppAuthForm, AppAuthModal, AppAuthModule, AppChangePasswordModule, AppChangePasswordPage, AppEditor, AppEditorOptions, AppEntityEditor, AppEntityEditorModal, AppEntityEditorModalOptions, AppEntityFormModule, AppForm, AppFormArray, AppFormButtonsBarModule, AppFormContainer, AppFormField, AppFormModule, AppFormProvider, AppFormUtils, AppGestureConfig, AppGraphQLModule, AppHomePageModule, AppIconComponent, AppIconModule, AppImageGalleryComponent, AppInMemoryTable, AppInstallUpgradeCard, AppInstallUpgradeCardModule, AppListForm, AppListFormModule, AppLoadingSpinner, AppMarkdownContent, AppMarkdownModal, AppMenuModule, AppNullForm, AppPropertiesForm, AppPropertiesFormModule, AppPropertiesTable, AppPropertiesUtils, AppPropertyUtils, AppRegisterModule, AppResetPasswordModal, AppRowField, AppSelectPeerModule, AppSettingsPageModule, AppTabEditor, AppTabEditorOptions, AppTable, AppTableModule, AppTableUtils, AppTextPopoverModule, AppUpdateOfflineModeCard, AppUpdateOfflineModeCardModule, AppValidatorService, AppendQueryParamsPipePipe, ArrayDistinctPipe, ArrayFilterPipe, ArrayFindByPropertyPipe, ArrayFirstPipe, ArrayFormTestPage, ArrayIncludesPipe, ArrayJoinPipe, ArrayLastPipe, ArrayLengthPipe, ArrayPluckPipe, ArraySortPipe, AsAnyPipe, AsArrayPipe, AsBooleanPipe, AsFloatLabelTypePipe, AsObservablePipe, AudioProvider, AudioTestingModule, AudioTestingPage, AuthGuardService, AutoResizeDirective, AutoTitleDirective, AutocompleteTestPage, AutofocusDirective, BadgeDirective, BadgeNumberPipe, Base58, BaseEntityService, BaseGraphqlService, BaseGraphqlServiceOptions, BaseReferential, Beans, BooleanFormatPipe, BooleanTestPage, CORE_CONFIG_OPTIONS, CORE_TESTING_PAGES, CapitalizePipe, CellValueChangeListener, ChangePasswordForm, ChipsTestPage, Color, ColorScale, ComponentDirtyGuard, ConfigFragments, ConfigService, Configuration, CoreModule, CorePipesModule, CoreTestingModule, CryptoService, CsvUtils, DATE_ISO_PATTERN, DATE_MATCH_REGEXP, DATE_PATTERN, DATE_UNIX_MS_TIMESTAMP, DATE_UNIX_TIMESTAMP, DEFAULT_JOIN_ARRAY_VALUES_SEPARATOR, DEFAULT_JOIN_PROPERTIES_SEPARATOR, DEFAULT_MENU_SHOW_WHEN, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLACEHOLDER_CHAR, DEFAULT_REQUIRED_COLUMNS, DateDiffDurationPipe, DateFormatPipe, DateFormatService, DateFromNowPipe, DateShortTestPage, DateTestPage, DateTimeTestPage, DateUtils, DebugComponent, Department, DepartmentToStringPipe, DiscourseFeedService, DiscourseUtils, DisplayWithPipe, DragAndDropDirective, DurationPipe, DurationTestPage, ED25519_SEED_LENGTH, EMPTY_PLACEHOLDER_CHAR, EMPTY_PLACEHOLDER_CHAR_REGEXP_GLOBAL, ENTITIES_STORAGE_KEY_PREFIX, ENVIRONMENT, EmptyArrayPipe, EntitiesAsyncTableDataSource, EntitiesStorage, EntitiesTableDataSource, Entity, EntityClass, EntityClasses, EntityFilter, EntityFilterUtils, EntityMetadataComponent, EntityStore, EntityUtils, Environment, EnvironmentHttpLoader, EnvironmentLoader, ErrorCodes, EvenPipe, FeedDirective, FeedModule, FeedsComponent, FileResponse, FileService, FileSizePipe, FilesUtils, FirstFalsePipe, FirstPipe, FirstTruePipe, FormArrayHelper, FormArrayTestModule, FormButtonsBarComponent, FormButtonsBarToken, FormErrorPipe, FormErrorTranslatePipe, FormErrorTranslator, FormFieldDefinitionUtils, FormFieldValuesHolder, FormGetArrayPipe, FormGetControlPipe, FormGetGroupPipe, FormGetPipe, FormGetValuePipe, GalleryTestPage, GeolocationUtils, GraphqlService, HAMMER_PRESS_TIME, HAMMER_TAP_TIME, HighlightPipe, HomePage, Hotkeys, HotkeysDialogComponent, IMAGE_DEFAULTS, IPosition, ImageAttachment, ImageAttachmentFilter, ImageAttachmentService, ImageGalleryModule, ImageGalleryTestingModule, ImageModule, ImageService, ImagesUtils, InMemoryEntitiesService, IsAllSelectedPipe, IsEmptySelectionPipe, IsLoginAccountPipe, IsMultipleSelectionPipe, IsNilOrBlankPipe, IsNilOrNaNPipe, IsNilPipe, IsNotAllSelectedPipe, IsNotEmptySelectionPipe, IsNotNilOrBlankPipe, IsNotNilOrNaNPipe, IsNotNilPipe, IsOnDeskPipe, IsOnFieldPipe, IsSelectedPipe, IsSingleSelectionPipe, IsValidDatePipe, JobModule, JobProgression, JobProgressionComponent, JobProgressionIcon, JobProgressionList, JobProgressionService, JobProgressionTestService, JobProgressionTestingPage, JobTestingModule, JobUtils, JsonFeedUtils, JsonUtils, KEYBOARD_HIDE_DELAY_MS, LAT_LONG_PATTERNS, LAT_LONG_PATTERN_MAX_DECIMALS, LAT_LONG_VALUE_MAX_DECIMALS, LatLongFormatPipe, LatLongTestPage, LatitudeFormatPipe, LocalSettingsService, LogLevel, LogUtils, Logger, LoggingService, LoggingServiceModule, LongitudeFormatPipe, MASKS, MASK_RANGES, MAT_FORM_FIELD_DEFAULT_APPEARANCE, MAT_FORM_FIELD_DEFAULT_SUBSCRIPT_SIZING, MINIFY_ENTITY_FOR_LOCAL_STORAGE, MINIFY_ENTITY_FOR_POD, MOMENT_NO_TIME_PROPERTY, MapGetPipe, MapKeysPipe, MapPipe, MapValuesPipe, MarkdownDirective, MarkdownService, MarkdownTestPage, MarkdownTestingModule, MarkdownUtils, MaskitoPlaceholderPipe, MaskitoTestPage, MatAutocompleteConfigHolder, MatAutocompleteField, MatAutocompleteFieldUtils, MatBadgeTestPage, MatBooleanField, MatChipsField, MatColorPipe, MatCommonTestPage, MatDate, MatDateShort, MatDateTime, MatDuration, MatLatLongField, MatLatLongFieldInput, MatPaginatorI18n, MatStepperI18n, MatSwipeField, MaterialTestingModule, MathAbsPipe, MenuComponent, MenuItem, MenuItems, MenuOptions, MenuService, MenuTestingModule, MenuTestingPage, Message, MessageFilter, MessageForm, MessageModal, MessageModule, MessageService, MessageTypeList, MessageTypes, MimeTypes, ModalToolbarComponent, NETWORK_DEFAULT_CONNECTION_TIMEOUT, NamedFilter, NamedFilterFilter, NamedFilterSelector, NamedFilterSelectorTestingModule, NamedFilterSelectorTestingPage, NavActionsColumnComponent, NetworkService, NetworkUtils, NewTokenForm, NewTokenModal, NgInitDirective, NgVarDirective, NoHtmlPipe, NotEmptyArrayPipe, NumberFormatPipe, ObservableTestPage, OddPipe, OtherMenuTestingPage, PEER_URL_REGEXP, PLUS_PLACEHOLDER_CHAR_REGEXP_GLOBAL, PRINT_ID_QUERY_PARAM, PRINT_LOADING_STORAGE_KEY_PREFIX, PRIORITIZED_AUTHORITIES, PUBKEY_REGEXP, Peer, Person, PersonFilter, PersonFragments, PersonService, PersonToStringPipe, PersonUtils, PersonValidatorService, PlatformService, PrintService, ProgressBarService, ProgressInterceptor, PropertiesFormTestPage, PropertiesFormTestingModule, PropertyEntity, PropertyEntityFilter, PropertyEntityValidator, PropertyFormatPipe, PropertyGetPipe, RESERVED_END_COLUMNS, RESERVED_START_COLUMNS, Referential, ReferentialFilter, ReferentialRef, ReferentialToStringPipe, ReferentialUtils, ReferentialValidatorService, RegExpUtils, RegisterConfirmPage, RegisterForm, RegisterModal, ResizableComponent, ResizableDirective, ResizableModule, RoundPipe, RxStateComputed, RxStateModule, RxStateProperty, RxStateRegister, RxStateSelect, SCRYPT_PARAMS, SETTINGS_COMPACT_ROWS, SETTINGS_DISPLAY_COLUMNS, SETTINGS_FILTER, SETTINGS_PAGE_SIZE, SETTINGS_SORTED_COLUMN, SETTINGS_STORAGE_KEY, SETTINGS_TRANSIENT_PROPERTIES, SHARED_MATERIAL_TESTING_PAGES, SHARED_STORAGE_TESTING_PAGES, SHARED_TESTING_PAGES, SOCIAL_CONFIG_OPTIONS, SOCIAL_TESTING_PAGES, SPACE_PLACEHOLDER_CHAR, SPACE_PLACEHOLDER_CHAR_REGEXP_GLOBAL, SafeHtmlPipe, SafeStylePipe, SelectPeerModal, SelectionLengthPipe, ServerErrorCodes, SettingsPage, SharedAsyncValidators, SharedBadgeModule, SharedDebugModule, SharedDirectivesModule, SharedFormArrayValidators, SharedFormGroupValidators, SharedHotkeysModule, SharedMarkdownModule, SharedMatAutocompleteModule, SharedMatBooleanModule, SharedMatChipsModule, SharedMatDateTimeModule, SharedMatDurationModule, SharedMatLatLongModule, SharedMatSwipeModule, SharedMaterialModule, SharedModule, SharedNamedFilterModule, SharedPipesModule, SharedRoutingModule, SharedTestingModule, SharedTestsPage, SharedTextFormModule, SharedToolbarModule, SharedValidators, SocialErrorCodes, SocialModule, SocialModuleOptionsToken, SocialTestingModule, Software, SplitArrayInChunksPipe, StartableService, StatusById, StatusIds, StatusList, StorageDrivers, StorageExplorerComponent, StorageExplorerModule, StorageExplorerTestingModule, StorageExplorerTestingRoutingModule, StorageService, StrIncludesPipe, StrLengthPipe, StrReplacePipe, SubMenuTabDirective, SwipeTestPage, TABLE_SETTINGS_ENUM, TOOLBAR_HEADER_ID, Table2TestPage, TableSelectColumnsComponent, TableTestPage, TableTestingModule, TableValidatorService, TextForm, TextFormTestingPage, TextPopover, TextPopoverTestingModule, TextPopoverTestingPage, ThrottledClickDirective, ToStringPipe, ToastTestingModule, ToastTestingPage, Toasts, TokenScope, ToolbarComponent, ToolbarToken, TranslatablePipe, TranslateContextPipe, TranslateContextService, TreeItemEntityUtils, TruncHtmlPipe, TruncTextPipe, UploadFile, UploadFileComponent, UploadFilePopover, UploadFileTestingModule, UploadFileTestingPage, UriUtils, UrlUtils, UserEventModule, UserEventNotificationIcon, UserEventNotificationList, UserEventNotificationModal, UserEventTestService, UserEventTestingModule, UserEventTestingPage, UserSettings, UserToken, UserTokenTable, UsersPage, ValueFormatPipe, VersionUtils, accountToString, adaptValueToControl, addValueInArray, arrayDistinct, arrayResize, arraySize, asInputElement, booleanToString, canHaveFocus, capitalizeFirstLetter, chainPromises, changeCaseToUnderscore, clearValueInArray, collectByProperty, compareVersionNumbers, computeDecimalDegrees, computeDecimalPart, copyEntity2Form, createPromiseEvent, createPromiseEventEmitter, departmentToString, departmentsToString, disableAndClearControl, disableAndClearControls, disableControl, disableControls, emitPromiseEvent, enableControl, enableControls, enableRxStateProdMode, entityToString, equals, equalsOrNil, escapeRegExp, expansionAnimation, fadeInAnimation, fadeInOutAnimation, fadeInSlowAnimation, filterFalse, filterFormErrors, filterFormErrorsByPath, filterFormErrorsByPrefix, filterNotNil, filterNumberInput, filterTrue, findParentWithClass, firstArrayValue, firstFalse, firstFalsePromise, firstNotNil, firstNotNilPromise, firstTrue, firstTruePromise, focusInput, focusNextInput, focusPreviousInput, formatLatLong, formatLatitude, formatLongitude, fromDateISOString, fromScrollEndEvent, fromUnixMsTimestamp, fromUnixTimestamp, getCaretPosition, getColorContrast, getColorShade, getColorTint, getControlFromPath, getFocusableInputElements, getFormErrors, getFormValueFromEntity, getInputRangeFromCaretIndex, getInputSelectionRangesFromMask, getProperty, getPropertyByPath, getPropertyByPathAsString, getRandomImage, getRandomImageWithCredit, getUserAgent, hexToRgb, hexToRgbArray, initArrayControlsFromValues, interpolateString, intersectArrays, isAndroid, isBlankString, isCapacitor, isChrome, isControlHasInput, isEdge, isEmptyArray, isEntityService, isFirefox, isIOS, isInputElement, isInstanceOf, isInt, isIpad, isMacOS, isMobile, isNil, isNilOrBlank, isNilOrNaN, isNotEmptyArray, isNotNil, isNotNilBoolean, isNotNilObject, isNotNilOrBlank, isNotNilOrNaN, isNotNilString, isNumber, isNumberRange, isOnFieldMode, isPrint, isProgressEvent, isPromise, isResponseEvent, isSafari, isSameVersion, isStartableService, isTouchUi, isVersionCompatible, isWindows, joinProperties, joinPropertiesPath, lastArrayValue, logFormErrors, markAllAsTouched, markAsUntouched, markControlAsTouched, markFormGroupAsTouched, maskitoAutoSelectByMaskPattern, maskitoPrefixPlugin, matchMedia, matchUpperCase, mergeLoadResult, mixHex, moveInputCaretToSeparator, newArray, noHtml, noTrailingSlash, notNilOrDefault, nullIfNilOrBlank, nullIfUndefined, numberOrNilAttribute, numberToString, parseLatitudeOrLongitude, propertiesPathComparator, propertyComparator, propertyPathComparator, referentialToString, referentialsToString, remove, removeAll, removeDiacritics, removeDuplicatesFromArray, removeEnd, removeValueInArray, replaceAll, resetCalculatedValue, resizeArray, rgbArrayToHex, rgbToHex, round, scrollFactory, selectInputContent, selectInputContentFromEvent, selectInputRange, setCalculatedValue, setControlEnabled, setControlsEnabled, setFormErrors, setPropertyByPath, setTabIndex, sleep, slideDownAnimation, slideInAnimation, slideInOutAnimation, slideUpDownAnimation, sort, splitArrayInChunks, splitById, splitByProperty, splitDegreesToDDArray, splitDegreesToDDMMArray, splitDegreesToDDMMSSArray, startsWithUpperCase, suggestFromArray, suggestFromStringArray, tabindexComparator, testUserAgent, toBoolean, toDateISOString, toDuration, toFloat, toInt, toNotNil, toNumber, trimEmptyToNull, uncapitalizeFirstLetter, undefinedIfNull, underscoreToChangeCase, updateValueAndValidity, waitFor, waitForFalse, waitForTrue, waitIdle, waitWhilePending };
49729
+ export { APP_ABOUT_DEVELOPERS, APP_ABOUT_PARTNERS, APP_CONFIG_OPTIONS, APP_DEBUG_DATA_SERVICE, APP_FEED_SERVICE, APP_FORM_ERROR_I18N_KEYS, APP_GRAPHQL_FRAGMENTS, APP_GRAPHQL_TYPE_POLICIES, APP_HOME_BUTTONS, APP_HOME_CONFIG, APP_HOTKEYS_CONFIG, APP_JOB_PROGRESSION_SERVICE, APP_LOCALES, APP_LOCAL_SETTINGS, APP_LOCAL_SETTINGS_OPTIONS, APP_LOCAL_STORAGE_TYPE_POLICIES, APP_LOGGING_SERVICE, APP_MENU_ITEMS, APP_MENU_OPTIONS, APP_NAMED_FILTER_SERVICE, APP_PROGRESS_BAR_SERVICE, APP_SETTINGS_MENU_ITEMS, APP_STORAGE, APP_STORAGE_EXPLORER_PROTECTED_KEYS, APP_TESTING_PAGES, APP_USER_EVENT_LIST_INFINITE_SCROLL_THRESHOLD, APP_USER_EVENT_SERVICE, APP_USER_SETTINGS_OPTIONS, APP_USER_TOKEN_SCOPES, AboutModal, AbstractNamedFilterService, AbstractSelectionModelPipe, AbstractTableSelectionPipe, AbstractUserEventService, Account, AccountPage, AccountService, AccountToStringPipe, AccountUtils, ActionsColumnComponent, AdminModule, AdminRoutingModule, AdminUsersModule, Alerts, AndroidOsEnvironment, AppAboutModalModule, AppAccountModule, AppAsyncTable, AppAuthForm, AppAuthModal, AppAuthModule, AppChangePasswordModule, AppChangePasswordPage, AppEditor, AppEditorOptions, AppEntityEditor, AppEntityEditorModal, AppEntityEditorModalOptions, AppEntityFormModule, AppForm, AppFormArray, AppFormButtonsBarModule, AppFormContainer, AppFormField, AppFormModule, AppFormProvider, AppFormUtils, AppGestureConfig, AppGraphQLModule, AppHomePageModule, AppIconComponent, AppIconModule, AppImageGalleryComponent, AppInMemoryTable, AppInstallUpgradeCard, AppInstallUpgradeCardModule, AppListForm, AppListFormModule, AppLoadingSpinner, AppMarkdownContent, AppMarkdownModal, AppMenuModule, AppNullForm, AppPropertiesForm, AppPropertiesFormModule, AppPropertiesTable, AppPropertiesUtils, AppPropertyUtils, AppRegisterModule, AppResetPasswordModal, AppRowField, AppSelectPeerModule, AppSettingsPageModule, AppTabEditor, AppTabEditorOptions, AppTable, AppTableModule, AppTableUtils, AppTextPopoverModule, AppUpdateOfflineModeCard, AppUpdateOfflineModeCardModule, AppValidatorService, AppendQueryParamsPipePipe, ArrayDistinctPipe, ArrayFilterPipe, ArrayFindByPropertyPipe, ArrayFirstPipe, ArrayFormTestPage, ArrayIncludesPipe, ArrayJoinPipe, ArrayLastPipe, ArrayLengthPipe, ArrayPluckPipe, ArraySortPipe, AsAnyPipe, AsArrayPipe, AsBooleanPipe, AsFloatLabelTypePipe, AsObservablePipe, AudioProvider, AudioTestingModule, AudioTestingPage, AuthGuardService, AutoResizeDirective, AutoTitleDirective, AutocompleteTestPage, AutofocusDirective, BadgeDirective, BadgeNumberPipe, Base58, BaseEntityService, BaseGraphqlService, BaseGraphqlServiceOptions, BaseReferential, Beans, BooleanFormatPipe, BooleanTestPage, CORE_CONFIG_OPTIONS, CORE_TESTING_PAGES, CapitalizePipe, CellValueChangeListener, ChangePasswordForm, ChipsTestPage, Color, ColorScale, ComponentDirtyGuard, ConfigFragments, ConfigService, Configuration, CoreModule, CorePipesModule, CoreTestingModule, CryptoService, CsvUtils, DATE_ISO_PATTERN, DATE_MATCH_REGEXP, DATE_PATTERN, DATE_UNIX_MS_TIMESTAMP, DATE_UNIX_TIMESTAMP, DEFAULT_JOIN_ARRAY_VALUES_SEPARATOR, DEFAULT_JOIN_PROPERTIES_SEPARATOR, DEFAULT_MENU_SHOW_WHEN, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLACEHOLDER_CHAR, DEFAULT_REQUIRED_COLUMNS, DateDiffDurationPipe, DateFormatPipe, DateFormatService, DateFromNowPipe, DateShortTestPage, DateTestPage, DateTimeTestPage, DateUtils, DebugComponent, Department, DepartmentToStringPipe, DisplayWithPipe, DragAndDropDirective, DurationPipe, DurationTestPage, ED25519_SEED_LENGTH, EMPTY_PLACEHOLDER_CHAR, EMPTY_PLACEHOLDER_CHAR_REGEXP_GLOBAL, ENTITIES_STORAGE_KEY_PREFIX, ENVIRONMENT, EmptyArrayPipe, EntitiesAsyncTableDataSource, EntitiesStorage, EntitiesTableDataSource, Entity, EntityClass, EntityClasses, EntityFilter, EntityFilterUtils, EntityMetadataComponent, EntityStore, EntityUtils, Environment, EnvironmentHttpLoader, EnvironmentLoader, ErrorCodes, EvenPipe, FeedDirective, FeedModule, FeedService, FeedsComponent, FileResponse, FileService, FileSizePipe, FilesUtils, FirstFalsePipe, FirstPipe, FirstTruePipe, FormArrayHelper, FormArrayTestModule, FormButtonsBarComponent, FormButtonsBarToken, FormErrorPipe, FormErrorTranslatePipe, FormErrorTranslator, FormFieldDefinitionUtils, FormFieldValuesHolder, FormGetArrayPipe, FormGetControlPipe, FormGetGroupPipe, FormGetPipe, FormGetValuePipe, GalleryTestPage, GeolocationUtils, GraphqlService, HAMMER_PRESS_TIME, HAMMER_TAP_TIME, HighlightPipe, HomePage, Hotkeys, HotkeysDialogComponent, IMAGE_DEFAULTS, IPosition, ImageAttachment, ImageAttachmentFilter, ImageAttachmentService, ImageGalleryModule, ImageGalleryTestingModule, ImageModule, ImageService, ImagesUtils, InMemoryEntitiesService, IsAllSelectedPipe, IsEmptySelectionPipe, IsLoginAccountPipe, IsMultipleSelectionPipe, IsNilOrBlankPipe, IsNilOrNaNPipe, IsNilPipe, IsNotAllSelectedPipe, IsNotEmptySelectionPipe, IsNotNilOrBlankPipe, IsNotNilOrNaNPipe, IsNotNilPipe, IsOnDeskPipe, IsOnFieldPipe, IsSelectedPipe, IsSingleSelectionPipe, IsValidDatePipe, JobModule, JobProgression, JobProgressionComponent, JobProgressionIcon, JobProgressionList, JobProgressionService, JobProgressionTestService, JobProgressionTestingPage, JobTestingModule, JobUtils, JsonFeedUtils, JsonUtils, KEYBOARD_HIDE_DELAY_MS, LAT_LONG_PATTERNS, LAT_LONG_PATTERN_MAX_DECIMALS, LAT_LONG_VALUE_MAX_DECIMALS, LatLongFormatPipe, LatLongTestPage, LatitudeFormatPipe, LocalSettingsService, LogLevel, LogUtils, Logger, LoggingService, LoggingServiceModule, LongitudeFormatPipe, MASKS, MASK_RANGES, MAT_FORM_FIELD_DEFAULT_APPEARANCE, MAT_FORM_FIELD_DEFAULT_SUBSCRIPT_SIZING, MINIFY_ENTITY_FOR_LOCAL_STORAGE, MINIFY_ENTITY_FOR_POD, MOMENT_NO_TIME_PROPERTY, MapGetPipe, MapKeysPipe, MapPipe, MapValuesPipe, MarkdownDirective, MarkdownService, MarkdownTestPage, MarkdownTestingModule, MarkdownUtils, MaskitoPlaceholderPipe, MaskitoTestPage, MatAutocompleteConfigHolder, MatAutocompleteField, MatAutocompleteFieldUtils, MatBadgeTestPage, MatBooleanField, MatChipsField, MatColorPipe, MatCommonTestPage, MatDate, MatDateShort, MatDateTime, MatDuration, MatLatLongField, MatLatLongFieldInput, MatPaginatorI18n, MatStepperI18n, MatSwipeField, MaterialTestingModule, MathAbsPipe, MenuComponent, MenuItem, MenuItems, MenuOptions, MenuService, MenuTestingModule, MenuTestingPage, Message, MessageFilter, MessageForm, MessageModal, MessageModule, MessageService, MessageTypeList, MessageTypes, MimeTypes, ModalToolbarComponent, NETWORK_DEFAULT_CONNECTION_TIMEOUT, NamedFilter, NamedFilterFilter, NamedFilterSelector, NamedFilterSelectorTestingModule, NamedFilterSelectorTestingPage, NavActionsColumnComponent, NetworkService, NetworkUtils, NewTokenForm, NewTokenModal, NgInitDirective, NgVarDirective, NoHtmlPipe, NotEmptyArrayPipe, NumberFormatPipe, ObservableTestPage, OddPipe, OtherMenuTestingPage, PEER_URL_REGEXP, PLUS_PLACEHOLDER_CHAR_REGEXP_GLOBAL, PRINT_ID_QUERY_PARAM, PRINT_LOADING_STORAGE_KEY_PREFIX, PRIORITIZED_AUTHORITIES, PUBKEY_REGEXP, Peer, Person, PersonFilter, PersonFragments, PersonService, PersonToStringPipe, PersonUtils, PersonValidatorService, PlatformService, PrintService, ProgressBarService, ProgressInterceptor, PropertiesFormTestPage, PropertiesFormTestingModule, PropertyEntity, PropertyEntityFilter, PropertyEntityValidator, PropertyFormatPipe, PropertyGetPipe, RESERVED_END_COLUMNS, RESERVED_START_COLUMNS, Referential, ReferentialFilter, ReferentialRef, ReferentialToStringPipe, ReferentialUtils, ReferentialValidatorService, RegExpUtils, RegisterConfirmPage, RegisterForm, RegisterModal, ResizableComponent, ResizableDirective, ResizableModule, RoundPipe, RxStateComputed, RxStateModule, RxStateProperty, RxStateRegister, RxStateSelect, SCRYPT_PARAMS, SETTINGS_COMPACT_ROWS, SETTINGS_DISPLAY_COLUMNS, SETTINGS_FILTER, SETTINGS_PAGE_SIZE, SETTINGS_SORTED_COLUMN, SETTINGS_STORAGE_KEY, SETTINGS_TRANSIENT_PROPERTIES, SHARED_MATERIAL_TESTING_PAGES, SHARED_STORAGE_TESTING_PAGES, SHARED_TESTING_PAGES, SOCIAL_CONFIG_OPTIONS, SOCIAL_TESTING_PAGES, SPACE_PLACEHOLDER_CHAR, SPACE_PLACEHOLDER_CHAR_REGEXP_GLOBAL, SafeHtmlPipe, SafeStylePipe, SelectPeerModal, SelectionLengthPipe, ServerErrorCodes, SettingsPage, SharedAsyncValidators, SharedBadgeModule, SharedDebugModule, SharedDirectivesModule, SharedFormArrayValidators, SharedFormGroupValidators, SharedHotkeysModule, SharedMarkdownModule, SharedMatAutocompleteModule, SharedMatBooleanModule, SharedMatChipsModule, SharedMatDateTimeModule, SharedMatDurationModule, SharedMatLatLongModule, SharedMatSwipeModule, SharedMaterialModule, SharedModule, SharedNamedFilterModule, SharedPipesModule, SharedRoutingModule, SharedTestingModule, SharedTestsPage, SharedTextFormModule, SharedToolbarModule, SharedValidators, SocialErrorCodes, SocialModule, SocialModuleOptionsToken, SocialTestingModule, Software, SplitArrayInChunksPipe, StartableService, StatusById, StatusIds, StatusList, StorageDrivers, StorageExplorerComponent, StorageExplorerModule, StorageExplorerTestingModule, StorageExplorerTestingRoutingModule, StorageService, StrIncludesPipe, StrLengthPipe, StrReplacePipe, SubMenuTabDirective, SwipeTestPage, TABLE_SETTINGS_ENUM, TOOLBAR_HEADER_ID, Table2TestPage, TableSelectColumnsComponent, TableTestPage, TableTestingModule, TableValidatorService, TextForm, TextFormTestingPage, TextPopover, TextPopoverTestingModule, TextPopoverTestingPage, ThrottledClickDirective, ToStringPipe, ToastTestingModule, ToastTestingPage, Toasts, TokenScope, ToolbarComponent, ToolbarToken, TranslatablePipe, TranslateContextPipe, TranslateContextService, TreeItemEntityUtils, TruncHtmlPipe, TruncTextPipe, UploadFile, UploadFileComponent, UploadFilePopover, UploadFileTestingModule, UploadFileTestingPage, UriUtils, UrlUtils, UserEventModule, UserEventNotificationIcon, UserEventNotificationList, UserEventNotificationModal, UserEventTestService, UserEventTestingModule, UserEventTestingPage, UserSettings, UserToken, UserTokenTable, UsersPage, ValueFormatPipe, VersionUtils, accountToString, adaptValueToControl, addValueInArray, arrayDistinct, arrayResize, arraySize, asInputElement, booleanToString, canHaveFocus, capitalizeFirstLetter, chainPromises, changeCaseToUnderscore, clearValueInArray, collectByProperty, compareVersionNumbers, computeDecimalDegrees, computeDecimalPart, copyEntity2Form, createPromiseEvent, createPromiseEventEmitter, departmentToString, departmentsToString, disableAndClearControl, disableAndClearControls, disableControl, disableControls, emitPromiseEvent, enableControl, enableControls, enableRxStateProdMode, entityToString, equals, equalsOrNil, escapeRegExp, expansionAnimation, fadeInAnimation, fadeInOutAnimation, fadeInSlowAnimation, filterFalse, filterFormErrors, filterFormErrorsByPath, filterFormErrorsByPrefix, filterNotNil, filterNumberInput, filterTrue, findParentWithClass, firstArrayValue, firstFalse, firstFalsePromise, firstNotNil, firstNotNilPromise, firstTrue, firstTruePromise, focusInput, focusNextInput, focusPreviousInput, formatLatLong, formatLatitude, formatLongitude, fromDateISOString, fromScrollEndEvent, fromUnixMsTimestamp, fromUnixTimestamp, getCaretPosition, getColorContrast, getColorShade, getColorTint, getControlFromPath, getFocusableInputElements, getFormErrors, getFormValueFromEntity, getInputRangeFromCaretIndex, getInputSelectionRangesFromMask, getProperty, getPropertyByPath, getPropertyByPathAsString, getRandomImage, getRandomImageWithCredit, getUserAgent, hexToRgb, hexToRgbArray, initArrayControlsFromValues, interpolateString, intersectArrays, isAndroid, isBlankString, isCapacitor, isChrome, isControlHasInput, isEdge, isEmptyArray, isEntityService, isFirefox, isIOS, isInputElement, isInstanceOf, isInt, isIpad, isMacOS, isMobile, isNil, isNilOrBlank, isNilOrNaN, isNotEmptyArray, isNotNil, isNotNilBoolean, isNotNilObject, isNotNilOrBlank, isNotNilOrNaN, isNotNilString, isNumber, isNumberRange, isOnFieldMode, isPrint, isProgressEvent, isPromise, isResponseEvent, isSafari, isSameVersion, isStartableService, isTouchUi, isVersionCompatible, isWindows, joinProperties, joinPropertiesPath, lastArrayValue, logFormErrors, markAllAsTouched, markAsUntouched, markControlAsTouched, markFormGroupAsTouched, maskitoAutoSelectByMaskPattern, maskitoPrefixPlugin, matchMedia, matchUpperCase, mergeLoadResult, mixHex, moveInputCaretToSeparator, newArray, noHtml, noTrailingSlash, notNilOrDefault, nullIfNilOrBlank, nullIfUndefined, numberOrNilAttribute, numberToString, parseLatitudeOrLongitude, propertiesPathComparator, propertyComparator, propertyPathComparator, referentialToString, referentialsToString, remove, removeAll, removeDiacritics, removeDuplicatesFromArray, removeEnd, removeValueInArray, replaceAll, resetCalculatedValue, resizeArray, rgbArrayToHex, rgbToHex, round, scrollFactory, selectInputContent, selectInputContentFromEvent, selectInputRange, setCalculatedValue, setControlEnabled, setControlsEnabled, setFormErrors, setPropertyByPath, setTabIndex, sleep, slideDownAnimation, slideInAnimation, slideInOutAnimation, slideUpDownAnimation, sort, splitArrayInChunks, splitById, splitByProperty, splitDegreesToDDArray, splitDegreesToDDMMArray, splitDegreesToDDMMSSArray, startsWithUpperCase, suggestFromArray, suggestFromStringArray, tabindexComparator, testUserAgent, toBoolean, toDateISOString, toDuration, toFloat, toInt, toNotNil, toNumber, trimEmptyToNull, uncapitalizeFirstLetter, undefinedIfNull, underscoreToChangeCase, updateValueAndValidity, waitFor, waitForFalse, waitForTrue, waitIdle, waitWhilePending };
49902
49730
  //# sourceMappingURL=sumaris-net.ngx-components.mjs.map