@sumaris-net/ngx-components 18.16.7 → 18.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/doc/changelog.md +11 -2
- package/esm2022/public_api.mjs +5 -4
- package/esm2022/src/app/admin/users/person.filter.mjs +76 -0
- package/esm2022/src/app/admin/users/person.service.mjs +197 -0
- package/esm2022/src/app/admin/users/person.validator.mjs +72 -0
- package/esm2022/src/app/admin/users/users.mjs +4 -4
- package/esm2022/src/app/core/about/about.modal.mjs +5 -5
- package/esm2022/src/app/core/home/home.mjs +3 -3
- package/esm2022/src/app/core/services/account.service.mjs +8 -2
- package/esm2022/src/app/core/services/network.service.mjs +7 -4
- package/esm2022/src/app/core/services/validator/account.validator.mjs +2 -2
- package/esm2022/src/app/shared/validator/validators.mjs +3 -3
- package/esm2022/src/app/social/feed/feed.component.mjs +180 -33
- package/esm2022/src/app/social/feed/feed.model.mjs +1 -1
- package/esm2022/src/app/social/feed/feed.module.mjs +5 -4
- package/esm2022/src/app/social/feed/feed.page.mjs +67 -0
- package/esm2022/src/app/social/feed/feed.service.mjs +64 -13
- package/esm2022/src/app/social/feed/testing/feed.testing.mjs +3 -3
- package/esm2022/src/app/social/message/message.form.mjs +8 -5
- package/esm2022/src/app/social/message/message.modal.mjs +10 -4
- package/esm2022/src/app/social/message/message.model.mjs +2 -2
- package/esm2022/src/app/social/message/message.module.mjs +5 -4
- package/esm2022/src/app/social/message/message.service.mjs +81 -1
- package/esm2022/src/app/social/social.errors.mjs +2 -1
- package/esm2022/src/app/social/social.testing.module.mjs +7 -1
- package/esm2022/src/environments/environment.mjs +5 -2
- package/fesm2022/sumaris-net.ngx-components.mjs +1029 -671
- package/fesm2022/sumaris-net.ngx-components.mjs.map +1 -1
- package/package.json +1 -1
- package/public_api.d.ts +4 -3
- package/src/app/admin/{services/filter → users}/person.filter.d.ts +4 -4
- package/src/app/admin/{services → users}/person.service.d.ts +2 -1
- package/src/app/admin/{services/validator → users}/person.validator.d.ts +4 -4
- package/src/app/admin/users/users.d.ts +2 -2
- package/src/app/core/services/account.service.d.ts +2 -0
- package/src/app/core/services/network.service.d.ts +3 -2
- package/src/app/core/services/validator/account.validator.d.ts +1 -1
- package/src/app/social/feed/feed.component.d.ts +49 -13
- package/src/app/social/feed/feed.model.d.ts +3 -2
- package/src/app/social/feed/feed.module.d.ts +7 -6
- package/src/app/social/feed/feed.page.d.ts +24 -0
- package/src/app/social/feed/feed.service.d.ts +37 -24
- package/src/app/social/message/message.form.d.ts +3 -3
- package/src/app/social/message/message.modal.d.ts +6 -2
- package/src/app/social/message/message.model.d.ts +1 -1
- package/src/app/social/message/message.module.d.ts +2 -1
- package/src/app/social/message/message.service.d.ts +12 -0
- package/src/app/social/social.errors.d.ts +1 -0
- package/src/assets/i18n/en-US.json +7 -3
- package/src/assets/i18n/en.json +5 -2
- package/src/assets/i18n/fr.json +5 -2
- package/src/assets/manifest.json +1 -1
- package/src/theme/_ngx-components.forms.scss +1 -0
- package/src/theme/_ngx-components.table.scss +1 -0
- package/esm2022/src/app/admin/services/filter/person.filter.mjs +0 -76
- package/esm2022/src/app/admin/services/person.service.mjs +0 -184
- package/esm2022/src/app/admin/services/validator/person.validator.mjs +0 -72
|
@@ -1,7 +1,7 @@
|
|
|
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
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
|
-
import { catchError, map, filter, takeUntil, first, switchMap, tap as tap$1, throttleTime, debounceTime, startWith, distinctUntilChanged, mergeMap, skip, finalize,
|
|
4
|
+
import { catchError, map, filter, takeUntil, first, switchMap, tap as tap$1, throttleTime, debounceTime, startWith, distinctUntilChanged, mergeMap, skip, finalize, distinctUntilKeyChanged, bufferWhen, take } from 'rxjs/operators';
|
|
5
5
|
import * as cloneImported from 'clone';
|
|
6
6
|
import * as i3$1 from '@angular/common';
|
|
7
7
|
import { CommonModule, DOCUMENT, LocationStrategy, Location, AsyncPipe, JsonPipe } from '@angular/common';
|
|
@@ -2871,14 +2871,14 @@ class SharedValidators {
|
|
|
2871
2871
|
}
|
|
2872
2872
|
static entity(control) {
|
|
2873
2873
|
const value = control.value;
|
|
2874
|
-
if (value && (typeof value !== 'object' || value.id
|
|
2874
|
+
if (value && (typeof value !== 'object' || isNil(value.id))) {
|
|
2875
2875
|
return { entity: true };
|
|
2876
2876
|
}
|
|
2877
2877
|
return null;
|
|
2878
2878
|
}
|
|
2879
2879
|
static entities(control) {
|
|
2880
2880
|
const value = control.value;
|
|
2881
|
-
if (value && (!Array.isArray(value) || value.every((e) => e?.id
|
|
2881
|
+
if (value && (!Array.isArray(value) || value.every((e) => isNil(e?.id)))) {
|
|
2882
2882
|
return { entity: true };
|
|
2883
2883
|
}
|
|
2884
2884
|
return null;
|
|
@@ -13142,7 +13142,10 @@ const environment = Object.freeze({
|
|
|
13142
13142
|
// Example with discourse API :
|
|
13143
13143
|
//'https://raw.githubusercontent.com/duniter/cesium/master/doc/feed/1.1/feed-fr-FR.json',
|
|
13144
13144
|
],
|
|
13145
|
-
en: [
|
|
13145
|
+
en: [
|
|
13146
|
+
'/api/feed.json',
|
|
13147
|
+
'https://gitlab.ifremer.fr/sih-public/sumaris/ngx-sumaris-components/-/raw/master/doc/feed/feed-en.json'
|
|
13148
|
+
],
|
|
13146
13149
|
},
|
|
13147
13150
|
maxContentLength: 1000,
|
|
13148
13151
|
maxAgeInMonths: -1,
|
|
@@ -19713,6 +19716,9 @@ class NetworkService extends StartableObservableService {
|
|
|
19713
19716
|
get connectionParams() {
|
|
19714
19717
|
return this._connectionParams;
|
|
19715
19718
|
}
|
|
19719
|
+
get peer$() {
|
|
19720
|
+
return this.dataSubject.pipe(distinctUntilKeyChanged('url'));
|
|
19721
|
+
}
|
|
19716
19722
|
constructor(_document, platform, modalCtrl, storage, settings, cache, http, environment, loggingService, translate, toastController) {
|
|
19717
19723
|
super(platform);
|
|
19718
19724
|
this._document = _document;
|
|
@@ -20283,7 +20289,7 @@ class NetworkService extends StartableObservableService {
|
|
|
20283
20289
|
if (!uri.startsWith('http://') && !uri.startsWith('https://')) {
|
|
20284
20290
|
let peerUrl = this.peer?.url;
|
|
20285
20291
|
// Remove trailing slash
|
|
20286
|
-
if (peerUrl
|
|
20292
|
+
if (peerUrl?.endsWith('/')) {
|
|
20287
20293
|
peerUrl = peerUrl.substring(0, peerUrl.length - 1);
|
|
20288
20294
|
}
|
|
20289
20295
|
// Add first path
|
|
@@ -20291,7 +20297,7 @@ class NetworkService extends StartableObservableService {
|
|
|
20291
20297
|
path = '/' + path;
|
|
20292
20298
|
}
|
|
20293
20299
|
// Create the URI: concat peer URL and path
|
|
20294
|
-
uri = peerUrl + path;
|
|
20300
|
+
uri = (peerUrl ?? '') + path;
|
|
20295
20301
|
}
|
|
20296
20302
|
return uri;
|
|
20297
20303
|
}
|
|
@@ -23014,7 +23020,7 @@ const Fragments = {
|
|
|
23014
23020
|
`,
|
|
23015
23021
|
};
|
|
23016
23022
|
// Account queries
|
|
23017
|
-
const Queries = {
|
|
23023
|
+
const Queries$1 = {
|
|
23018
23024
|
load: gql `
|
|
23019
23025
|
query Account {
|
|
23020
23026
|
data: account {
|
|
@@ -23176,12 +23182,18 @@ class AccountService extends BaseGraphqlService {
|
|
|
23176
23182
|
get account() {
|
|
23177
23183
|
return this._cache.loaded ? this._data : undefined;
|
|
23178
23184
|
}
|
|
23185
|
+
get account$() {
|
|
23186
|
+
return this.onChange.asObservable().pipe(startWith(this.account));
|
|
23187
|
+
}
|
|
23179
23188
|
get person() {
|
|
23180
23189
|
if (this._cache.loaded && !this._cache.person) {
|
|
23181
23190
|
this._cache.person = this._cache.loaded ? this._data.asPerson() : undefined;
|
|
23182
23191
|
}
|
|
23183
23192
|
return this._cache.person;
|
|
23184
23193
|
}
|
|
23194
|
+
get person$() {
|
|
23195
|
+
return this.onChange.asObservable().pipe(map(() => this.person), startWith(this.person));
|
|
23196
|
+
}
|
|
23185
23197
|
get department() {
|
|
23186
23198
|
if (this._cache.loaded && !this._cache.department) {
|
|
23187
23199
|
this._cache.department = this._cache.loaded ? this._data.asPerson().department : undefined;
|
|
@@ -23610,7 +23622,7 @@ class AccountService extends BaseGraphqlService {
|
|
|
23610
23622
|
}
|
|
23611
23623
|
// Load remotely
|
|
23612
23624
|
else {
|
|
23613
|
-
const query = opts?.query || (this.apiTokenEnabled ? Queries.loadWithTokens : Queries.load);
|
|
23625
|
+
const query = opts?.query || (this.apiTokenEnabled ? Queries$1.loadWithTokens : Queries$1.load);
|
|
23614
23626
|
const { data } = await this.graphql.query({
|
|
23615
23627
|
query,
|
|
23616
23628
|
error: { code: ErrorCodes.LOAD_ACCOUNT_ERROR, message: 'ERROR.LOAD_ACCOUNT_ERROR' },
|
|
@@ -30020,10 +30032,10 @@ class AboutModal {
|
|
|
30020
30032
|
}
|
|
30021
30033
|
/* -- protected functions -- */
|
|
30022
30034
|
setConfig(config) {
|
|
30023
|
-
this.forumUrl = config?.getProperty(CORE_CONFIG_OPTIONS.FORUM_URL) || this.environment
|
|
30024
|
-
this.helpUrl = config?.getProperty(CORE_CONFIG_OPTIONS.HELP_URL) || this.environment
|
|
30025
|
-
this.reportIssueUrl = config?.getProperty(CORE_CONFIG_OPTIONS.REPORT_ISSUE_URL) || this.environment
|
|
30026
|
-
this.buildDate = this.environment
|
|
30035
|
+
this.forumUrl = config?.getProperty(CORE_CONFIG_OPTIONS.FORUM_URL) || this.environment?.forumUrl;
|
|
30036
|
+
this.helpUrl = config?.getProperty(CORE_CONFIG_OPTIONS.HELP_URL) || this.environment?.helpUrl;
|
|
30037
|
+
this.reportIssueUrl = config?.getProperty(CORE_CONFIG_OPTIONS.REPORT_ISSUE_URL) || this.environment?.reportIssueUrl;
|
|
30038
|
+
this.buildDate = this.environment?.buildDate;
|
|
30027
30039
|
}
|
|
30028
30040
|
async loadNodeInfo() {
|
|
30029
30041
|
this.nodeInfo = await this.getNodeInfo();
|
|
@@ -32720,6 +32732,7 @@ const SocialErrorCodes = {
|
|
|
32720
32732
|
SAVE_USER_EVENT_ERROR: 50001,
|
|
32721
32733
|
COUNT_USER_EVENT_ERROR: 50002,
|
|
32722
32734
|
SEND_MESSAGE_ERROR: 50003,
|
|
32735
|
+
DELETE_MESSAGE_ERROR: 50004,
|
|
32723
32736
|
SUBSCRIBE_USER_EVENTS_ERROR: 50005,
|
|
32724
32737
|
SUBSCRIBE_JOB_PROGRESSION_ERROR: 50010,
|
|
32725
32738
|
LOAD_JOB_PROGRESSIONS_ERROR: 50011,
|
|
@@ -33781,6 +33794,725 @@ class JsonFeedUtils {
|
|
|
33781
33794
|
}
|
|
33782
33795
|
}
|
|
33783
33796
|
|
|
33797
|
+
var PersonFilter_1;
|
|
33798
|
+
// @dynamic
|
|
33799
|
+
let PersonFilter = class PersonFilter extends EntityFilter {
|
|
33800
|
+
static { PersonFilter_1 = this; }
|
|
33801
|
+
static fromObject;
|
|
33802
|
+
static searchFilter(source) {
|
|
33803
|
+
return source && PersonFilter_1.fromObject(source).asFilterFn();
|
|
33804
|
+
}
|
|
33805
|
+
email;
|
|
33806
|
+
pubkey;
|
|
33807
|
+
searchText;
|
|
33808
|
+
statusIds;
|
|
33809
|
+
userProfiles;
|
|
33810
|
+
includedIds;
|
|
33811
|
+
excludedIds;
|
|
33812
|
+
searchAttribute;
|
|
33813
|
+
searchAttributes;
|
|
33814
|
+
constructor() {
|
|
33815
|
+
super(PersonFilter_1.TYPENAME);
|
|
33816
|
+
}
|
|
33817
|
+
fromObject(source, opts) {
|
|
33818
|
+
super.fromObject(source, opts);
|
|
33819
|
+
this.email = source.email;
|
|
33820
|
+
this.pubkey = source.pubkey;
|
|
33821
|
+
this.searchText = source.searchText;
|
|
33822
|
+
this.statusIds = source.statusIds || (isNotNil(source.statusId) ? [source.statusId] : undefined);
|
|
33823
|
+
this.userProfiles = source.userProfiles;
|
|
33824
|
+
this.excludedIds = source.excludedIds;
|
|
33825
|
+
this.searchAttribute = source.searchAttribute;
|
|
33826
|
+
this.searchAttributes = source.searchAttributes;
|
|
33827
|
+
}
|
|
33828
|
+
asObject(opts) {
|
|
33829
|
+
const target = super.asObject(opts);
|
|
33830
|
+
target.email = this.email;
|
|
33831
|
+
target.pubkey = this.pubkey;
|
|
33832
|
+
target.searchText = this.searchText;
|
|
33833
|
+
target.statusIds = this.statusIds;
|
|
33834
|
+
target.userProfiles = this.userProfiles;
|
|
33835
|
+
target.excludedIds = this.excludedIds;
|
|
33836
|
+
target.searchAttribute = this.searchAttribute;
|
|
33837
|
+
target.searchAttributes = this.searchAttributes;
|
|
33838
|
+
return target;
|
|
33839
|
+
}
|
|
33840
|
+
buildFilter() {
|
|
33841
|
+
const filterFns = super.buildFilter();
|
|
33842
|
+
// Filter by status
|
|
33843
|
+
if (isNotEmptyArray(this.statusIds)) {
|
|
33844
|
+
filterFns.push((e) => this.statusIds.includes(e.statusId));
|
|
33845
|
+
}
|
|
33846
|
+
// Filter included ids
|
|
33847
|
+
const includedIds = this.includedIds;
|
|
33848
|
+
if (isNotEmptyArray(includedIds)) {
|
|
33849
|
+
filterFns.push((e) => isNotNil(e.id) && includedIds.includes(e.id));
|
|
33850
|
+
}
|
|
33851
|
+
// Filter excluded ids
|
|
33852
|
+
const excludedIds = this.excludedIds;
|
|
33853
|
+
if (isNotEmptyArray(excludedIds)) {
|
|
33854
|
+
filterFns.push((e) => isNil(e.id) || !excludedIds.includes(e.id));
|
|
33855
|
+
}
|
|
33856
|
+
// Search text
|
|
33857
|
+
const searchTextFilter = EntityUtils.searchTextFilter(this.searchAttribute || this.searchAttributes || ['lastName', 'firstName', 'department.name'], this.searchText);
|
|
33858
|
+
if (searchTextFilter)
|
|
33859
|
+
filterFns.push(searchTextFilter);
|
|
33860
|
+
return filterFns;
|
|
33861
|
+
}
|
|
33862
|
+
};
|
|
33863
|
+
PersonFilter = PersonFilter_1 = __decorate([
|
|
33864
|
+
EntityClass({ typename: 'PersonFilterVO' })
|
|
33865
|
+
], PersonFilter);
|
|
33866
|
+
|
|
33867
|
+
const MessageTypes = {
|
|
33868
|
+
INBOX_MESSAGE: 'INBOX_MESSAGE',
|
|
33869
|
+
EMAIL: 'EMAIL',
|
|
33870
|
+
FEED: 'FEED',
|
|
33871
|
+
};
|
|
33872
|
+
const MessageTypeList = Object.freeze([
|
|
33873
|
+
{
|
|
33874
|
+
id: MessageTypes.INBOX_MESSAGE,
|
|
33875
|
+
icon: 'notifications',
|
|
33876
|
+
label: 'SOCIAL.MESSAGE.TYPE_ENUM.INBOX_MESSAGE',
|
|
33877
|
+
},
|
|
33878
|
+
{
|
|
33879
|
+
id: MessageTypes.EMAIL,
|
|
33880
|
+
icon: 'mail',
|
|
33881
|
+
label: 'SOCIAL.MESSAGE.TYPE_ENUM.EMAIL',
|
|
33882
|
+
},
|
|
33883
|
+
{
|
|
33884
|
+
id: MessageTypes.FEED,
|
|
33885
|
+
icon: 'megaphone',
|
|
33886
|
+
label: 'SOCIAL.MESSAGE.TYPE_ENUM.FEED',
|
|
33887
|
+
},
|
|
33888
|
+
]);
|
|
33889
|
+
// @dynamic
|
|
33890
|
+
let Message = class Message extends Entity {
|
|
33891
|
+
static fromObject;
|
|
33892
|
+
type;
|
|
33893
|
+
issuer;
|
|
33894
|
+
recipients;
|
|
33895
|
+
recipientFilter;
|
|
33896
|
+
subject;
|
|
33897
|
+
body;
|
|
33898
|
+
constructor() {
|
|
33899
|
+
super();
|
|
33900
|
+
}
|
|
33901
|
+
fromObject(source, opts) {
|
|
33902
|
+
super.fromObject(source, opts);
|
|
33903
|
+
this.type = source.type;
|
|
33904
|
+
this.issuer = source.issuer && Person.fromObject(source.issuer);
|
|
33905
|
+
this.recipients = source.recipients && source.recipients.map(Person.fromObject);
|
|
33906
|
+
this.recipientFilter = (source.recipientFilter && PersonFilter.fromObject(source.recipientFilter)) || undefined;
|
|
33907
|
+
this.subject = source.subject;
|
|
33908
|
+
this.body = source.body;
|
|
33909
|
+
}
|
|
33910
|
+
asObject(opts) {
|
|
33911
|
+
const target = super.asObject(opts);
|
|
33912
|
+
target.recipients = this.recipients && this.recipients.map((p) => p.asObject(opts));
|
|
33913
|
+
target.recipientFilter = (this.recipientFilter && this.recipientFilter.asObject(opts)) || undefined;
|
|
33914
|
+
return target;
|
|
33915
|
+
}
|
|
33916
|
+
};
|
|
33917
|
+
Message = __decorate([
|
|
33918
|
+
EntityClass({ typename: 'MessageVO' })
|
|
33919
|
+
], Message);
|
|
33920
|
+
// @dynamic
|
|
33921
|
+
let MessageFilter = class MessageFilter extends EntityFilter {
|
|
33922
|
+
static fromObject;
|
|
33923
|
+
fromObject(source, opts) {
|
|
33924
|
+
super.fromObject(source, opts);
|
|
33925
|
+
}
|
|
33926
|
+
buildFilter() {
|
|
33927
|
+
return super.buildFilter();
|
|
33928
|
+
}
|
|
33929
|
+
};
|
|
33930
|
+
MessageFilter = __decorate([
|
|
33931
|
+
EntityClass({ typename: 'MessageFilterVO' })
|
|
33932
|
+
], MessageFilter);
|
|
33933
|
+
|
|
33934
|
+
const PersonFragments = {
|
|
33935
|
+
person: gql$1 `
|
|
33936
|
+
fragment PersonFragment on PersonVO {
|
|
33937
|
+
id
|
|
33938
|
+
firstName
|
|
33939
|
+
lastName
|
|
33940
|
+
email
|
|
33941
|
+
pubkey
|
|
33942
|
+
avatar
|
|
33943
|
+
statusId
|
|
33944
|
+
updateDate
|
|
33945
|
+
creationDate
|
|
33946
|
+
profiles
|
|
33947
|
+
username
|
|
33948
|
+
usernameExtranet
|
|
33949
|
+
department {
|
|
33950
|
+
id
|
|
33951
|
+
label
|
|
33952
|
+
name
|
|
33953
|
+
logo
|
|
33954
|
+
__typename
|
|
33955
|
+
}
|
|
33956
|
+
__typename
|
|
33957
|
+
}
|
|
33958
|
+
`,
|
|
33959
|
+
personFilter: gql$1 `
|
|
33960
|
+
fragment PersonFilterFragment on PersonFilterVO {
|
|
33961
|
+
email
|
|
33962
|
+
pubkey
|
|
33963
|
+
searchText
|
|
33964
|
+
statusIds
|
|
33965
|
+
userProfiles
|
|
33966
|
+
includedIds
|
|
33967
|
+
excludedIds
|
|
33968
|
+
searchAttribute
|
|
33969
|
+
searchAttributes
|
|
33970
|
+
}
|
|
33971
|
+
`,
|
|
33972
|
+
};
|
|
33973
|
+
// Load persons query
|
|
33974
|
+
const PersonQueries = {
|
|
33975
|
+
loadAll: gql$1 `
|
|
33976
|
+
query Persons($offset: Int, $size: Int, $sortBy: String, $sortDirection: String, $filter: PersonFilterVOInput) {
|
|
33977
|
+
data: persons(filter: $filter, offset: $offset, size: $size, sortBy: $sortBy, sortDirection: $sortDirection) {
|
|
33978
|
+
...PersonFragment
|
|
33979
|
+
}
|
|
33980
|
+
}
|
|
33981
|
+
${PersonFragments.person}
|
|
33982
|
+
`,
|
|
33983
|
+
loadAllWithTotal: gql$1 `
|
|
33984
|
+
query PersonsWithTotal($offset: Int, $size: Int, $sortBy: String, $sortDirection: String, $filter: PersonFilterVOInput) {
|
|
33985
|
+
data: persons(filter: $filter, offset: $offset, size: $size, sortBy: $sortBy, sortDirection: $sortDirection) {
|
|
33986
|
+
...PersonFragment
|
|
33987
|
+
}
|
|
33988
|
+
total: personsCount(filter: $filter)
|
|
33989
|
+
}
|
|
33990
|
+
${PersonFragments.person}
|
|
33991
|
+
`,
|
|
33992
|
+
};
|
|
33993
|
+
const PersonMutations = {
|
|
33994
|
+
saveAll: gql$1 `
|
|
33995
|
+
mutation savePersons($data: [PersonVOInput]) {
|
|
33996
|
+
data: savePersons(persons: $data) {
|
|
33997
|
+
...PersonFragment
|
|
33998
|
+
}
|
|
33999
|
+
}
|
|
34000
|
+
${PersonFragments.person}
|
|
34001
|
+
`,
|
|
34002
|
+
deleteAll: gql$1 `
|
|
34003
|
+
mutation deletePersons($ids: [Int]) {
|
|
34004
|
+
deletePersons(ids: $ids)
|
|
34005
|
+
}
|
|
34006
|
+
`,
|
|
34007
|
+
};
|
|
34008
|
+
class PersonService extends BaseEntityService {
|
|
34009
|
+
graphql;
|
|
34010
|
+
platform;
|
|
34011
|
+
network;
|
|
34012
|
+
entities;
|
|
34013
|
+
constructor(graphql, platform, network, entities) {
|
|
34014
|
+
super(graphql, platform, Person, PersonFilter, {
|
|
34015
|
+
queries: PersonQueries,
|
|
34016
|
+
mutations: PersonMutations,
|
|
34017
|
+
defaultSortBy: 'lastName',
|
|
34018
|
+
defaultSortDirection: 'asc',
|
|
34019
|
+
});
|
|
34020
|
+
this.graphql = graphql;
|
|
34021
|
+
this.platform = platform;
|
|
34022
|
+
this.network = network;
|
|
34023
|
+
this.entities = entities;
|
|
34024
|
+
// for DEV only -----
|
|
34025
|
+
this._debug = !environment.production;
|
|
34026
|
+
}
|
|
34027
|
+
async loadAll(offset, size, sortBy, sortDirection, filter, opts) {
|
|
34028
|
+
const offline = this.network.offline && (!opts || opts.fetchPolicy !== 'network-only');
|
|
34029
|
+
if (offline) {
|
|
34030
|
+
return this.loadAllLocally(offset, size, sortBy, sortDirection, filter, opts);
|
|
34031
|
+
}
|
|
34032
|
+
return super.loadAll(offset, size, sortBy, sortDirection, filter, opts);
|
|
34033
|
+
}
|
|
34034
|
+
async loadAllLocally(offset, size, sortBy, sortDirection, filter, opts) {
|
|
34035
|
+
filter = this.asFilter(filter);
|
|
34036
|
+
const variables = {
|
|
34037
|
+
offset: offset || 0,
|
|
34038
|
+
size: size || 100,
|
|
34039
|
+
sortBy: sortBy || this.defaultSortBy,
|
|
34040
|
+
sortDirection: sortDirection || this.defaultSortDirection,
|
|
34041
|
+
filter: filter && filter.asFilterFn(),
|
|
34042
|
+
};
|
|
34043
|
+
const { data, total } = await this.entities.loadAll('PersonVO', variables);
|
|
34044
|
+
const entities = this.fromObjects(data, opts);
|
|
34045
|
+
const res = { data: entities, total };
|
|
34046
|
+
// Add fetch more function
|
|
34047
|
+
const nextOffset = (offset || 0) + entities.length;
|
|
34048
|
+
if (nextOffset < total) {
|
|
34049
|
+
res.fetchMore = () => this.loadAllLocally(nextOffset, size, sortBy, sortDirection, filter, opts);
|
|
34050
|
+
}
|
|
34051
|
+
return res;
|
|
34052
|
+
}
|
|
34053
|
+
async suggest(value, filter, sortBy, sortDirection, opts) {
|
|
34054
|
+
if (EntityUtils.isNotEmpty(value, 'id'))
|
|
34055
|
+
return { data: [value] };
|
|
34056
|
+
value = (typeof value === 'string' && value !== '*' && value) || undefined;
|
|
34057
|
+
sortBy = sortBy || filter.searchAttribute || (filter.searchAttributes && filter.searchAttributes[0]);
|
|
34058
|
+
return this.loadAll(0, !value ? 30 : 10, sortBy, sortDirection, {
|
|
34059
|
+
...filter,
|
|
34060
|
+
searchText: value,
|
|
34061
|
+
statusIds: (filter && filter.statusIds) || [StatusIds.ENABLE, StatusIds.TEMPORARY],
|
|
34062
|
+
userProfiles: filter && filter.userProfiles,
|
|
34063
|
+
}, {
|
|
34064
|
+
withTotal: true /* need by autocomplete */,
|
|
34065
|
+
...opts,
|
|
34066
|
+
});
|
|
34067
|
+
}
|
|
34068
|
+
async executeImport(filter, opts) {
|
|
34069
|
+
const maxProgression = (opts && opts.maxProgression) || 100;
|
|
34070
|
+
filter = {
|
|
34071
|
+
...filter,
|
|
34072
|
+
statusIds: [StatusIds.ENABLE, StatusIds.TEMPORARY],
|
|
34073
|
+
userProfiles: ['SUPERVISOR', 'USER', 'GUEST'],
|
|
34074
|
+
};
|
|
34075
|
+
console.info('[person-service] Importing persons...');
|
|
34076
|
+
const res = await JobUtils.fetchAllPages((offset, size) => this.loadAll(offset, size, 'id', null, filter, {
|
|
34077
|
+
debug: false,
|
|
34078
|
+
fetchPolicy: 'network-only',
|
|
34079
|
+
withTotal: offset === 0, // Compute total only once
|
|
34080
|
+
toEntity: false,
|
|
34081
|
+
}), { progression: opts?.progression, maxProgression: maxProgression * 0.9 });
|
|
34082
|
+
// Save result locally
|
|
34083
|
+
await this.entities.saveAll(res.data, { entityName: 'PersonVO', reset: true });
|
|
34084
|
+
}
|
|
34085
|
+
async loadById(id, opts) {
|
|
34086
|
+
const { data } = await this.loadAll(0, 1, null, null, { includedIds: [id] }, { withTotal: false, ...opts });
|
|
34087
|
+
const source = isNotEmptyArray(data) ? data[0] : { id };
|
|
34088
|
+
return this.fromObject(source, opts);
|
|
34089
|
+
}
|
|
34090
|
+
async loadByPubkey(pubkey, opts) {
|
|
34091
|
+
const { data } = await this.loadAll(0, 1, null, null, { pubkey }, { withTotal: false, ...opts });
|
|
34092
|
+
const source = isNotEmptyArray(data) ? data[0] : { pubkey };
|
|
34093
|
+
return this.fromObject(source, opts);
|
|
34094
|
+
}
|
|
34095
|
+
/* -- protected methods -- */
|
|
34096
|
+
asObject(source) {
|
|
34097
|
+
if (!source)
|
|
34098
|
+
return undefined;
|
|
34099
|
+
if (!(source instanceof Person)) {
|
|
34100
|
+
source = Person.fromObject(source);
|
|
34101
|
+
}
|
|
34102
|
+
const target = source.asObject();
|
|
34103
|
+
// Not known in server GraphQL schema
|
|
34104
|
+
delete target.mainProfile;
|
|
34105
|
+
target.department = source.department?.asObject();
|
|
34106
|
+
return target;
|
|
34107
|
+
}
|
|
34108
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PersonService, deps: [{ token: GraphqlService }, { token: PlatformService }, { token: NetworkService }, { token: EntitiesStorage }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
34109
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PersonService, providedIn: 'root' });
|
|
34110
|
+
}
|
|
34111
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PersonService, decorators: [{
|
|
34112
|
+
type: Injectable,
|
|
34113
|
+
args: [{ providedIn: 'root' }]
|
|
34114
|
+
}], ctorParameters: () => [{ type: GraphqlService }, { type: PlatformService }, { type: NetworkService }, { type: EntitiesStorage }] });
|
|
34115
|
+
|
|
34116
|
+
class MessageForm extends AppForm {
|
|
34117
|
+
formBuilder;
|
|
34118
|
+
cd;
|
|
34119
|
+
mobile;
|
|
34120
|
+
suggestFn;
|
|
34121
|
+
subjectMinLength = 5;
|
|
34122
|
+
subjectMaxLength = 255;
|
|
34123
|
+
bodyMaxLength = 2000;
|
|
34124
|
+
bodyAutoHeight = true;
|
|
34125
|
+
canSelectType = false;
|
|
34126
|
+
canRecipientFilter = false;
|
|
34127
|
+
recipientFilterCount = 0;
|
|
34128
|
+
types = MessageTypeList;
|
|
34129
|
+
constructor(injector, formBuilder, cd) {
|
|
34130
|
+
super(injector);
|
|
34131
|
+
this.formBuilder = formBuilder;
|
|
34132
|
+
this.cd = cd;
|
|
34133
|
+
this.mobile = this.settings.mobile;
|
|
34134
|
+
}
|
|
34135
|
+
ngOnInit() {
|
|
34136
|
+
this.setForm(this.formBuilder.group({
|
|
34137
|
+
type: [MessageTypes.INBOX_MESSAGE, Validators.required],
|
|
34138
|
+
recipients: [null, Validators.required],
|
|
34139
|
+
recipientFilter: [null],
|
|
34140
|
+
subject: [
|
|
34141
|
+
null,
|
|
34142
|
+
this.subjectMaxLength
|
|
34143
|
+
? Validators.compose([Validators.required, Validators.minLength(this.subjectMinLength), Validators.maxLength(this.subjectMaxLength)])
|
|
34144
|
+
: Validators.required,
|
|
34145
|
+
],
|
|
34146
|
+
body: [null, this.bodyMaxLength ? Validators.compose([Validators.maxLength(this.bodyMaxLength)]) : Validators.required],
|
|
34147
|
+
}));
|
|
34148
|
+
this.registerSubscription(this._form
|
|
34149
|
+
.get('type')
|
|
34150
|
+
.valueChanges.pipe(filter(isNotNil))
|
|
34151
|
+
.subscribe((type) => this.updateFormGroup(this._form, { type })));
|
|
34152
|
+
// Person combo
|
|
34153
|
+
const personAttributes = this.settings.getFieldDisplayAttributes('person', ['lastName', 'firstName', 'department.name']);
|
|
34154
|
+
this.registerAutocompleteField('recipients', {
|
|
34155
|
+
showAllOnFocus: false,
|
|
34156
|
+
suggestFn: this.suggestFn,
|
|
34157
|
+
filter: {
|
|
34158
|
+
statusIds: [StatusIds.TEMPORARY, StatusIds.ENABLE],
|
|
34159
|
+
},
|
|
34160
|
+
attributes: personAttributes,
|
|
34161
|
+
columnNames: personAttributes.map((attr) => `USER.${changeCaseToUnderscore(attr).toUpperCase()}`),
|
|
34162
|
+
displayWith: PersonUtils.personToString,
|
|
34163
|
+
multiple: true,
|
|
34164
|
+
mobile: this.mobile,
|
|
34165
|
+
});
|
|
34166
|
+
}
|
|
34167
|
+
isSamePerson(o1, o2) {
|
|
34168
|
+
return EntityUtils.equals(o1, o2, 'id');
|
|
34169
|
+
}
|
|
34170
|
+
updateFormGroup(formGroup, opts) {
|
|
34171
|
+
console.debug('[message-form] Updating form group...', opts);
|
|
34172
|
+
// Recipient validator
|
|
34173
|
+
const recipientsRequired = toBoolean(opts?.recipientRequired, opts?.type !== MessageTypes.FEED);
|
|
34174
|
+
{
|
|
34175
|
+
const control = formGroup.get('recipients');
|
|
34176
|
+
if (recipientsRequired) {
|
|
34177
|
+
if (!control.hasValidator(Validators.required)) {
|
|
34178
|
+
control.addValidators(Validators.required);
|
|
34179
|
+
}
|
|
34180
|
+
control.enable();
|
|
34181
|
+
}
|
|
34182
|
+
else {
|
|
34183
|
+
if (control.hasValidator(Validators.required)) {
|
|
34184
|
+
control.removeValidators(Validators.required);
|
|
34185
|
+
}
|
|
34186
|
+
control.disable();
|
|
34187
|
+
}
|
|
34188
|
+
}
|
|
34189
|
+
// Recipient filter validator
|
|
34190
|
+
const recipientFilterRequired = this.canRecipientFilter && !recipientsRequired;
|
|
34191
|
+
{
|
|
34192
|
+
const control = formGroup.get('recipientFilter');
|
|
34193
|
+
if (recipientFilterRequired) {
|
|
34194
|
+
if (!control.hasValidator(Validators.required)) {
|
|
34195
|
+
control.addValidators(Validators.required);
|
|
34196
|
+
}
|
|
34197
|
+
control.enable();
|
|
34198
|
+
}
|
|
34199
|
+
else {
|
|
34200
|
+
if (control.hasValidator(Validators.required)) {
|
|
34201
|
+
control.removeValidators(Validators.required);
|
|
34202
|
+
}
|
|
34203
|
+
control.disable();
|
|
34204
|
+
}
|
|
34205
|
+
}
|
|
34206
|
+
formGroup.updateValueAndValidity();
|
|
34207
|
+
}
|
|
34208
|
+
markForCheck() {
|
|
34209
|
+
this.cd.markForCheck();
|
|
34210
|
+
}
|
|
34211
|
+
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 });
|
|
34212
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: MessageForm, selector: "app-message-form", inputs: { mobile: "mobile", suggestFn: "suggestFn", subjectMinLength: "subjectMinLength", subjectMaxLength: "subjectMaxLength", bodyMaxLength: "bodyMaxLength", bodyAutoHeight: "bodyAutoHeight", canSelectType: "canSelectType", canRecipientFilter: "canRecipientFilter", recipientFilterCount: "recipientFilterCount" }, usesInheritance: true, ngImport: i0, template: "<!-- debug -->\n@if (debug) {\n <ng-container *ngTemplateOutlet=\"debugPanel\"></ng-container>\n}\n\n<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\n\n<ng-template #debugPanel>\n <app-debug title=\"Message form\">\n <ion-grid>\n <ion-row>\n <ion-col>\n ready: {{ readySubject | async }}\n <br />\n loading: {{ loadingSubject | async }}\n <br />\n enabled: {{ enabled }}\n <br />\n dirty: {{ dirty }}\n <br />\n valid: {{ valid }}\n <br />\n <br />\n error: {{ _form | formError | json}}\n </ion-col>\n </ion-row>\n </ion-grid>\n </app-debug>\n</ng-template>\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: "directive", type: i3$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i2$1.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i2$1.IonGrid, selector: "ion-grid", inputs: ["fixed"] }, { kind: "component", type: i2$1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2$1.IonRow, selector: "ion-row" }, { 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: "component", type: DebugComponent, selector: "app-debug", inputs: ["titlePrefix", "title", "enable", "expanded"] }, { kind: "pipe", type: i3$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3$1.JsonPipe, name: "json" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }, { kind: "pipe", type: FormErrorPipe, name: "formError" }, { kind: "pipe", type: FormGetValuePipe, name: "formGetValue" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
34213
|
+
}
|
|
34214
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessageForm, decorators: [{
|
|
34215
|
+
type: Component,
|
|
34216
|
+
args: [{ selector: 'app-message-form', changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- debug -->\n@if (debug) {\n <ng-container *ngTemplateOutlet=\"debugPanel\"></ng-container>\n}\n\n<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\n\n<ng-template #debugPanel>\n <app-debug title=\"Message form\">\n <ion-grid>\n <ion-row>\n <ion-col>\n ready: {{ readySubject | async }}\n <br />\n loading: {{ loadingSubject | async }}\n <br />\n enabled: {{ enabled }}\n <br />\n dirty: {{ dirty }}\n <br />\n valid: {{ valid }}\n <br />\n <br />\n error: {{ _form | formError | json}}\n </ion-col>\n </ion-row>\n </ion-grid>\n </app-debug>\n</ng-template>\n", styles: ["textarea.fixed-height{height:11.5em}textarea{min-height:11.5em}\n"] }]
|
|
34217
|
+
}], ctorParameters: () => [{ type: i0.Injector }, { type: i1$3.UntypedFormBuilder }, { type: i0.ChangeDetectorRef }], propDecorators: { mobile: [{
|
|
34218
|
+
type: Input
|
|
34219
|
+
}], suggestFn: [{
|
|
34220
|
+
type: Input
|
|
34221
|
+
}], subjectMinLength: [{
|
|
34222
|
+
type: Input
|
|
34223
|
+
}], subjectMaxLength: [{
|
|
34224
|
+
type: Input
|
|
34225
|
+
}], bodyMaxLength: [{
|
|
34226
|
+
type: Input
|
|
34227
|
+
}], bodyAutoHeight: [{
|
|
34228
|
+
type: Input
|
|
34229
|
+
}], canSelectType: [{
|
|
34230
|
+
type: Input
|
|
34231
|
+
}], canRecipientFilter: [{
|
|
34232
|
+
type: Input
|
|
34233
|
+
}], recipientFilterCount: [{
|
|
34234
|
+
type: Input
|
|
34235
|
+
}] } });
|
|
34236
|
+
|
|
34237
|
+
class MessageModal {
|
|
34238
|
+
settings;
|
|
34239
|
+
viewCtrl;
|
|
34240
|
+
accountService;
|
|
34241
|
+
cd;
|
|
34242
|
+
mobile;
|
|
34243
|
+
debug = false;
|
|
34244
|
+
title = 'SOCIAL.MESSAGE.NEW';
|
|
34245
|
+
suggestFn;
|
|
34246
|
+
data;
|
|
34247
|
+
canSelectType;
|
|
34248
|
+
canRecipientFilter;
|
|
34249
|
+
recipientFilterCount;
|
|
34250
|
+
form;
|
|
34251
|
+
constructor(settings, viewCtrl, accountService, cd) {
|
|
34252
|
+
this.settings = settings;
|
|
34253
|
+
this.viewCtrl = viewCtrl;
|
|
34254
|
+
this.accountService = accountService;
|
|
34255
|
+
this.cd = cd;
|
|
34256
|
+
this.mobile = this.settings.mobile;
|
|
34257
|
+
}
|
|
34258
|
+
ngOnInit() {
|
|
34259
|
+
this.canSelectType = toBoolean(this.canSelectType, this.accountService.isAdmin());
|
|
34260
|
+
}
|
|
34261
|
+
ngAfterViewInit() {
|
|
34262
|
+
setTimeout(() => {
|
|
34263
|
+
this.form.markAsReady({ emitEvent: false });
|
|
34264
|
+
if (this.data) {
|
|
34265
|
+
this.data.type = this.data.type || MessageTypes.INBOX_MESSAGE;
|
|
34266
|
+
this.form.setValue(this.data);
|
|
34267
|
+
}
|
|
34268
|
+
this.form.markAsLoaded();
|
|
34269
|
+
this.form.enable();
|
|
34270
|
+
});
|
|
34271
|
+
}
|
|
34272
|
+
cancel() {
|
|
34273
|
+
this.viewCtrl.dismiss();
|
|
34274
|
+
}
|
|
34275
|
+
async doSubmit() {
|
|
34276
|
+
if (this.form.disabled)
|
|
34277
|
+
return;
|
|
34278
|
+
if (!this.form.valid) {
|
|
34279
|
+
await AppFormUtils.waitWhilePending(this.form);
|
|
34280
|
+
if (this.form.invalid) {
|
|
34281
|
+
AppFormUtils.logFormErrors(this.form.form, '[message-modal] ');
|
|
34282
|
+
this.form.markAllAsTouched();
|
|
34283
|
+
return;
|
|
34284
|
+
}
|
|
34285
|
+
}
|
|
34286
|
+
this.markAsLoading();
|
|
34287
|
+
try {
|
|
34288
|
+
const data = this.form.value;
|
|
34289
|
+
// Disable the form
|
|
34290
|
+
this.form.disable();
|
|
34291
|
+
const entity = Message.fromObject(data);
|
|
34292
|
+
return this.viewCtrl.dismiss(entity);
|
|
34293
|
+
}
|
|
34294
|
+
catch (err) {
|
|
34295
|
+
this.form.error = (err && err.message) || err;
|
|
34296
|
+
this.markAsLoaded();
|
|
34297
|
+
// Enable the form
|
|
34298
|
+
this.form.enable();
|
|
34299
|
+
// Reset form error on next changes
|
|
34300
|
+
firstNotNilPromise(this.form.form.valueChanges).then(() => {
|
|
34301
|
+
this.form.error = null;
|
|
34302
|
+
this.markForCheck();
|
|
34303
|
+
});
|
|
34304
|
+
return;
|
|
34305
|
+
}
|
|
34306
|
+
}
|
|
34307
|
+
markForCheck() {
|
|
34308
|
+
this.cd.markForCheck();
|
|
34309
|
+
}
|
|
34310
|
+
markAsLoading(opts) {
|
|
34311
|
+
this.form.markAsLoading(opts);
|
|
34312
|
+
}
|
|
34313
|
+
markAsLoaded(opts) {
|
|
34314
|
+
this.form.markAsLoaded(opts);
|
|
34315
|
+
}
|
|
34316
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessageModal, deps: [{ token: LocalSettingsService }, { token: i2$1.ModalController }, { token: AccountService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
34317
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: MessageModal, selector: "app-message-modal", inputs: { debug: "debug", title: "title", suggestFn: "suggestFn", data: "data", canSelectType: "canSelectType", canRecipientFilter: "canRecipientFilter", recipientFilterCount: "recipientFilterCount" }, viewQueries: [{ propertyName: "form", first: true, predicate: ["form"], descendants: true, static: true }], ngImport: i0, template: "<ion-header>\n <ion-toolbar color=\"secondary\">\n <ion-buttons slot=\"start\">\n <ion-button class=\"back-button\" (click)=\"cancel()\" visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title>\n {{ title | translate }}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <ion-button\n class=\"back-button\"\n (click)=\"doSubmit()\"\n [disabled]=\"!form.valid\"\n visible-xs\n visible-sm\n visible-mobile\n >\n <ion-icon slot=\"icon-only\" name=\"checkmark\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n <ion-item *ngIf=\"form.error\" visible-xs visible-sm visible-mobile lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"form.error | translate\"></ion-label>\n </ion-item>\n\n <app-message-form\n #form\n (onSubmit)=\"doSubmit()\"\n (onCancel)=\"cancel()\"\n [canSelectType]=\"canSelectType\"\n [canRecipientFilter]=\"canRecipientFilter\"\n [recipientFilterCount]=\"recipientFilterCount\"\n [suggestFn]=\"suggestFn\"\n [debug]=\"debug\">\n ></app-message-form>\n</ion-content>\n\n<ion-footer hidden-xs hidden-sm hidden-mobile>\n <ion-toolbar>\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col></ion-col>\n\n <!-- buttons -->\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n\n <ion-button\n [fill]=\"form.invalid ? 'clear' : 'solid'\"\n [disabled]=\"form.loading || form.invalid\"\n (keyup.enter)=\"doSubmit()\"\n (click)=\"doSubmit()\"\n color=\"tertiary\"\n >\n <ion-label translate>COMMON.BTN_SEND</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-toolbar>\n</ion-footer>\n", dependencies: [{ kind: "directive", type: i3$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2$1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2$1.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i2$1.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i2$1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2$1.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2$1.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2$1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2$1.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2$1.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2$1.IonRow, selector: "ion-row" }, { kind: "component", type: i2$1.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: i2$1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: MessageForm, selector: "app-message-form", inputs: ["mobile", "suggestFn", "subjectMinLength", "subjectMaxLength", "bodyMaxLength", "bodyAutoHeight", "canSelectType", "canRecipientFilter", "recipientFilterCount"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
34318
|
+
}
|
|
34319
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessageModal, decorators: [{
|
|
34320
|
+
type: Component,
|
|
34321
|
+
args: [{ selector: 'app-message-modal', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ion-header>\n <ion-toolbar color=\"secondary\">\n <ion-buttons slot=\"start\">\n <ion-button class=\"back-button\" (click)=\"cancel()\" visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title>\n {{ title | translate }}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <ion-button\n class=\"back-button\"\n (click)=\"doSubmit()\"\n [disabled]=\"!form.valid\"\n visible-xs\n visible-sm\n visible-mobile\n >\n <ion-icon slot=\"icon-only\" name=\"checkmark\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n <ion-item *ngIf=\"form.error\" visible-xs visible-sm visible-mobile lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"form.error | translate\"></ion-label>\n </ion-item>\n\n <app-message-form\n #form\n (onSubmit)=\"doSubmit()\"\n (onCancel)=\"cancel()\"\n [canSelectType]=\"canSelectType\"\n [canRecipientFilter]=\"canRecipientFilter\"\n [recipientFilterCount]=\"recipientFilterCount\"\n [suggestFn]=\"suggestFn\"\n [debug]=\"debug\">\n ></app-message-form>\n</ion-content>\n\n<ion-footer hidden-xs hidden-sm hidden-mobile>\n <ion-toolbar>\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col></ion-col>\n\n <!-- buttons -->\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n\n <ion-button\n [fill]=\"form.invalid ? 'clear' : 'solid'\"\n [disabled]=\"form.loading || form.invalid\"\n (keyup.enter)=\"doSubmit()\"\n (click)=\"doSubmit()\"\n color=\"tertiary\"\n >\n <ion-label translate>COMMON.BTN_SEND</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-toolbar>\n</ion-footer>\n" }]
|
|
34322
|
+
}], ctorParameters: () => [{ type: LocalSettingsService }, { type: i2$1.ModalController }, { type: AccountService }, { type: i0.ChangeDetectorRef }], propDecorators: { debug: [{
|
|
34323
|
+
type: Input
|
|
34324
|
+
}], title: [{
|
|
34325
|
+
type: Input
|
|
34326
|
+
}], suggestFn: [{
|
|
34327
|
+
type: Input
|
|
34328
|
+
}], data: [{
|
|
34329
|
+
type: Input
|
|
34330
|
+
}], canSelectType: [{
|
|
34331
|
+
type: Input
|
|
34332
|
+
}], canRecipientFilter: [{
|
|
34333
|
+
type: Input
|
|
34334
|
+
}], recipientFilterCount: [{
|
|
34335
|
+
type: Input
|
|
34336
|
+
}], form: [{
|
|
34337
|
+
type: ViewChild,
|
|
34338
|
+
args: ['form', { static: true }]
|
|
34339
|
+
}] } });
|
|
34340
|
+
|
|
34341
|
+
const MessageFragments = {
|
|
34342
|
+
message: gql$1 `
|
|
34343
|
+
fragment MessageFragment on MessageVO {
|
|
34344
|
+
id
|
|
34345
|
+
subject
|
|
34346
|
+
body
|
|
34347
|
+
type
|
|
34348
|
+
recipientFilter {
|
|
34349
|
+
...PersonFilterFragment
|
|
34350
|
+
}
|
|
34351
|
+
issuer {
|
|
34352
|
+
...PersonFragment
|
|
34353
|
+
}
|
|
34354
|
+
}
|
|
34355
|
+
`,
|
|
34356
|
+
};
|
|
34357
|
+
const Queries = {
|
|
34358
|
+
load: gql$1 `
|
|
34359
|
+
mutation LoadMessage($id: Int!) {
|
|
34360
|
+
data: message(id: $id) {
|
|
34361
|
+
...MessageFragment
|
|
34362
|
+
}
|
|
34363
|
+
}
|
|
34364
|
+
${MessageFragments.message}
|
|
34365
|
+
${PersonFragments.person}
|
|
34366
|
+
${PersonFragments.personFilter}
|
|
34367
|
+
`,
|
|
34368
|
+
};
|
|
34369
|
+
const Mutations = {
|
|
34370
|
+
send: gql$1 `
|
|
34371
|
+
mutation SendMessage($data: MessageVOInput) {
|
|
34372
|
+
done: sendMessage(message: $data)
|
|
34373
|
+
}
|
|
34374
|
+
`,
|
|
34375
|
+
delete: gql$1 `
|
|
34376
|
+
mutation DeleteMessage($id: Int!) {
|
|
34377
|
+
done: deleteMessage(id: $id)
|
|
34378
|
+
}
|
|
34379
|
+
`,
|
|
34380
|
+
};
|
|
34381
|
+
class MessageService extends BaseGraphqlService {
|
|
34382
|
+
graphql;
|
|
34383
|
+
translate;
|
|
34384
|
+
modalCtrl;
|
|
34385
|
+
toastController;
|
|
34386
|
+
environment;
|
|
34387
|
+
constructor(graphql, translate, modalCtrl, toastController, environment) {
|
|
34388
|
+
super(graphql, environment);
|
|
34389
|
+
this.graphql = graphql;
|
|
34390
|
+
this.translate = translate;
|
|
34391
|
+
this.modalCtrl = modalCtrl;
|
|
34392
|
+
this.toastController = toastController;
|
|
34393
|
+
this.environment = environment;
|
|
34394
|
+
// For DEV only
|
|
34395
|
+
this._debug = !environment.production;
|
|
34396
|
+
}
|
|
34397
|
+
/**
|
|
34398
|
+
* Send a message to recipient(s)
|
|
34399
|
+
*
|
|
34400
|
+
* @param entity
|
|
34401
|
+
* @param opts
|
|
34402
|
+
*/
|
|
34403
|
+
async send(entity, opts) {
|
|
34404
|
+
// Transform into json
|
|
34405
|
+
const data = entity.asObject(MINIFY_ENTITY_FOR_POD);
|
|
34406
|
+
const now = Date.now();
|
|
34407
|
+
if (this._debug)
|
|
34408
|
+
console.debug(`[message-service] Sending message...`);
|
|
34409
|
+
try {
|
|
34410
|
+
const { done } = await this.graphql.mutate({
|
|
34411
|
+
mutation: Mutations.send,
|
|
34412
|
+
variables: { data },
|
|
34413
|
+
error: { code: SocialErrorCodes.SEND_MESSAGE_ERROR, message: 'SOCIAL.ERROR.SEND_MESSAGE_ERROR' },
|
|
34414
|
+
});
|
|
34415
|
+
if (this._debug)
|
|
34416
|
+
console.debug(`[message-service] Send message [OK] in ${Date.now() - now}ms`);
|
|
34417
|
+
if (done && (!opts || opts.showToast !== false)) {
|
|
34418
|
+
await this.showToast({ type: 'info', message: 'SOCIAL.INFO.MESSAGE_SENT' });
|
|
34419
|
+
}
|
|
34420
|
+
return done;
|
|
34421
|
+
}
|
|
34422
|
+
catch (err) {
|
|
34423
|
+
const error = (err && err.message) || err;
|
|
34424
|
+
console.error(error);
|
|
34425
|
+
// Show error
|
|
34426
|
+
if (!opts || opts.showToast !== false) {
|
|
34427
|
+
const message = error || 'SOCIAL.ERROR.SEND_MESSAGE_ERROR';
|
|
34428
|
+
await this.showToast({ type: 'error', message });
|
|
34429
|
+
}
|
|
34430
|
+
return false;
|
|
34431
|
+
}
|
|
34432
|
+
}
|
|
34433
|
+
/**
|
|
34434
|
+
* Delete a message by ID
|
|
34435
|
+
*
|
|
34436
|
+
* @param id
|
|
34437
|
+
* @param opts
|
|
34438
|
+
*/
|
|
34439
|
+
async delete(id, opts) {
|
|
34440
|
+
const now = Date.now();
|
|
34441
|
+
if (this._debug)
|
|
34442
|
+
console.debug(`[message-service] Deleting message #${id}...`);
|
|
34443
|
+
try {
|
|
34444
|
+
const { done } = await this.graphql.mutate({
|
|
34445
|
+
mutation: Mutations.delete,
|
|
34446
|
+
variables: { id },
|
|
34447
|
+
error: { code: SocialErrorCodes.DELETE_MESSAGE_ERROR, message: 'SOCIAL.ERROR.DELETE_MESSAGE_ERROR' },
|
|
34448
|
+
});
|
|
34449
|
+
if (this._debug)
|
|
34450
|
+
console.debug(`[message-service] Delete message [OK] in ${Date.now() - now}ms`);
|
|
34451
|
+
if (done && (!opts || opts.showToast !== false)) {
|
|
34452
|
+
await this.showToast({ type: 'info', message: 'SOCIAL.INFO.MESSAGE_DELETED' });
|
|
34453
|
+
}
|
|
34454
|
+
return done;
|
|
34455
|
+
}
|
|
34456
|
+
catch (err) {
|
|
34457
|
+
const error = (err && err.message) || err;
|
|
34458
|
+
console.error(error);
|
|
34459
|
+
// Show error
|
|
34460
|
+
if (!opts || opts.showToast !== false) {
|
|
34461
|
+
const message = error || 'SOCIAL.ERROR.DELETE_MESSAGE_ERROR';
|
|
34462
|
+
await this.showToast({ type: 'error', message });
|
|
34463
|
+
}
|
|
34464
|
+
return false;
|
|
34465
|
+
}
|
|
34466
|
+
}
|
|
34467
|
+
async openComposeModal(options) {
|
|
34468
|
+
const hasTopModal = !!(await this.modalCtrl.getTop());
|
|
34469
|
+
const modal = await this.modalCtrl.create({
|
|
34470
|
+
component: MessageModal,
|
|
34471
|
+
componentProps: options,
|
|
34472
|
+
cssClass: hasTopModal && 'stack-modal',
|
|
34473
|
+
});
|
|
34474
|
+
// Open the modal
|
|
34475
|
+
await modal.present();
|
|
34476
|
+
// On dismiss
|
|
34477
|
+
const { data } = await modal.onDidDismiss();
|
|
34478
|
+
if (!data || !(data instanceof Message))
|
|
34479
|
+
return true; // CANCELLED
|
|
34480
|
+
// Send message
|
|
34481
|
+
return await this.send(data, { showToast: options?.showToast });
|
|
34482
|
+
}
|
|
34483
|
+
async load(id, opts) {
|
|
34484
|
+
const { data } = await this.graphql.query({
|
|
34485
|
+
query: Queries.load,
|
|
34486
|
+
variables: {
|
|
34487
|
+
id,
|
|
34488
|
+
},
|
|
34489
|
+
fetchPolicy: 'no-cache',
|
|
34490
|
+
});
|
|
34491
|
+
const entity = opts?.toEntity !== false ? Message.fromObject(data) : data;
|
|
34492
|
+
console.debug(`[message-service] Loaded message #${id}:`, entity);
|
|
34493
|
+
return entity;
|
|
34494
|
+
}
|
|
34495
|
+
/* -- protected methods -- */
|
|
34496
|
+
async showToast(opts) {
|
|
34497
|
+
return Toasts.show(this.toastController, this.translate, {
|
|
34498
|
+
type: 'info',
|
|
34499
|
+
message: 'SOCIAL.INFO.MESSAGE_SENT',
|
|
34500
|
+
...opts,
|
|
34501
|
+
});
|
|
34502
|
+
}
|
|
34503
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessageService, deps: [{ token: GraphqlService }, { token: i1$1.TranslateService }, { token: i2$1.ModalController }, { token: i2$1.ToastController }, { token: ENVIRONMENT, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
34504
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessageService, providedIn: 'root' });
|
|
34505
|
+
}
|
|
34506
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessageService, decorators: [{
|
|
34507
|
+
type: Injectable,
|
|
34508
|
+
args: [{ providedIn: 'root' }]
|
|
34509
|
+
}], ctorParameters: () => [{ type: GraphqlService }, { type: i1$1.TranslateService }, { type: i2$1.ModalController }, { type: i2$1.ToastController }, { type: Environment, decorators: [{
|
|
34510
|
+
type: Optional
|
|
34511
|
+
}, {
|
|
34512
|
+
type: Inject,
|
|
34513
|
+
args: [ENVIRONMENT]
|
|
34514
|
+
}] }] });
|
|
34515
|
+
|
|
33784
34516
|
const APP_FEED_SERVICE = new InjectionToken('FeeService');
|
|
33785
34517
|
class FeedService extends StartableService {
|
|
33786
34518
|
settings;
|
|
@@ -33788,6 +34520,9 @@ class FeedService extends StartableService {
|
|
|
33788
34520
|
_logPrefix = '[feed-service] ';
|
|
33789
34521
|
_state = new RxState();
|
|
33790
34522
|
network = inject(NetworkService);
|
|
34523
|
+
modalCtrl = inject(ModalController);
|
|
34524
|
+
messageService = inject(MessageService);
|
|
34525
|
+
personService = inject(PersonService);
|
|
33791
34526
|
locale$ = this._state.select('locale');
|
|
33792
34527
|
feedUrls$ = this._state.select('feedUrls');
|
|
33793
34528
|
get feedUrls() {
|
|
@@ -33808,7 +34543,7 @@ class FeedService extends StartableService {
|
|
|
33808
34543
|
console.debug(`${this._logPrefix}created`);
|
|
33809
34544
|
}
|
|
33810
34545
|
async ngOnStart() {
|
|
33811
|
-
await this.settings.ready();
|
|
34546
|
+
await Promise.all([this.settings.ready(), this.network.ready()]);
|
|
33812
34547
|
return {
|
|
33813
34548
|
locale: this.settings.locale,
|
|
33814
34549
|
};
|
|
@@ -33818,9 +34553,10 @@ class FeedService extends StartableService {
|
|
|
33818
34553
|
return from(this.start()).pipe(switchMap$1(() => this.watchAll(opts)));
|
|
33819
34554
|
}
|
|
33820
34555
|
if (isNotEmptyArray(opts?.urls)) {
|
|
33821
|
-
|
|
34556
|
+
const locale$ = opts.locale ? of(opts.locale) : this.locale$;
|
|
34557
|
+
return locale$.pipe(mergeMap((locale) => this.loadAll({ locale, ...opts })));
|
|
33822
34558
|
}
|
|
33823
|
-
return this.feedUrls$.pipe(filter(isNotEmptyArray), mergeMap((urls) => this.loadAll(
|
|
34559
|
+
return this.feedUrls$.pipe(filter(isNotEmptyArray), mergeMap((urls) => this.loadAll({ ...opts, urls })));
|
|
33824
34560
|
}
|
|
33825
34561
|
getHomeUrl(feed) {
|
|
33826
34562
|
const feedUrl = feed?.feed_url ?? firstArrayValue(this.feedUrls);
|
|
@@ -33833,12 +34569,14 @@ class FeedService extends StartableService {
|
|
|
33833
34569
|
return feed.tag_template?.replace('{tag}', tag) ?? baseUrl + '/tag/' + tag;
|
|
33834
34570
|
}
|
|
33835
34571
|
async load(url, opts) {
|
|
33836
|
-
|
|
33837
|
-
|
|
34572
|
+
if (!url)
|
|
34573
|
+
throw new Error('Missing url argument');
|
|
34574
|
+
const { data } = await this.loadAll({ ...opts, urls: [url] });
|
|
34575
|
+
return firstArrayValue(data);
|
|
33838
34576
|
}
|
|
33839
|
-
async loadAll(
|
|
34577
|
+
async loadAll(opts) {
|
|
33840
34578
|
await this.ready();
|
|
33841
|
-
urls = urls ?? this.feedUrls;
|
|
34579
|
+
const urls = opts?.urls ?? this.feedUrls;
|
|
33842
34580
|
opts = {
|
|
33843
34581
|
maxAgeInMonths: opts?.maxAgeInMonths ?? this.environment.feed?.maxAgeInMonths,
|
|
33844
34582
|
maxContentLength: opts?.maxContentLength ?? this.environment.feed?.maxContentLength,
|
|
@@ -33849,7 +34587,7 @@ class FeedService extends StartableService {
|
|
|
33849
34587
|
const feeds = await Promise.all((urls || []).map(async (url) => {
|
|
33850
34588
|
try {
|
|
33851
34589
|
// Get JSON
|
|
33852
|
-
const json = await this.network.get(url);
|
|
34590
|
+
const json = await this.network.get(url, { nocache: opts?.cache });
|
|
33853
34591
|
console.debug(`${this._logPrefix}Loaded JSON from ${url}`, json);
|
|
33854
34592
|
// Resolve feed
|
|
33855
34593
|
return await this.resolveFeed(json, url, opts);
|
|
@@ -33864,13 +34602,53 @@ class FeedService extends StartableService {
|
|
|
33864
34602
|
return Promise.resolve([]);
|
|
33865
34603
|
}
|
|
33866
34604
|
}));
|
|
33867
|
-
const data = feeds.flat();
|
|
34605
|
+
const data = feeds.filter(isNotEmptyArray).flat();
|
|
33868
34606
|
// Close opened resources
|
|
33869
34607
|
if (opts.depth === 0) {
|
|
33870
34608
|
this.onAfterLoadAll();
|
|
33871
34609
|
}
|
|
33872
34610
|
return { data, total: data.length };
|
|
33873
34611
|
}
|
|
34612
|
+
async openEditModal(event, feedItem, opts) {
|
|
34613
|
+
const messageId = +feedItem.id;
|
|
34614
|
+
if (isNilOrNaN(messageId))
|
|
34615
|
+
throw new Error(`Cannot load message - invalid id: ${feedItem.id}`);
|
|
34616
|
+
// Fetch the original message
|
|
34617
|
+
const message = await this.messageService.load(messageId);
|
|
34618
|
+
// Count recipients
|
|
34619
|
+
let recipientFilterCount;
|
|
34620
|
+
if (message?.recipientFilter) {
|
|
34621
|
+
recipientFilterCount = await this.personService.countAll(message?.recipientFilter);
|
|
34622
|
+
}
|
|
34623
|
+
const hasTopModal = !!(await this.modalCtrl.getTop());
|
|
34624
|
+
const modal = await this.modalCtrl.create({
|
|
34625
|
+
component: MessageModal,
|
|
34626
|
+
componentProps: {
|
|
34627
|
+
title: 'SOCIAL.FEED.EDIT_TITLE',
|
|
34628
|
+
suggestFn: (value, filter, sortBy, sortDirection, opts) => this.personService.suggest(value, filter, sortBy, sortDirection, opts),
|
|
34629
|
+
canSelectType: false,
|
|
34630
|
+
canRecipientFilter: false,
|
|
34631
|
+
recipientFilterCount,
|
|
34632
|
+
data: message,
|
|
34633
|
+
debug: true,
|
|
34634
|
+
},
|
|
34635
|
+
cssClass: hasTopModal && 'stack-modal',
|
|
34636
|
+
});
|
|
34637
|
+
// Open the modal
|
|
34638
|
+
await modal.present();
|
|
34639
|
+
// On dismiss
|
|
34640
|
+
const { data } = await modal.onDidDismiss();
|
|
34641
|
+
if (!data || !(data instanceof Message))
|
|
34642
|
+
return true; // CANCELLED
|
|
34643
|
+
return await this.messageService.send(data, opts);
|
|
34644
|
+
}
|
|
34645
|
+
async deleteItem(feedItem) {
|
|
34646
|
+
const messageId = +feedItem.id;
|
|
34647
|
+
if (isNilOrNaN(messageId))
|
|
34648
|
+
throw new Error(`Cannot delete message - invalid id: ${feedItem.id}`);
|
|
34649
|
+
return await this.messageService.delete(messageId);
|
|
34650
|
+
}
|
|
34651
|
+
/* -- protected functions -- */
|
|
33874
34652
|
async resolveFeed(json, url, opts) {
|
|
33875
34653
|
// Check json is JsonFeed compatible
|
|
33876
34654
|
if (JsonFeedUtils.isJsonFeed(json)) {
|
|
@@ -33883,7 +34661,7 @@ class FeedService extends StartableService {
|
|
|
33883
34661
|
return isNotEmptyArray(feed?.items) ? [feed] : [];
|
|
33884
34662
|
}
|
|
33885
34663
|
// not resolved (unknown format)
|
|
33886
|
-
return
|
|
34664
|
+
return [];
|
|
33887
34665
|
}
|
|
33888
34666
|
async resolveFeedItems(json, opts) {
|
|
33889
34667
|
if (!json)
|
|
@@ -34071,31 +34849,43 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
34071
34849
|
class FeedsComponent {
|
|
34072
34850
|
environment;
|
|
34073
34851
|
feedService;
|
|
34852
|
+
accountService;
|
|
34853
|
+
alertCtrl;
|
|
34074
34854
|
_state = new RxState();
|
|
34075
34855
|
translate = inject(TranslateService);
|
|
34076
34856
|
platform = inject(PlatformService);
|
|
34857
|
+
networkService = inject(NetworkService);
|
|
34077
34858
|
router = inject(Router);
|
|
34078
34859
|
version;
|
|
34860
|
+
modalItemId;
|
|
34861
|
+
onRefresh = new EventEmitter();
|
|
34079
34862
|
feeds$ = this._state.select('feeds');
|
|
34080
|
-
|
|
34863
|
+
urls$ = this._state.select('urls');
|
|
34081
34864
|
hasFeeds$ = this._state.select('hasFeeds');
|
|
34865
|
+
userId$ = this._state.select('userId');
|
|
34082
34866
|
debug = false;
|
|
34867
|
+
mobile;
|
|
34083
34868
|
showHeader = true;
|
|
34869
|
+
showReadMoreButton = true;
|
|
34084
34870
|
headerColor = 'secondary';
|
|
34085
34871
|
cardColor = 'light-transparent';
|
|
34086
34872
|
shape = 'legacy';
|
|
34087
34873
|
class = '';
|
|
34874
|
+
itemId;
|
|
34875
|
+
filterItem;
|
|
34876
|
+
editItem = new EventEmitter();
|
|
34877
|
+
deleteItem = new EventEmitter();
|
|
34088
34878
|
set feeds(value) {
|
|
34089
34879
|
this._state.set('feeds', () => value);
|
|
34090
34880
|
}
|
|
34091
34881
|
get feeds() {
|
|
34092
34882
|
return this._state.get('feeds');
|
|
34093
34883
|
}
|
|
34094
|
-
set
|
|
34095
|
-
this._state.set('
|
|
34884
|
+
set urls(value) {
|
|
34885
|
+
this._state.set('urls', () => value);
|
|
34096
34886
|
}
|
|
34097
|
-
get
|
|
34098
|
-
return this._state.get('
|
|
34887
|
+
get urls() {
|
|
34888
|
+
return this._state.get('urls');
|
|
34099
34889
|
}
|
|
34100
34890
|
get hasFeeds() {
|
|
34101
34891
|
return this._state.get('hasFeeds');
|
|
@@ -34112,6 +34902,9 @@ class FeedsComponent {
|
|
|
34112
34902
|
get maxContentLength() {
|
|
34113
34903
|
return this._state.get('maxContentLength');
|
|
34114
34904
|
}
|
|
34905
|
+
get peerUrl() {
|
|
34906
|
+
return this._state.get('peerUrl');
|
|
34907
|
+
}
|
|
34115
34908
|
get hostClass() {
|
|
34116
34909
|
const classes = [this.class];
|
|
34117
34910
|
if (this.shape) {
|
|
@@ -34119,15 +34912,26 @@ class FeedsComponent {
|
|
|
34119
34912
|
}
|
|
34120
34913
|
return classes.filter((cls) => cls).join(' ');
|
|
34121
34914
|
}
|
|
34122
|
-
|
|
34915
|
+
modal;
|
|
34916
|
+
constructor(settings, environment, feedService, accountService, alertCtrl) {
|
|
34123
34917
|
this.environment = environment;
|
|
34124
34918
|
this.feedService = feedService;
|
|
34919
|
+
this.accountService = accountService;
|
|
34920
|
+
this.alertCtrl = alertCtrl;
|
|
34921
|
+
this.mobile = settings.mobile;
|
|
34922
|
+
this._state.connect('locale', settings.locale$);
|
|
34125
34923
|
this._state.connect('hasFeeds', this.feeds$.pipe(map(isNotEmptyArray)));
|
|
34924
|
+
this._state.connect('userId', this.accountService.person$.pipe(map((person) => person?.id)));
|
|
34925
|
+
this._state.connect('peerUrl', this.networkService.peer$.pipe(map((peer) => peer?.url)));
|
|
34126
34926
|
if (this.feedService) {
|
|
34127
|
-
this._state.connect('feeds', this.
|
|
34128
|
-
urls
|
|
34927
|
+
this._state.connect('feeds', merge(this.onRefresh.pipe(map(() => ({ ...this._state.get(), cache: false }))), this._state
|
|
34928
|
+
.select(['urls', 'maxAgeInMonths', 'maxContentLength', 'locale'])
|
|
34929
|
+
.pipe(map(({ urls, maxAgeInMonths, maxContentLength, locale }) => ({ urls, maxAgeInMonths, maxContentLength, locale, cache: true })))).pipe(switchMap(({ urls, maxAgeInMonths, maxContentLength, locale, cache }) => this.feedService.watchAll({
|
|
34930
|
+
urls: urls,
|
|
34129
34931
|
maxAgeInMonths,
|
|
34130
34932
|
maxContentLength,
|
|
34933
|
+
locale,
|
|
34934
|
+
cache,
|
|
34131
34935
|
})), map(({ data }) => data)
|
|
34132
34936
|
// DEBUG
|
|
34133
34937
|
//tap((feeds) => console.debug('[feed-component] feeds', feeds))
|
|
@@ -34135,22 +34939,56 @@ class FeedsComponent {
|
|
|
34135
34939
|
}
|
|
34136
34940
|
}
|
|
34137
34941
|
ngOnInit() {
|
|
34138
|
-
this.
|
|
34942
|
+
this.urls = this.urls ?? null; // Should set the urls, in order to trigger the select in constructor
|
|
34139
34943
|
this.maxAgeInMonths = this.maxAgeInMonths ?? this.environment.feed?.maxAgeInMonths ?? -1;
|
|
34140
34944
|
this.maxContentLength = this.maxContentLength ?? this.environment.feed?.maxContentLength ?? -1;
|
|
34945
|
+
const self = this;
|
|
34946
|
+
this.filterItem = this.filterItem ?? ((item) => !self.itemId || item.id === self.itemId);
|
|
34141
34947
|
}
|
|
34142
34948
|
ngOnDestroy() {
|
|
34143
34949
|
this._state.ngOnDestroy();
|
|
34144
34950
|
}
|
|
34145
|
-
openFeedHome(feed) {
|
|
34951
|
+
async openFeedHome(feed) {
|
|
34146
34952
|
if (!feed) {
|
|
34147
|
-
|
|
34953
|
+
// Reduce feed by home url (keep one feed by home url)
|
|
34954
|
+
const homeUrls = [];
|
|
34955
|
+
const feeds = this.feeds?.reduce((res, item) => {
|
|
34956
|
+
const url = this.getFeedHomeUrl(item);
|
|
34957
|
+
if (!url || homeUrls.includes(url))
|
|
34958
|
+
return res;
|
|
34959
|
+
return res.concat(item);
|
|
34960
|
+
}, []);
|
|
34961
|
+
// Recursive call
|
|
34962
|
+
if (isNotEmptyArray(feeds)) {
|
|
34963
|
+
feeds.forEach((f) => this.openFeedHome(f));
|
|
34964
|
+
}
|
|
34148
34965
|
return;
|
|
34149
34966
|
}
|
|
34150
|
-
const url =
|
|
34967
|
+
const url = this.getFeedHomeUrl(feed);
|
|
34151
34968
|
if (!url)
|
|
34152
34969
|
return;
|
|
34153
|
-
|
|
34970
|
+
// Feed comes from the current pod:
|
|
34971
|
+
if (url.startsWith(this.networkService.peer?.url) || UrlUtils.isInternalUrl(url)) {
|
|
34972
|
+
await this.modal.present();
|
|
34973
|
+
return;
|
|
34974
|
+
}
|
|
34975
|
+
return this.openUrl(url);
|
|
34976
|
+
}
|
|
34977
|
+
async openFeedItem(feedItem, feed) {
|
|
34978
|
+
const url = feedItem?.url ?? feed?.feed_url;
|
|
34979
|
+
if (!url || !this.showReadMoreButton)
|
|
34980
|
+
return;
|
|
34981
|
+
// Feed comes from the current pod:
|
|
34982
|
+
if (url.startsWith(this.networkService.peer?.url) || UrlUtils.isInternalUrl(url)) {
|
|
34983
|
+
this.modalItemId = feedItem.id;
|
|
34984
|
+
await this.modal.present();
|
|
34985
|
+
await this.modal.onDidDismiss();
|
|
34986
|
+
// Reset item id
|
|
34987
|
+
this.modalItemId = undefined;
|
|
34988
|
+
return;
|
|
34989
|
+
}
|
|
34990
|
+
const fixedUrl = JsonFeedUtils.removeJsonExtension(url);
|
|
34991
|
+
return this.platform.open(fixedUrl);
|
|
34154
34992
|
}
|
|
34155
34993
|
openUrl(url) {
|
|
34156
34994
|
if (!url)
|
|
@@ -34174,13 +35012,77 @@ class FeedsComponent {
|
|
|
34174
35012
|
}
|
|
34175
35013
|
return [];
|
|
34176
35014
|
}
|
|
34177
|
-
|
|
34178
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: FeedsComponent, selector: "app-feed", inputs: { debug: "debug", showHeader: "showHeader", headerColor: "headerColor", cardColor: "cardColor", shape: "shape", class: "class", feeds: "feeds", feedUrls: "feedUrls", maxAgeInMonths: "maxAgeInMonths", maxContentLength: "maxContentLength" }, host: { properties: { "class": "this.hostClass" } }, providers: [RxState], ngImport: i0, template: "<!-- debug -->\n@if (debug) {\n <app-debug [title]=\"'Feed'\">\n <p>\n hasFeeds?: {{ hasFeeds$ | async }}\n <br />\n feedUrls: {{ feedUrls$ | async | json }}\n <br />\n shape: {{ shape }}\n </p>\n </app-debug>\n}\n\n@let feeds = feeds$ | async;\n@if (feeds | isNotEmptyArray) {\n <!-- top header -->\n @if (showHeader && (feeds | arrayFirst); as feed) {\n <ion-item lines=\"none\" [color]=\"headerColor\" class=\"feed-header shape-{{ shape }}\">\n <ion-icon slot=\"start\" name=\"megaphone\"></ion-icon>\n <ion-label>\n <b>{{ feed.title || ('SOCIAL.FEED.NEWS' | translate) }}</b>\n </ion-label>\n <ion-button slot=\"end\" fill=\"clear\" (click)=\"openFeedHome()\" shape=\"\">\n <ion-label translate>SOCIAL.FEED.SHOW_ALL_FEED</ion-label>\n <ion-icon slot=\"end\" name=\"chevron-forward-outline\"></ion-icon>\n </ion-button>\n </ion-item>\n }\n\n <div class=\"feed-content shape-{{ shape }} ion-no-padding\" [class.has-header]=\"showHeader\">\n <!-- feeds -->\n @for (feed of feeds; track feed.feed_url; let firstFeed = $first; let lastFeed = $last) {\n <!-- items -->\n @for (item of feed.items; track item.id; let firstItem = $first; let lastItem = $last) {\n <ion-card\n [class.first]=\"firstFeed && firstItem\"\n [class.last]=\"lastFeed && lastItem\"\n [color]=\"cardColor !== 'light-transparent' ? cardColor : undefined\"\n >\n <ion-card-header>\n <ion-card-subtitle style=\"vertical-align: middle\">\n <!-- Authors -->\n @for (author of item.authors || feed.authors; track author) {\n @if (author.name || author.avatar) {\n <ion-chip (click)=\"openUrl(author.url)\" tappable>\n @if (author.avatar) {\n <ion-avatar>\n <ion-img [src]=\"author.avatar\" [alt]=\"author.name\"></ion-img>\n </ion-avatar>\n }\n @if (author.name) {\n <ion-label class=\"author\">{{ author.name }}</ion-label>\n }\n </ion-chip>\n }\n }\n <ion-note class=\"ion-float-end\">\n <small>{{ item.date_published | dateFromNow }}</small>\n </ion-note>\n </ion-card-subtitle>\n\n <!-- title -->\n <ion-card-title (click)=\"openUrl(item.url || feed.feed_url)\" tappable>{{ item?.title }}</ion-card-title>\n\n <!-- tags -->\n @let tags = item | map: getTags;\n @if (tags | isNotEmptyArray) {\n <ion-text class=\"tags\">\n @for (tag of tags; track tag; let last = $last) {\n <a (click)=\"openTag(feed, tag)\" tappable>\n <ion-text>#{{ tag }}</ion-text>\n </a>\n @if (!last) {\n \n }\n }\n </ion-text>\n }\n </ion-card-header>\n\n <!-- Feed content -->\n <ion-card-content>\n <ion-text [feed]=\"item.url || feed.feed_url\">\n @if (item.content_html) {\n <p [innerHTML]=\"item.content_html\"></p>\n } @else if (item.content_text) {\n <p>\n <markdown [data]=\"item.content_text\" emoji></markdown>\n </p>\n }\n </ion-text>\n </ion-card-content>\n\n <ion-button (click)=\"openUrl(item.url)\" class=\"ion-float-end\" fill=\"clear\">\n <ion-label>{{ (item.truncated ? 'SOCIAL.FEED.READ_MORE' : 'COMMON.BTN_SHOW') | translate }}</ion-label>\n <ion-icon slot=\"end\" name=\"chevron-forward-outline\"></ion-icon>\n </ion-button>\n </ion-card>\n }\n }\n </div>\n}\n", styles: [":host{display:block;height:calc(100% - 10px);max-height:fit-content;overflow:hidden;--feed-header-height: 48px;-webkit-box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12);box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 1px 5px rgba(0,0,0,.12);-webkit-margin-start:10px;margin-inline-start:10px;-webkit-margin-end:10px;margin-inline-end:10px;margin-top:0;margin-bottom:10px;--feed-border-radius: 4px;border-radius:var(--feed-border-radius);--ion-card-background: rgba(var(--ion-background-color-rgb), .6)}:host.shape-round{--feed-border-radius: 12px}ion-button{text-transform:unset;--color: rgba(var(--ion-color-contrast-rgb), .7)}ion-item.feed-header{height:var(--feed-header-height);margin:0;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);border-radius:var(--feed-border-radius) var(--feed-border-radius) 0 0}ion-item.feed-header ion-icon[slot=start]{-webkit-margin-end:8px;margin-inline-end:8px}.feed-content{height:auto;overflow-y:auto;--margin-bottom: 8px}.feed-content.has-header{height:calc(100% - var(--feed-header-height, 0))}.feed-content ion-card{--top-radius: 4px;--bottom-radius: 4px;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);margin:0 0 var(--margin-bottom) 0;border-radius:var(--top-radius) var(--top-radius) var(--bottom-radius) var(--bottom-radius);--ion-card-color-contrast-rgb: var(--ion-color-contrast-rgb, var(--ion-color-dark-rgb, 0, 0, 0));--color: rgba(var(--ion-card-color-contrast-rgb), .87)}.feed-content ion-card.first{--top-radius: 0}.feed-content ion-card.last{--margin-bottom: 0;--bottom-radius: 0}.feed-content ion-card ion-card-header ion-card-title{--color: rgba(var(--ion-card-color-contrast-rgb), .87)}.feed-content ion-card ion-card-header ion-card-subtitle ion-chip{--background: transparent;--border-color: transparent;--border-width: 0}.feed-content ion-card ion-card-header ion-card-subtitle ion-chip ion-avatar{--color: rgba(var(--ion-card-color-contrast-rgb), .6);border:1px solid var(--color)}.feed-content ion-card ion-card-header ion-card-subtitle ion-chip ion-label{--color: rgba(var(--ion-card-color-contrast-rgb), .8);color:var(--color)}.feed-content ion-card ion-card-header ion-card-subtitle ion-note{--color: rgba(var(--ion-card-color-contrast-rgb), .6);color:var(--color)}.feed-content ion-card ion-card-header .tags{display:inline}.feed-content ion-card ion-card-header .tags a{color:rgba(var(--ion-card-color-contrast-rgb),.6)!important}.feed-content ion-card ion-card-content ion-text ::ng-deep img{max-width:100%;height:auto!important}\n"], dependencies: [{ kind: "component", type: i2$1.IonAvatar, selector: "ion-avatar" }, { kind: "component", type: i2$1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2$1.IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: i2$1.IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: i2$1.IonCardHeader, selector: "ion-card-header", inputs: ["color", "mode", "translucent"] }, { kind: "component", type: i2$1.IonCardSubtitle, selector: "ion-card-subtitle", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonCardTitle, selector: "ion-card-title", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonChip, selector: "ion-chip", inputs: ["color", "disabled", "mode", "outline"] }, { kind: "component", type: i2$1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2$1.IonImg, selector: "ion-img", inputs: ["alt", "src"] }, { kind: "component", type: i2$1.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2$1.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2$1.IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: i4$2.MarkdownComponent, selector: "markdown, [markdown]", inputs: ["data", "src", "disableSanitizer", "inline", "clipboard", "clipboardButtonComponent", "clipboardButtonTemplate", "emoji", "katex", "katexOptions", "mermaid", "mermaidOptions", "lineHighlight", "line", "lineOffset", "lineNumbers", "start", "commandLine", "filterOutput", "host", "prompt", "output", "user"], outputs: ["error", "load", "ready"] }, { kind: "component", type: DebugComponent, selector: "app-debug", inputs: ["titlePrefix", "title", "enable", "expanded"] }, { kind: "directive", type: MarkdownDirective, selector: "markdown,[markdown]" }, { kind: "directive", type: FeedDirective, selector: "feed,[feed]", inputs: ["feed"] }, { kind: "pipe", type: i3$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3$1.JsonPipe, name: "json" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }, { kind: "pipe", type: DateFromNowPipe, name: "dateFromNow" }, { kind: "pipe", type: NotEmptyArrayPipe, name: "isNotEmptyArray" }, { kind: "pipe", type: ArrayFirstPipe, name: "arrayFirst" }, { kind: "pipe", type: MapPipe, name: "map" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
35015
|
+
getFeedHomeUrl(feed) {
|
|
35016
|
+
return feed.home_page_url ?? JsonFeedUtils.removeJsonExtension(feed.feed_url) ?? this.feedService.getHomeUrl();
|
|
35017
|
+
}
|
|
35018
|
+
/**
|
|
35019
|
+
* Check if the current user is the author of the feed item
|
|
35020
|
+
*/
|
|
35021
|
+
canEditItem = (item, userId, feed) => {
|
|
35022
|
+
if (!item || isNil(userId))
|
|
35023
|
+
return false; // No item, or user not connected
|
|
35024
|
+
// DEBUG
|
|
35025
|
+
//console.debug('[feed-component] canEditItem...');
|
|
35026
|
+
// Check feed URL point on the current peer (/api/feed/ ...)
|
|
35027
|
+
if (!item.url?.startsWith(this.peerUrl))
|
|
35028
|
+
return false;
|
|
35029
|
+
// Check item authors first
|
|
35030
|
+
let isAuthor = false;
|
|
35031
|
+
if (isNotEmptyArray(item.authors)) {
|
|
35032
|
+
isAuthor = item.authors.some((author) => +author.id === userId);
|
|
35033
|
+
}
|
|
35034
|
+
// Check feed authors
|
|
35035
|
+
if (!isAuthor && isNotEmptyArray(feed?.authors)) {
|
|
35036
|
+
isAuthor = feed.authors.some((author) => +author.id === userId);
|
|
35037
|
+
}
|
|
35038
|
+
return isAuthor || this.accountService.isAdmin();
|
|
35039
|
+
};
|
|
35040
|
+
/**
|
|
35041
|
+
* Handle edit item action
|
|
35042
|
+
*/
|
|
35043
|
+
async onEditItem(event, item) {
|
|
35044
|
+
if (event) {
|
|
35045
|
+
event.preventDefault();
|
|
35046
|
+
event.stopPropagation();
|
|
35047
|
+
}
|
|
35048
|
+
if (this.editItem.observed) {
|
|
35049
|
+
this.editItem.emit(item);
|
|
35050
|
+
}
|
|
35051
|
+
const done = await this.feedService?.openEditModal(event, item);
|
|
35052
|
+
if (done) {
|
|
35053
|
+
// force a refresh of the feeds
|
|
35054
|
+
this.onRefresh.emit();
|
|
35055
|
+
}
|
|
35056
|
+
}
|
|
35057
|
+
/**
|
|
35058
|
+
* Handle delete item action
|
|
35059
|
+
*/
|
|
35060
|
+
async onDeleteItem(event, item) {
|
|
35061
|
+
if (event) {
|
|
35062
|
+
event.preventDefault();
|
|
35063
|
+
event.stopPropagation();
|
|
35064
|
+
}
|
|
35065
|
+
// Ask for confirmation before deletion
|
|
35066
|
+
const confirmed = await Alerts.askActionConfirmation(this.alertCtrl, this.translate, true, event);
|
|
35067
|
+
if (confirmed !== true) {
|
|
35068
|
+
return; // User cancelled or dismissed
|
|
35069
|
+
}
|
|
35070
|
+
if (this.deleteItem.observed) {
|
|
35071
|
+
this.deleteItem.emit(item);
|
|
35072
|
+
}
|
|
35073
|
+
const done = await this.feedService?.deleteItem(item);
|
|
35074
|
+
if (done) {
|
|
35075
|
+
// force a refresh of the feeds
|
|
35076
|
+
this.onRefresh.emit();
|
|
35077
|
+
}
|
|
35078
|
+
}
|
|
35079
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FeedsComponent, deps: [{ token: LocalSettingsService }, { token: ENVIRONMENT }, { token: APP_FEED_SERVICE, optional: true }, { token: AccountService }, { token: i2$1.AlertController }], target: i0.ɵɵFactoryTarget.Component });
|
|
35080
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: FeedsComponent, selector: "app-feed", inputs: { debug: "debug", mobile: "mobile", showHeader: "showHeader", showReadMoreButton: "showReadMoreButton", headerColor: "headerColor", cardColor: "cardColor", shape: "shape", class: "class", itemId: "itemId", filterItem: "filterItem", feeds: "feeds", urls: "urls", maxAgeInMonths: "maxAgeInMonths", maxContentLength: "maxContentLength" }, outputs: { editItem: "editItem", deleteItem: "deleteItem" }, host: { properties: { "class": "this.hostClass" } }, providers: [RxState], viewQueries: [{ propertyName: "modal", first: true, predicate: ["modal"], descendants: true }], ngImport: i0, template: "<!-- debug -->\n@if (debug) {\n <app-debug [title]=\"'Feed'\">\n <p>\n hasFeeds?: {{ hasFeeds$ | async }}\n <br />\n urls: {{ urls$ | async | json }}\n <br />\n shape: {{ shape }}\n </p>\n </app-debug>\n}\n\n@let feeds = feeds$ | async;\n@let userId = userId$ | async;\n\n@if (feeds | isNotEmptyArray) {\n <!-- top header -->\n @if (showHeader && (feeds | arrayFirst); as feed) {\n <ion-item lines=\"none\" [color]=\"headerColor\" class=\"feed-header shape-{{ shape }}\">\n <ion-icon slot=\"start\" name=\"megaphone\"></ion-icon>\n <ion-label>\n <b>{{ feed.title || ('SOCIAL.FEED.NEWS' | translate) }}</b>\n </ion-label>\n <ion-button slot=\"end\" fill=\"clear\" (click)=\"openFeedHome()\" shape=\"\">\n <ion-label translate>SOCIAL.FEED.SHOW_ALL_FEED</ion-label>\n <ion-icon slot=\"end\" name=\"chevron-forward-outline\"></ion-icon>\n </ion-button>\n </ion-item>\n }\n\n <div class=\"feed-content shape-{{ shape }} ion-no-padding\" [class.has-header]=\"showHeader\">\n <!-- feeds -->\n @for (feed of feeds; track feed.feed_url; let firstFeed = $first; let lastFeed = $last) {\n <!-- items -->\n @for (item of feed.items | arrayFilter: filterItem; track item.id; let firstItem = $first; let lastItem = $last) {\n <ion-card\n [class.first]=\"firstFeed && firstItem\"\n [class.last]=\"lastFeed && lastItem\"\n [color]=\"cardColor !== 'light-transparent' ? cardColor : undefined\"\n class=\"feed-item-card\"\n >\n <ion-card-header>\n <ion-card-subtitle style=\"vertical-align: middle\">\n <!-- Authors -->\n @for (author of item.authors || feed.authors; track author) {\n @if (author.name || author.avatar) {\n <ion-chip (click)=\"openUrl(author.url)\" tappable>\n @if (author.avatar) {\n <ion-avatar>\n <ion-img [src]=\"author.avatar\" [alt]=\"author.name\"></ion-img>\n </ion-avatar>\n }\n @if (author.name) {\n <ion-label class=\"author\">{{ author.name }}</ion-label>\n }\n </ion-chip>\n }\n }\n <ion-note class=\"ion-float-end\">\n <small>{{ item.date_published | dateFromNow }}</small>\n </ion-note>\n </ion-card-subtitle>\n\n <!-- title -->\n <ion-card-title (click)=\"openFeedItem(item, feed)\" tappable>{{ item?.title }}</ion-card-title>\n\n <!-- tags -->\n @let tags = item | map: getTags;\n @if (tags | isNotEmptyArray) {\n <ion-text class=\"tags\">\n @for (tag of tags; track tag; let last = $last) {\n <a (click)=\"openTag(feed, tag)\" tappable>\n <ion-text>#{{ tag }}</ion-text>\n </a>\n @if (!last) {\n \n }\n }\n </ion-text>\n }\n </ion-card-header>\n\n <!-- Feed content -->\n <ion-card-content>\n <ion-text [feed]=\"item.url || feed.feed_url\">\n @if (item.content_html) {\n <p [innerHTML]=\"item.content_html\"></p>\n } @else if (item.content_text) {\n <p>\n <markdown [data]=\"item.content_text\" emoji></markdown>\n </p>\n }\n </ion-text>\n </ion-card-content>\n\n @let editable = canEditItem(item, userId, feed);\n @if (editable || showReadMoreButton) {\n @if (editable) {\n\n <!-- Delete button (visible hover)-->\n <button\n mat-icon-button\n (click)=\"onDeleteItem($event, item)\"\n class=\"visible-hover ion-float-start\"\n [title]=\"'COMMON.BTN_DELETE' | translate\"\n >\n <mat-icon>delete</mat-icon>\n </button>\n <!-- Edit button (visible hover) -->\n <ion-button\n (click)=\"onEditItem($event, item)\"\n class=\"visible-hover ion-float-start\" fill=\"clear\"\n >\n <mat-icon slot=\"start\">edit</mat-icon>\n<!-- <ion-icon name=\"pencil\" slot=\"start\"></ion-icon>-->\n <ion-label translate>COMMON.BTN_EDIT</ion-label>\n </ion-button>\n }\n @if (showReadMoreButton) {\n <ion-button (click)=\"openFeedItem(item, feed)\" class=\"ion-float-end\" fill=\"clear\">\n <ion-label>{{ (item.truncated ? 'SOCIAL.FEED.READ_MORE' : 'COMMON.BTN_SHOW') | translate }}</ion-label>\n <ion-icon slot=\"end\" name=\"chevron-forward-outline\"></ion-icon>\n </ion-button>\n }\n }\n </ion-card>\n }\n }\n </div>\n}\n\n<!-- Details modal -->\n<ion-modal #modal [showBackdrop]=\"false\"\n class=\"stack-modal\" [class.modal-large]=\"!mobile\">\n <ng-template>\n <ion-header>\n <ion-toolbar color=\"secondary\">\n <ion-title>{{ 'SOCIAL.FEED.NEWS' | translate }}</ion-title>\n <ion-buttons slot=\"end\">\n <ion-button (click)=\"modal.dismiss()\">\n <ion-icon slot=\"icon-only\" name=\"close\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content>\n <div class=\"ion-padding\">\n <app-feed\n [urls]=\"urls\"\n [showHeader]=\"false\"\n [showReadMoreButton]=\"false\"\n [maxContentLength]=\"-1\"\n [maxAgeInMonths]=\"-1\"\n [itemId]=\"modalItemId\"\n cardColor=\"light\"\n [debug]=\"debug\"\n ></app-feed>\n </div>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [":host{display:block;height:calc(100% - 10px);max-height:fit-content;overflow:hidden;--feed-header-height: 48px;-webkit-box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12);box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 1px 5px rgba(0,0,0,.12);-webkit-margin-start:10px;margin-inline-start:10px;-webkit-margin-end:10px;margin-inline-end:10px;margin-top:0;margin-bottom:10px;--feed-border-radius: 4px;border-radius:var(--feed-border-radius);--ion-card-background: rgba(var(--ion-background-color-rgb), .6)}:host.shape-round{--feed-border-radius: 12px}ion-button{text-transform:unset;--color: rgba(var(--ion-color-contrast-rgb), .7)}ion-item.feed-header{height:var(--feed-header-height);margin:0;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);border-radius:var(--feed-border-radius) var(--feed-border-radius) 0 0}ion-item.feed-header ion-icon[slot=start]{-webkit-margin-end:8px;margin-inline-end:8px}.feed-content{height:auto;overflow-y:auto;--margin-bottom: 8px}.feed-content.has-header{height:calc(100% - var(--feed-header-height, 0))}.feed-content ion-card.feed-item-card{--top-radius: 4px;--bottom-radius: 4px;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);margin:0 0 var(--margin-bottom) 0;border-radius:var(--top-radius) var(--top-radius) var(--bottom-radius) var(--bottom-radius);--ion-card-color-contrast-rgb: var(--ion-color-contrast-rgb, var(--ion-color-dark-rgb, 0, 0, 0));--color: rgba(var(--ion-card-color-contrast-rgb), .87)}.feed-content ion-card.feed-item-card.first{--top-radius: 0}.feed-content ion-card.feed-item-card.last{--margin-bottom: 0;--bottom-radius: 0}.feed-content ion-card.feed-item-card ion-card-header ion-card-title{--color: rgba(var(--ion-card-color-contrast-rgb), .87)}.feed-content ion-card.feed-item-card ion-card-header ion-card-subtitle ion-chip{--background: transparent;--border-color: transparent;--border-width: 0}.feed-content ion-card.feed-item-card ion-card-header ion-card-subtitle ion-chip ion-avatar{--color: rgba(var(--ion-card-color-contrast-rgb), .6);border:1px solid var(--color)}.feed-content ion-card.feed-item-card ion-card-header ion-card-subtitle ion-chip ion-label{--color: rgba(var(--ion-card-color-contrast-rgb), .8);color:var(--color)}.feed-content ion-card.feed-item-card ion-card-header ion-card-subtitle ion-note{--color: rgba(var(--ion-card-color-contrast-rgb), .6);color:var(--color)}.feed-content ion-card.feed-item-card ion-card-header .tags{display:inline}.feed-content ion-card.feed-item-card ion-card-header .tags a{color:rgba(var(--ion-card-color-contrast-rgb),.6)!important}.feed-content ion-card.feed-item-card ion-card-content ion-text ::ng-deep img{max-width:100%;height:auto!important}.feed-content ion-card.feed-item-card .visible-hover{opacity:0;transition:opacity .2s ease-in-out}.feed-content ion-card.feed-item-card:hover .visible-hover{opacity:1}\n"], dependencies: [{ kind: "component", type: i2$1.IonAvatar, selector: "ion-avatar" }, { kind: "component", type: i2$1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2$1.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i2$1.IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: i2$1.IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: i2$1.IonCardHeader, selector: "ion-card-header", inputs: ["color", "mode", "translucent"] }, { kind: "component", type: i2$1.IonCardSubtitle, selector: "ion-card-subtitle", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonCardTitle, selector: "ion-card-title", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonChip, selector: "ion-chip", inputs: ["color", "disabled", "mode", "outline"] }, { kind: "component", type: i2$1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2$1.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2$1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2$1.IonImg, selector: "ion-img", inputs: ["alt", "src"] }, { kind: "component", type: i2$1.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2$1.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2$1.IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: i2$1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonModal, selector: "ion-modal" }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: i4$2.MarkdownComponent, selector: "markdown, [markdown]", inputs: ["data", "src", "disableSanitizer", "inline", "clipboard", "clipboardButtonComponent", "clipboardButtonTemplate", "emoji", "katex", "katexOptions", "mermaid", "mermaidOptions", "lineHighlight", "line", "lineOffset", "lineNumbers", "start", "commandLine", "filterOutput", "host", "prompt", "output", "user"], outputs: ["error", "load", "ready"] }, { kind: "component", type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i9.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: DebugComponent, selector: "app-debug", inputs: ["titlePrefix", "title", "enable", "expanded"] }, { kind: "directive", type: MarkdownDirective, selector: "markdown,[markdown]" }, { kind: "component", type: FeedsComponent, selector: "app-feed", inputs: ["debug", "mobile", "showHeader", "showReadMoreButton", "headerColor", "cardColor", "shape", "class", "itemId", "filterItem", "feeds", "urls", "maxAgeInMonths", "maxContentLength"], outputs: ["editItem", "deleteItem"] }, { kind: "directive", type: FeedDirective, selector: "feed,[feed]", inputs: ["feed"] }, { kind: "pipe", type: i3$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i3$1.JsonPipe, name: "json" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }, { kind: "pipe", type: DateFromNowPipe, name: "dateFromNow" }, { kind: "pipe", type: NotEmptyArrayPipe, name: "isNotEmptyArray" }, { kind: "pipe", type: ArrayFirstPipe, name: "arrayFirst" }, { kind: "pipe", type: ArrayFilterPipe, name: "arrayFilter" }, { kind: "pipe", type: MapPipe, name: "map" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
34179
35081
|
}
|
|
34180
35082
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FeedsComponent, decorators: [{
|
|
34181
35083
|
type: Component,
|
|
34182
|
-
args: [{ selector: 'app-feed', providers: [RxState], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- debug -->\n@if (debug) {\n <app-debug [title]=\"'Feed'\">\n <p>\n hasFeeds?: {{ hasFeeds$ | async }}\n <br />\n
|
|
34183
|
-
}], ctorParameters: () => [{ type: Environment, decorators: [{
|
|
35084
|
+
args: [{ selector: 'app-feed', providers: [RxState], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- debug -->\n@if (debug) {\n <app-debug [title]=\"'Feed'\">\n <p>\n hasFeeds?: {{ hasFeeds$ | async }}\n <br />\n urls: {{ urls$ | async | json }}\n <br />\n shape: {{ shape }}\n </p>\n </app-debug>\n}\n\n@let feeds = feeds$ | async;\n@let userId = userId$ | async;\n\n@if (feeds | isNotEmptyArray) {\n <!-- top header -->\n @if (showHeader && (feeds | arrayFirst); as feed) {\n <ion-item lines=\"none\" [color]=\"headerColor\" class=\"feed-header shape-{{ shape }}\">\n <ion-icon slot=\"start\" name=\"megaphone\"></ion-icon>\n <ion-label>\n <b>{{ feed.title || ('SOCIAL.FEED.NEWS' | translate) }}</b>\n </ion-label>\n <ion-button slot=\"end\" fill=\"clear\" (click)=\"openFeedHome()\" shape=\"\">\n <ion-label translate>SOCIAL.FEED.SHOW_ALL_FEED</ion-label>\n <ion-icon slot=\"end\" name=\"chevron-forward-outline\"></ion-icon>\n </ion-button>\n </ion-item>\n }\n\n <div class=\"feed-content shape-{{ shape }} ion-no-padding\" [class.has-header]=\"showHeader\">\n <!-- feeds -->\n @for (feed of feeds; track feed.feed_url; let firstFeed = $first; let lastFeed = $last) {\n <!-- items -->\n @for (item of feed.items | arrayFilter: filterItem; track item.id; let firstItem = $first; let lastItem = $last) {\n <ion-card\n [class.first]=\"firstFeed && firstItem\"\n [class.last]=\"lastFeed && lastItem\"\n [color]=\"cardColor !== 'light-transparent' ? cardColor : undefined\"\n class=\"feed-item-card\"\n >\n <ion-card-header>\n <ion-card-subtitle style=\"vertical-align: middle\">\n <!-- Authors -->\n @for (author of item.authors || feed.authors; track author) {\n @if (author.name || author.avatar) {\n <ion-chip (click)=\"openUrl(author.url)\" tappable>\n @if (author.avatar) {\n <ion-avatar>\n <ion-img [src]=\"author.avatar\" [alt]=\"author.name\"></ion-img>\n </ion-avatar>\n }\n @if (author.name) {\n <ion-label class=\"author\">{{ author.name }}</ion-label>\n }\n </ion-chip>\n }\n }\n <ion-note class=\"ion-float-end\">\n <small>{{ item.date_published | dateFromNow }}</small>\n </ion-note>\n </ion-card-subtitle>\n\n <!-- title -->\n <ion-card-title (click)=\"openFeedItem(item, feed)\" tappable>{{ item?.title }}</ion-card-title>\n\n <!-- tags -->\n @let tags = item | map: getTags;\n @if (tags | isNotEmptyArray) {\n <ion-text class=\"tags\">\n @for (tag of tags; track tag; let last = $last) {\n <a (click)=\"openTag(feed, tag)\" tappable>\n <ion-text>#{{ tag }}</ion-text>\n </a>\n @if (!last) {\n \n }\n }\n </ion-text>\n }\n </ion-card-header>\n\n <!-- Feed content -->\n <ion-card-content>\n <ion-text [feed]=\"item.url || feed.feed_url\">\n @if (item.content_html) {\n <p [innerHTML]=\"item.content_html\"></p>\n } @else if (item.content_text) {\n <p>\n <markdown [data]=\"item.content_text\" emoji></markdown>\n </p>\n }\n </ion-text>\n </ion-card-content>\n\n @let editable = canEditItem(item, userId, feed);\n @if (editable || showReadMoreButton) {\n @if (editable) {\n\n <!-- Delete button (visible hover)-->\n <button\n mat-icon-button\n (click)=\"onDeleteItem($event, item)\"\n class=\"visible-hover ion-float-start\"\n [title]=\"'COMMON.BTN_DELETE' | translate\"\n >\n <mat-icon>delete</mat-icon>\n </button>\n <!-- Edit button (visible hover) -->\n <ion-button\n (click)=\"onEditItem($event, item)\"\n class=\"visible-hover ion-float-start\" fill=\"clear\"\n >\n <mat-icon slot=\"start\">edit</mat-icon>\n<!-- <ion-icon name=\"pencil\" slot=\"start\"></ion-icon>-->\n <ion-label translate>COMMON.BTN_EDIT</ion-label>\n </ion-button>\n }\n @if (showReadMoreButton) {\n <ion-button (click)=\"openFeedItem(item, feed)\" class=\"ion-float-end\" fill=\"clear\">\n <ion-label>{{ (item.truncated ? 'SOCIAL.FEED.READ_MORE' : 'COMMON.BTN_SHOW') | translate }}</ion-label>\n <ion-icon slot=\"end\" name=\"chevron-forward-outline\"></ion-icon>\n </ion-button>\n }\n }\n </ion-card>\n }\n }\n </div>\n}\n\n<!-- Details modal -->\n<ion-modal #modal [showBackdrop]=\"false\"\n class=\"stack-modal\" [class.modal-large]=\"!mobile\">\n <ng-template>\n <ion-header>\n <ion-toolbar color=\"secondary\">\n <ion-title>{{ 'SOCIAL.FEED.NEWS' | translate }}</ion-title>\n <ion-buttons slot=\"end\">\n <ion-button (click)=\"modal.dismiss()\">\n <ion-icon slot=\"icon-only\" name=\"close\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content>\n <div class=\"ion-padding\">\n <app-feed\n [urls]=\"urls\"\n [showHeader]=\"false\"\n [showReadMoreButton]=\"false\"\n [maxContentLength]=\"-1\"\n [maxAgeInMonths]=\"-1\"\n [itemId]=\"modalItemId\"\n cardColor=\"light\"\n [debug]=\"debug\"\n ></app-feed>\n </div>\n </ion-content>\n </ng-template>\n</ion-modal>\n", styles: [":host{display:block;height:calc(100% - 10px);max-height:fit-content;overflow:hidden;--feed-header-height: 48px;-webkit-box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12);box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 1px 5px rgba(0,0,0,.12);-webkit-margin-start:10px;margin-inline-start:10px;-webkit-margin-end:10px;margin-inline-end:10px;margin-top:0;margin-bottom:10px;--feed-border-radius: 4px;border-radius:var(--feed-border-radius);--ion-card-background: rgba(var(--ion-background-color-rgb), .6)}:host.shape-round{--feed-border-radius: 12px}ion-button{text-transform:unset;--color: rgba(var(--ion-color-contrast-rgb), .7)}ion-item.feed-header{height:var(--feed-header-height);margin:0;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);border-radius:var(--feed-border-radius) var(--feed-border-radius) 0 0}ion-item.feed-header ion-icon[slot=start]{-webkit-margin-end:8px;margin-inline-end:8px}.feed-content{height:auto;overflow-y:auto;--margin-bottom: 8px}.feed-content.has-header{height:calc(100% - var(--feed-header-height, 0))}.feed-content ion-card.feed-item-card{--top-radius: 4px;--bottom-radius: 4px;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);margin:0 0 var(--margin-bottom) 0;border-radius:var(--top-radius) var(--top-radius) var(--bottom-radius) var(--bottom-radius);--ion-card-color-contrast-rgb: var(--ion-color-contrast-rgb, var(--ion-color-dark-rgb, 0, 0, 0));--color: rgba(var(--ion-card-color-contrast-rgb), .87)}.feed-content ion-card.feed-item-card.first{--top-radius: 0}.feed-content ion-card.feed-item-card.last{--margin-bottom: 0;--bottom-radius: 0}.feed-content ion-card.feed-item-card ion-card-header ion-card-title{--color: rgba(var(--ion-card-color-contrast-rgb), .87)}.feed-content ion-card.feed-item-card ion-card-header ion-card-subtitle ion-chip{--background: transparent;--border-color: transparent;--border-width: 0}.feed-content ion-card.feed-item-card ion-card-header ion-card-subtitle ion-chip ion-avatar{--color: rgba(var(--ion-card-color-contrast-rgb), .6);border:1px solid var(--color)}.feed-content ion-card.feed-item-card ion-card-header ion-card-subtitle ion-chip ion-label{--color: rgba(var(--ion-card-color-contrast-rgb), .8);color:var(--color)}.feed-content ion-card.feed-item-card ion-card-header ion-card-subtitle ion-note{--color: rgba(var(--ion-card-color-contrast-rgb), .6);color:var(--color)}.feed-content ion-card.feed-item-card ion-card-header .tags{display:inline}.feed-content ion-card.feed-item-card ion-card-header .tags a{color:rgba(var(--ion-card-color-contrast-rgb),.6)!important}.feed-content ion-card.feed-item-card ion-card-content ion-text ::ng-deep img{max-width:100%;height:auto!important}.feed-content ion-card.feed-item-card .visible-hover{opacity:0;transition:opacity .2s ease-in-out}.feed-content ion-card.feed-item-card:hover .visible-hover{opacity:1}\n"] }]
|
|
35085
|
+
}], ctorParameters: () => [{ type: LocalSettingsService }, { type: Environment, decorators: [{
|
|
34184
35086
|
type: Inject,
|
|
34185
35087
|
args: [ENVIRONMENT]
|
|
34186
35088
|
}] }, { type: undefined, decorators: [{
|
|
@@ -34188,10 +35090,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
34188
35090
|
}, {
|
|
34189
35091
|
type: Inject,
|
|
34190
35092
|
args: [APP_FEED_SERVICE]
|
|
34191
|
-
}] }], propDecorators: { debug: [{
|
|
35093
|
+
}] }, { type: AccountService }, { type: i2$1.AlertController }], propDecorators: { debug: [{
|
|
35094
|
+
type: Input
|
|
35095
|
+
}], mobile: [{
|
|
34192
35096
|
type: Input
|
|
34193
35097
|
}], showHeader: [{
|
|
34194
35098
|
type: Input
|
|
35099
|
+
}], showReadMoreButton: [{
|
|
35100
|
+
type: Input
|
|
34195
35101
|
}], headerColor: [{
|
|
34196
35102
|
type: Input
|
|
34197
35103
|
}], cardColor: [{
|
|
@@ -34200,9 +35106,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
34200
35106
|
type: Input
|
|
34201
35107
|
}], class: [{
|
|
34202
35108
|
type: Input
|
|
35109
|
+
}], itemId: [{
|
|
35110
|
+
type: Input
|
|
35111
|
+
}], filterItem: [{
|
|
35112
|
+
type: Input
|
|
35113
|
+
}], editItem: [{
|
|
35114
|
+
type: Output
|
|
35115
|
+
}], deleteItem: [{
|
|
35116
|
+
type: Output
|
|
34203
35117
|
}], feeds: [{
|
|
34204
35118
|
type: Input
|
|
34205
|
-
}],
|
|
35119
|
+
}], urls: [{
|
|
34206
35120
|
type: Input
|
|
34207
35121
|
}], maxAgeInMonths: [{
|
|
34208
35122
|
type: Input
|
|
@@ -34211,6 +35125,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
34211
35125
|
}], hostClass: [{
|
|
34212
35126
|
type: HostBinding,
|
|
34213
35127
|
args: ['class']
|
|
35128
|
+
}], modal: [{
|
|
35129
|
+
type: ViewChild,
|
|
35130
|
+
args: ['modal']
|
|
34214
35131
|
}] } });
|
|
34215
35132
|
|
|
34216
35133
|
/**
|
|
@@ -34586,11 +35503,11 @@ class HomePage extends RxState {
|
|
|
34586
35503
|
this.cd.markForCheck();
|
|
34587
35504
|
}
|
|
34588
35505
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: HomePage, deps: [{ token: AccountService }, { token: i2$1.ModalController }, { token: i1$1.TranslateService }, { token: i2$1.ToastController }, { token: ConfigService }, { token: PlatformService }, { token: i0.ChangeDetectorRef }, { token: NetworkService }, { token: LocalSettingsService }, { token: ENVIRONMENT }, { token: APP_LOCALES }, { token: APP_HOME_BUTTONS, optional: true }, { token: APP_HOME_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
34589
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: HomePage, selector: "app-page-home", viewQueries: [{ propertyName: "content", first: true, predicate: IonContent, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<app-toolbar [canGoBack]=\"false\" visible-xs visible-sm visible-mobile>\n <ion-buttons slot=\"end\">\n @if (showNotificationIcon) {\n <app-user-event-notification-icon [autoHide]=\"autoHideNotificationIcon\"></app-user-event-notification-icon>\n }\n\n <!-- dark mode (if allow by the environment token) -->\n @if (settings.allowDarkMode) {\n <ion-button (click)=\"toggleDarkMode()\">\n <ion-icon slot=\"icon-only\" [name]=\"(darkMode$ | push) ? 'sunny' : 'moon'\"></ion-icon>\n </ion-button>\n }\n\n <!-- Change locale button -->\n <ion-button [matMenuTriggerFor]=\"localeMenu\">\n <ion-icon slot=\"start\" name=\"language\"></ion-icon>\n </ion-button>\n </ion-buttons>\n</app-toolbar>\n\n<!-- Change locale menu -->\n<mat-menu #localeMenu=\"matMenu\">\n <ng-template matMenuContent>\n @for (item of locales; track item.key) {\n <button mat-menu-item (click)=\"changeLanguage(item.key)\">\n <!--<mat-icon>{{ currentLocale === item.key ? 'checkmark' : undefined }}</mat-icon>-->\n <ion-label>{{ item.value }}</ion-label>\n </button>\n }\n </ng-template>\n</mat-menu>\n\n<ion-content [ngStyle]=\"contentStyle\" [class.has-scrollbar]=\"hasScrollbar\" no-padding-xs>\n <!-- loading spinner -->\n <div class=\"loading-page\" [class.cdk-visually-hidden]=\"!(loading$ | push)\">\n @if (showSpinner) {\n <div class=\"spinner\">\n <p [innerHTML]=\"'COMMON.LOADING_DOTS' | translate\"></p>\n <div class=\"sk-cube1 sk-cube\"></div>\n <div class=\"sk-cube2 sk-cube\"></div>\n <div class=\"sk-cube4 sk-cube\"></div>\n <div class=\"sk-cube3 sk-cube\"></div>\n </div>\n }\n </div>\n\n <!-- Desktop: translucent top toolbar -->\n @if (!mobile) {\n <div class=\"hidden-xs hidden-sm\">\n <ion-toolbar color=\"traansparent\" translucent>\n <ion-buttons slot=\"start\">\n <ion-menu-toggle>\n <ion-button color=\"light\" fill=\"clear\">\n <ion-icon slot=\"icon-only\" name=\"menu\"></ion-icon>\n </ion-button>\n </ion-menu-toggle>\n </ion-buttons>\n\n <ion-buttons slot=\"end\">\n @if (showNotificationIcon) {\n <app-user-event-notification-icon\n [style]=\"'ion-button'\"\n color=\"secondary\"\n unreadColor=\"tertiary\"\n fill=\"solid\"\n [autoHide]=\"autoHideNotificationIcon\"\n ></app-user-event-notification-icon>\n }\n\n <!-- dark mode (if allow by the environment token) -->\n @if (settings.allowDarkMode) {\n <ion-button\n color=\"secondary\"\n fill=\"solid\"\n (click)=\"toggleDarkMode()\"\n [title]=\"'HOME.BTN_DARK_MODE' | translate\"\n >\n <ion-icon slot=\"icon-only\" [name]=\"(darkMode$ | push) ? 'moon' : 'sunny'\"></ion-icon>\n </ion-button>\n }\n <!-- change locale button -->\n <ion-button\n color=\"secondary\"\n fill=\"solid\"\n [matMenuTriggerFor]=\"localeMenu\"\n [title]=\"'SETTINGS.LOCALE' | translate\"\n >\n <ion-icon slot=\"icon-only\" name=\"language\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </div>\n }\n\n <!-- Install (and upgrade) card -->\n <app-install-upgrade-card [isLogin]=\"isLogin\" [showInstallButton]=\"true\"></app-install-upgrade-card>\n\n @if (!(loading$ | push)) {\n @let hasFeed = hasFeed$ | async;\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col size=\"0\" [sizeXl]=\"hasFeed ? 3 : 0\"></ion-col>\n <ion-col>\n <!-- Welcome card -->\n <ion-card class=\"main welcome ion-padding ion-text-center ion-align-self-center\" @fadeInAnimation>\n <ion-card-header>\n <ion-card-title class=\"ion-text-center\">\n <span *ngIf=\"isWeb\" [innerHTML]=\"'HOME.WELCOME_WEB' | translate: { appName: appName }\"></span>\n <span *ngIf=\"!isWeb\" [innerHTML]=\"'HOME.WELCOME_APP' | translate: { appName: appName }\"></span>\n </ion-card-title>\n <ion-card-subtitle [innerHTML]=\"description\"></ion-card-subtitle>\n </ion-card-header>\n <ion-card-content class=\"ion-no-padding\">\n <ion-text color=\"primary\">\n <img *ngIf=\"logo\" [attr.src]=\"logo\" alt=\"Logo\" />\n </ion-text>\n <!-- register help text -->\n <ion-text *ngIf=\"!isLogin && canRegister\">\n <br />\n <span translate>HOME.REGISTER_HELP</span>\n </ion-text>\n <div class=\"ion-padding-top\">\n <!-- If NOT login -->\n <ng-container *ngIf=\"!isLogin; else loginButtons\">\n <ion-button *ngIf=\"canRegister\" expand=\"block\" color=\"tertiary\" (click)=\"register()\">\n <span translate>HOME.BTN_REGISTER</span>\n </ion-button>\n <ion-button expand=\"block\" color=\"light\" [routerLink]=\"['/']\" (click)=\"login()\">\n <span translate>AUTH.BTN_LOGIN</span>\n </ion-button>\n </ng-container>\n\n <!-- If user login -->\n <ng-template #loginButtons>\n <!-- Feature buttons -->\n <ng-container *rxIf=\"$filteredButtons; let buttons\">\n <ng-container *ngFor=\"let item of buttons\">\n <ion-button\n *ngIf=\"item.path\"\n expand=\"block\"\n color=\"tertiary\"\n [class]=\"item.cssClass\"\n [routerLink]=\"item.path\"\n routerDirection=\"root\"\n >\n <ion-icon slot=\"start\" class=\"ion-float-start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" class=\"ion-float-start\" *ngIf=\"item.matIcon\">\n {{ item.matIcon }}\n </mat-icon>\n <ion-text>{{ 'HOME.BTN_DATA_ENTRY' | translate: { name: (item.title | translate) } }}</ion-text>\n </ion-button>\n\n <!-- divider -->\n <div *ngIf=\"!item.path && !item.action\" [class]=\"item.cssClass\">\n <ion-label translate>{{ item.title }} </ion-label>\n </div>\n </ng-container>\n\n <!--<p *ngIf=\"buttons.length\" class=\"visible-mobile\"> </p>-->\n </ng-container>\n\n <ion-button *ngIf=\"showAccountButton\" expand=\"block\" color=\"secondary\" [routerLink]=\"['/account']\">\n <ion-icon slot=\"start\" class=\"ion-float-start\" name=\"person-circle\"></ion-icon>\n <ion-text translate>HOME.BTN_MY_ACCOUNT</ion-text>\n </ion-button>\n\n <p hidden-xs hidden-sm hidden-mobile>\n <ion-text\n [innerHTML]=\"'HOME.NOT_THIS_ACCOUNT_QUESTION' | translate: { displayName: accountName }\"\n ></ion-text>\n <br />\n <ion-text>\n <a href=\"#\" (click)=\"logout($event)\">\n <span translate>HOME.BTN_DISCONNECT</span>\n </a>\n </ion-text>\n </p>\n </ng-template>\n </div>\n </ion-card-content>\n </ion-card>\n </ion-col>\n <ion-col size=\"0\" [sizeXl]=\"hasFeed ? 1 : 0\"></ion-col>\n <ion-col [class.feed]=\"hasFeed\" [size]=\"hasFeed ? 12 : 0\" [sizeXl]=\"hasFeed ? 4 : 0\">\n @if (showFeed) {\n @if (mobile) {\n <app-feed\n #feed\n shape=\"round\"\n [feedUrls]=\"feedUrls\"\n [maxAgeInMonths]=\"feedMaxAgeInMonths\"\n [maxContentLength]=\"feedMaxContentLength\"\n (ngInit)=\"initFeed(feed)\"\n @fadeInAnimation\n ></app-feed>\n } @else {\n <app-feed\n #feed\n shape=\"round\"\n [debug]=\"false\"\n [feedUrls]=\"feedUrls\"\n [maxAgeInMonths]=\"feedMaxAgeInMonths\"\n [maxContentLength]=\"feedMaxContentLength\"\n (ngInit)=\"initFeed(feed)\"\n @slideInAnimation\n @fadeInAnimation\n ></app-feed>\n }\n }\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Page history -->\n @let pageHistory = isLogin && (pageHistory$ | push);\n @if (pageHistory | isNotEmptyArray) {\n <ion-grid class=\"history-container ion-align-self-center\">\n <ion-row>\n @for (page of pageHistory; track page.path) {\n <ion-col size=\"12\" size-xl=\"\" class=\"ion-text-center\">\n <ion-card class=\"ion-align-self-start ion-text-start\" @fadeInAnimation>\n <ion-card-header class=\"ion-no-padding\">\n <!-- top bar -->\n <ion-card-subtitle>\n <button\n type=\"button\"\n tabindex=\"-1\"\n (click)=\"removePageHistory(page.path)\"\n mat-icon-button\n class=\"ion-float-start ion-no-margin close-button\"\n >\n <mat-icon>close</mat-icon>\n </button>\n <ion-label [innerHTML]=\"page.subtitle | translate\"></ion-label>\n <ion-text class=\"ion-float-end\" [title]=\"page.time | dateFormat: { time: true }\">\n <small>\n <ion-icon name=\"time-outline\"></ion-icon>\n {{ page.time | dateFromNow }}\n </small>\n \n </ion-text>\n </ion-card-subtitle>\n\n <!-- main page -->\n <ion-card-title class=\"ion-no-margin ion-no-padding\">\n <ion-item\n detail=\"true\"\n tappable\n class=\"text-1x\"\n [routerLink]=\"page.path\"\n routerDirection=\"root\"\n lines=\"none\"\n >\n <!-- page icon-->\n <ion-icon *ngIf=\"page.icon\" slot=\"start\" [name]=\"page.icon\"></ion-icon>\n <mat-icon *ngIf=\"page.matIcon\" slot=\"start\">{{ page.matIcon }}</mat-icon>\n\n <ion-label color=\"primary\" [innerHTML]=\"page.title\"></ion-label>\n </ion-item>\n </ion-card-title>\n </ion-card-header>\n\n <!-- children pages -->\n @if (page.children | isNotEmptyArray) {\n <ion-card-content class=\"ion-no-padding ion-padding-start\">\n <ion-list class=\"ion-no-padding\">\n @for (childPage of page.children; track childPage.path) {\n <ion-item\n detail=\"true\"\n tappable\n class=\"text-1x\"\n [routerLink]=\"childPage.path\"\n routerDirection=\"root\"\n >\n <!-- page icon-->\n <ion-icon *ngIf=\"childPage.icon\" slot=\"start\" color=\"dark\" [name]=\"childPage.icon\"></ion-icon>\n <mat-icon *ngIf=\"childPage.matIcon\" slot=\"start\" color=\"dark\">\n {{ childPage.matIcon }}\n </mat-icon>\n\n <ion-label color=\"dark\" [innerHTML]=\"childPage.title\"></ion-label>\n </ion-item>\n }\n </ion-list>\n </ion-card-content>\n }\n </ion-card>\n </ion-col>\n }\n </ion-row>\n </ion-grid>\n }\n\n <!-- Bottom banner -->\n @if (showPartnerBanner || showLegalInformation) {\n <ion-grid\n class=\"bottom-banner ion-text-center\"\n [class.floating]=\"!mobile && (pageHistory | isEmptyArray)\"\n @fadeInAnimation\n >\n <ion-row>\n <!-- partners logos -->\n @if (showPartnerBanner) {\n <ion-col size=\"12\" [sizeLg]=\"partnerBannerSize\" class=\"ion-text-center\">\n @if (showLegalInformation) {\n <ion-list class=\"legal-info\">\n <ion-list-header>{{ 'HOME.PARTNERS' | translate }}</ion-list-header>\n </ion-list>\n }\n <!-- partners -->\n @for (item of $partners | async; track $index) {\n <a href=\"{{ item.siteUrl }}\">\n <img class=\"logo\" src=\"{{ item.logo }}\" alt=\"{{ item.label }}\" [title]=\"item.label\" />\n </a>\n }\n </ion-col>\n }\n\n <!-- legal information -->\n @if (showLegalInformation) {\n <ion-col size=\"12\" size-sm=\"6\" size-lg=\"4\" [class.left-border]=\"showPartnerBanner\">\n <ion-list class=\"legal-info\">\n <ion-list-header class=\"ion-text-left\">{{ 'HOME.LEGAL_INFORMATION' | translate }}</ion-list-header>\n @for (item of legalInformation; track item.path) {\n <ion-item (click)=\"openMarkdownModal($event, item)\" lines=\"none\" [button]=\"true\">\n <ion-label>\n <p>\n {{ item.title | translate: item.titleArgs }}\n </p>\n </ion-label>\n </ion-item>\n }\n </ion-list>\n </ion-col>\n @if (showInstallLinks) {\n <ion-col size=\"12\" size-lg=\"3\" offset-lg=\"9\" [class.left-border]=\"showPartnerBanner\">\n <ion-list class=\"legal-info\">\n <ion-list-header>{{ 'HOME.INSTALL_APP' | translate }}</ion-list-header>\n <!-- TODO -->\n </ion-list>\n </ion-col>\n }\n }\n </ion-row>\n </ion-grid>\n }\n }\n\n <!-- image credits -->\n @if (contentCredits | isNotNilOrBlank) {\n <div class=\"content-credits\" [class.floating]=\"!mobile\">\n <ion-text>{{ contentCredits }}</ion-text>\n </div>\n }\n</ion-content>\n", styles: [":host{--ion-card-background-color: rgba(var(--ion-background-color-rgb), .7);--scrollbar-width: 0;--bottom-banner-height: 122px}h1,h2,h3,h4,h5{white-space:normal}.center,ion-content ion-card.welcome img{text-align:center;display:inline-block}ion-content{--background: transparent;background-size:cover;-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;background-color:var(--ion-background-color);display:inline-block;padding:15px}ion-content.has-scrollbar{--scrollbar-width: 8px}ion-content .loading-page{display:block;height:100%;width:100%;position:absolute;background-color:transparent;z-index:5;transition:background .5s linear;-webkit-transition:background 1.5s linear}ion-content .loading-page.hidden{background-color:rgba(var(--ion-color-primary),0)}ion-content ion-card{z-index:9;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}ion-content ion-card ion-card-header{display:block}ion-content ion-card ion-card-header ion-card-subtitle,ion-content ion-card ion-card-header ion-card-title{display:block;width:100%}ion-content ion-card.main{min-width:240px;max-width:400px;margin-left:auto;margin-right:auto}ion-content ion-card.welcome{background-color:var(--ion-card-background-color)}ion-content ion-card.welcome button{margin-top:16px}ion-content ion-card.welcome img{max-width:250px}ion-content .history-container{margin-left:auto;margin-right:auto}ion-content .history-container ion-card{display:inline-block;box-sizing:border-box;z-index:8;min-width:240px;max-width:400px;width:100%;margin-left:auto;margin-right:auto;background-color:var(--ion-card-background-color);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}ion-content .history-container ion-card ion-card-header ion-card-subtitle{height:40px}ion-content .history-container ion-card ion-card-header ion-card-subtitle button[float-start]{--mdc-icon-button-state-layer-size: 40px;padding:8px;z-index:99;margin:0}ion-content .history-container ion-card ion-card-header ion-card-subtitle ion-label{line-height:40px}ion-content .history-container ion-card ion-card-header ion-card-subtitle ion-label[float-end]{padding-right:16px;font-weight:400}ion-content .history-container ion-card ion-card-header ion-card-title ion-item{width:100%;--ion-item-background: $transparent;--ion-item-icon-color: var(--ion-color-primary);--ion-item-text-color: var(--ion-color-primary)}ion-content .history-container ion-card ion-card-header ion-card-title ion-item ion-icon[slot=start],ion-content .history-container ion-card ion-card-header ion-card-title ion-item mat-icon[slot=start]{margin-right:unset;margin-inline-end:16px!important;color:var(--ion-item-icon-color)!important;fill:currentColor;stroke:currentColor}ion-content .history-container ion-card ion-card-header ion-card-title ion-item ion-text,ion-content .history-container ion-card ion-card-header ion-card-title ion-item ion-label{color:var(--ion-item-text-color)!important;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;-ms-text-size-adjust:100%;text-size-adjust:100%}ion-content .history-container ion-card ion-card-content ion-list{--ion-item-background: var(--ion-color-transparent)}ion-content .history-container ion-card ion-card-content ion-list ion-item{--ion-item-icon-color: var(--ion-color-dark);--ion-item-text-color: var(--ion-color-dark)}ion-content .history-container ion-card ion-card-content ion-list ion-item ion-icon[slot=start],ion-content .history-container ion-card ion-card-content ion-list ion-item mat-icon[slot=start]{color:var(--ion-item-icon-color)!important;fill:currentColor;stroke:currentColor;margin-right:unset;margin-inline-end:16px!important}ion-content .history-container ion-card ion-card-content ion-list ion-item ion-text,ion-content .history-container ion-card ion-card-content ion-list ion-item ion-label{color:var(--ion-item-text-color)!important}ion-content .bottom-banner{--ion-card-background-color: rgba(var(--ion-background-color-rgb), .5);background-color:var(--ion-card-background-color);min-width:240px;z-index:0;border-radius:4px;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);margin:16px}ion-content .bottom-banner img.logo{max-height:50px;margin-left:8px}ion-content .bottom-banner ion-list-header{min-height:30px}ion-content .bottom-banner ion-item{--min-height: 28px}ion-content .bottom-banner ion-item ion-label{margin-top:3px!important;margin-bottom:3px!important}ion-content ion-text{text-align:center}@media screen and (max-width: 575px){ion-content ion-card{min-width:160px;width:calc(100% - 20px);max-width:100%;margin-left:10px;margin-right:10px}ion-content ion-card h1{margin-top:0;font-size:20px}ion-content ion-card ion-card-content ion-button{margin-top:8px}ion-content .bottom-banner.floating{display:block;position:unset}ion-content .bottom-banner img.logo{max-height:30px}}@media screen and (max-width: 767px) and (min-width: 576px){ion-content{min-height:555px}ion-content .bottom-banner img.logo{max-height:40px}}@media screen and (min-width: 768px){ion-content{min-height:calc(100% - var(--bottom-banner-height))}}@media screen and (min-width: 1200px){ion-content ion-col.feed{height:fit-content;max-height:calc(100vh - var(--ion-toolbar-height) - var(--bottom-banner-height) - var(--ion-padding) * 2);padding-inline-end:calc(var(--ion-padding) - 10px)}ion-content .bottom-banner.floating{position:fixed;left:0;right:0;bottom:0;overflow-y:auto;max-height:var(--bottom-banner-height);margin-top:0}}.content-credits{float:right}.content-credits.floating{float:unset;position:fixed;bottom:0;right:var(--scrollbar-width, 0)}.content-credits ion-text{padding-inline-start:4px;padding-inline-end:4px;font-size:.7rem;background-color:rgba(var(--ion-background-color-rgb),.5);color:rgba(var(--ion-text-color-rgb),.7)}@media screen and (min-width: 992px){.left-border{border-left:1px solid var(--ion-color-medium)}}\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: "directive", type: i3$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i2$1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2$1.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i2$1.IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: i2$1.IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: i2$1.IonCardHeader, selector: "ion-card-header", inputs: ["color", "mode", "translucent"] }, { kind: "component", type: i2$1.IonCardSubtitle, selector: "ion-card-subtitle", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonCardTitle, selector: "ion-card-title", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i2$1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2$1.IonGrid, selector: "ion-grid", inputs: ["fixed"] }, { kind: "component", type: i2$1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2$1.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2$1.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2$1.IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: i2$1.IonListHeader, selector: "ion-list-header", inputs: ["color", "lines", "mode"] }, { kind: "component", type: i2$1.IonMenuToggle, selector: "ion-menu-toggle", inputs: ["autoHide", "menu"] }, { kind: "component", type: i2$1.IonRow, selector: "ion-row" }, { kind: "component", type: i2$1.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i2$1.RouterLinkDelegate, selector: ":not(a):not(area)[routerLink]" }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i8$2.RxIf, selector: "[rxIf]", inputs: ["rxIf", "rxIfStrategy", "rxIfElse", "rxIfThen", "rxIfSuspense", "rxIfComplete", "rxIfError", "rxIfContextTrigger", "rxIfNextTrigger", "rxIfSuspenseTrigger", "rxIfErrorTrigger", "rxIfCompleteTrigger", "rxIfParent", "rxIfPatchZone", "rxIfRenderCallback"] }, { kind: "component", type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i9.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i8$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i8$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i8$1.MatMenuContent, selector: "ng-template[matMenuContent]" }, { kind: "directive", type: i8$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "directive", type: NgInitDirective, selector: "[ngInit]", outputs: ["ngInit"] }, { kind: "component", type: ToolbarComponent, selector: "app-toolbar", inputs: ["progressBarMode", "title", "color", "class", "id", "backHref", "defaultBackHref", "hasValidate", "hasClose", "hasSearch", "canGoBack", "canShowMenu"], outputs: ["onValidate", "onClose", "onValidateAndClose", "onBackClick", "onSearch"] }, { kind: "directive", type: i1$6.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: AppInstallUpgradeCard, selector: "app-install-upgrade-card", inputs: ["isLogin", "showUpgradeWarning", "showOfflineWarning", "showInstallButton", "debug"] }, { kind: "component", type: UserEventNotificationIcon, selector: "app-user-event-notification-icon", inputs: ["titleI18n", "disabled", "filter", "autoHide", "headerActions", "footerActions", "style", "color", "unreadColor", "fill", "mobile", "listStyle", "debug"], outputs: ["showList"] }, { kind: "component", type: FeedsComponent, selector: "app-feed", inputs: ["debug", "showHeader", "headerColor", "cardColor", "shape", "class", "feeds", "feedUrls", "maxAgeInMonths", "maxContentLength"] }, { kind: "pipe", type: i3$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }, { kind: "pipe", type: i19.RxPush, name: "push" }, { kind: "pipe", type: DateFormatPipe, name: "dateFormat" }, { kind: "pipe", type: DateFromNowPipe, name: "dateFromNow" }, { kind: "pipe", type: NotEmptyArrayPipe, name: "isNotEmptyArray" }, { kind: "pipe", type: EmptyArrayPipe, name: "isEmptyArray" }, { kind: "pipe", type: IsNotNilOrBlankPipe, name: "isNotNilOrBlank" }], animations: [fadeInAnimation, slideUpDownAnimation, slideInAnimation], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
35506
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: HomePage, selector: "app-page-home", viewQueries: [{ propertyName: "content", first: true, predicate: IonContent, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<app-toolbar [canGoBack]=\"false\" visible-xs visible-sm visible-mobile>\n <ion-buttons slot=\"end\">\n @if (showNotificationIcon) {\n <app-user-event-notification-icon [autoHide]=\"autoHideNotificationIcon\"></app-user-event-notification-icon>\n }\n\n <!-- dark mode (if allow by the environment token) -->\n @if (settings.allowDarkMode) {\n <ion-button (click)=\"toggleDarkMode()\">\n <ion-icon slot=\"icon-only\" [name]=\"(darkMode$ | push) ? 'sunny' : 'moon'\"></ion-icon>\n </ion-button>\n }\n\n <!-- Change locale button -->\n <ion-button [matMenuTriggerFor]=\"localeMenu\">\n <ion-icon slot=\"start\" name=\"language\"></ion-icon>\n </ion-button>\n </ion-buttons>\n</app-toolbar>\n\n<!-- Change locale menu -->\n<mat-menu #localeMenu=\"matMenu\">\n <ng-template matMenuContent>\n @for (item of locales; track item.key) {\n <button mat-menu-item (click)=\"changeLanguage(item.key)\">\n <!--<mat-icon>{{ currentLocale === item.key ? 'checkmark' : undefined }}</mat-icon>-->\n <ion-label>{{ item.value }}</ion-label>\n </button>\n }\n </ng-template>\n</mat-menu>\n\n<ion-content [ngStyle]=\"contentStyle\" [class.has-scrollbar]=\"hasScrollbar\" no-padding-xs>\n <!-- loading spinner -->\n <div class=\"loading-page\" [class.cdk-visually-hidden]=\"!(loading$ | push)\">\n @if (showSpinner) {\n <div class=\"spinner\">\n <p [innerHTML]=\"'COMMON.LOADING_DOTS' | translate\"></p>\n <div class=\"sk-cube1 sk-cube\"></div>\n <div class=\"sk-cube2 sk-cube\"></div>\n <div class=\"sk-cube4 sk-cube\"></div>\n <div class=\"sk-cube3 sk-cube\"></div>\n </div>\n }\n </div>\n\n <!-- Desktop: translucent top toolbar -->\n @if (!mobile) {\n <div class=\"hidden-xs hidden-sm\">\n <ion-toolbar color=\"traansparent\" translucent>\n <ion-buttons slot=\"start\">\n <ion-menu-toggle>\n <ion-button color=\"light\" fill=\"clear\">\n <ion-icon slot=\"icon-only\" name=\"menu\"></ion-icon>\n </ion-button>\n </ion-menu-toggle>\n </ion-buttons>\n\n <ion-buttons slot=\"end\">\n @if (showNotificationIcon) {\n <app-user-event-notification-icon\n [style]=\"'ion-button'\"\n color=\"secondary\"\n unreadColor=\"tertiary\"\n fill=\"solid\"\n [autoHide]=\"autoHideNotificationIcon\"\n ></app-user-event-notification-icon>\n }\n\n <!-- dark mode (if allow by the environment token) -->\n @if (settings.allowDarkMode) {\n <ion-button\n color=\"secondary\"\n fill=\"solid\"\n (click)=\"toggleDarkMode()\"\n [title]=\"'HOME.BTN_DARK_MODE' | translate\"\n >\n <ion-icon slot=\"icon-only\" [name]=\"(darkMode$ | push) ? 'moon' : 'sunny'\"></ion-icon>\n </ion-button>\n }\n <!-- change locale button -->\n <ion-button\n color=\"secondary\"\n fill=\"solid\"\n [matMenuTriggerFor]=\"localeMenu\"\n [title]=\"'SETTINGS.LOCALE' | translate\"\n >\n <ion-icon slot=\"icon-only\" name=\"language\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </div>\n }\n\n <!-- Install (and upgrade) card -->\n <app-install-upgrade-card [isLogin]=\"isLogin\" [showInstallButton]=\"true\"></app-install-upgrade-card>\n\n @if (!(loading$ | push)) {\n @let hasFeed = hasFeed$ | async;\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col size=\"0\" [sizeXl]=\"hasFeed ? 3 : 0\"></ion-col>\n <ion-col>\n <!-- Welcome card -->\n <ion-card class=\"main welcome ion-padding ion-text-center ion-align-self-center\" @fadeInAnimation>\n <ion-card-header>\n <ion-card-title class=\"ion-text-center\">\n <span *ngIf=\"isWeb\" [innerHTML]=\"'HOME.WELCOME_WEB' | translate: { appName: appName }\"></span>\n <span *ngIf=\"!isWeb\" [innerHTML]=\"'HOME.WELCOME_APP' | translate: { appName: appName }\"></span>\n </ion-card-title>\n <ion-card-subtitle [innerHTML]=\"description\"></ion-card-subtitle>\n </ion-card-header>\n <ion-card-content class=\"ion-no-padding\">\n <ion-text color=\"primary\">\n <img *ngIf=\"logo\" [attr.src]=\"logo\" alt=\"Logo\" />\n </ion-text>\n <!-- register help text -->\n <ion-text *ngIf=\"!isLogin && canRegister\">\n <br />\n <span translate>HOME.REGISTER_HELP</span>\n </ion-text>\n <div class=\"ion-padding-top\">\n <!-- If NOT login -->\n <ng-container *ngIf=\"!isLogin; else loginButtons\">\n <ion-button *ngIf=\"canRegister\" expand=\"block\" color=\"tertiary\" (click)=\"register()\">\n <span translate>HOME.BTN_REGISTER</span>\n </ion-button>\n <ion-button expand=\"block\" color=\"light\" [routerLink]=\"['/']\" (click)=\"login()\">\n <span translate>AUTH.BTN_LOGIN</span>\n </ion-button>\n </ng-container>\n\n <!-- If user login -->\n <ng-template #loginButtons>\n <!-- Feature buttons -->\n <ng-container *rxIf=\"$filteredButtons; let buttons\">\n <ng-container *ngFor=\"let item of buttons\">\n <ion-button\n *ngIf=\"item.path\"\n expand=\"block\"\n color=\"tertiary\"\n [class]=\"item.cssClass\"\n [routerLink]=\"item.path\"\n routerDirection=\"root\"\n >\n <ion-icon slot=\"start\" class=\"ion-float-start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" class=\"ion-float-start\" *ngIf=\"item.matIcon\">\n {{ item.matIcon }}\n </mat-icon>\n <ion-text>{{ 'HOME.BTN_DATA_ENTRY' | translate: { name: (item.title | translate) } }}</ion-text>\n </ion-button>\n\n <!-- divider -->\n <div *ngIf=\"!item.path && !item.action\" [class]=\"item.cssClass\">\n <ion-label translate>{{ item.title }} </ion-label>\n </div>\n </ng-container>\n\n <!--<p *ngIf=\"buttons.length\" class=\"visible-mobile\"> </p>-->\n </ng-container>\n\n <ion-button *ngIf=\"showAccountButton\" expand=\"block\" color=\"secondary\" [routerLink]=\"['/account']\">\n <ion-icon slot=\"start\" class=\"ion-float-start\" name=\"person-circle\"></ion-icon>\n <ion-text translate>HOME.BTN_MY_ACCOUNT</ion-text>\n </ion-button>\n\n <p hidden-xs hidden-sm hidden-mobile>\n <ion-text\n [innerHTML]=\"'HOME.NOT_THIS_ACCOUNT_QUESTION' | translate: { displayName: accountName }\"\n ></ion-text>\n <br />\n <ion-text>\n <a href=\"#\" (click)=\"logout($event)\">\n <span translate>HOME.BTN_DISCONNECT</span>\n </a>\n </ion-text>\n </p>\n </ng-template>\n </div>\n </ion-card-content>\n </ion-card>\n </ion-col>\n <ion-col size=\"0\" [sizeXl]=\"hasFeed ? 1 : 0\"></ion-col>\n <ion-col [class.feed]=\"hasFeed\" [size]=\"hasFeed ? 12 : 0\" [sizeXl]=\"hasFeed ? 4 : 0\">\n @if (showFeed) {\n @if (mobile) {\n <app-feed\n #feed\n shape=\"round\"\n [urls]=\"feedUrls\"\n [maxAgeInMonths]=\"feedMaxAgeInMonths\"\n [maxContentLength]=\"feedMaxContentLength\"\n (ngInit)=\"initFeed(feed)\"\n @fadeInAnimation\n ></app-feed>\n } @else {\n <app-feed\n #feed\n shape=\"round\"\n [debug]=\"false\"\n [urls]=\"feedUrls\"\n [maxAgeInMonths]=\"feedMaxAgeInMonths\"\n [maxContentLength]=\"feedMaxContentLength\"\n (ngInit)=\"initFeed(feed)\"\n @slideInAnimation\n @fadeInAnimation\n ></app-feed>\n }\n }\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Page history -->\n @let pageHistory = isLogin && (pageHistory$ | push);\n @if (pageHistory | isNotEmptyArray) {\n <ion-grid class=\"history-container ion-align-self-center\">\n <ion-row>\n @for (page of pageHistory; track page.path) {\n <ion-col size=\"12\" size-xl=\"\" class=\"ion-text-center\">\n <ion-card class=\"ion-align-self-start ion-text-start\" @fadeInAnimation>\n <ion-card-header class=\"ion-no-padding\">\n <!-- top bar -->\n <ion-card-subtitle>\n <button\n type=\"button\"\n tabindex=\"-1\"\n (click)=\"removePageHistory(page.path)\"\n mat-icon-button\n class=\"ion-float-start ion-no-margin close-button\"\n >\n <mat-icon>close</mat-icon>\n </button>\n <ion-label [innerHTML]=\"page.subtitle | translate\"></ion-label>\n <ion-text class=\"ion-float-end\" [title]=\"page.time | dateFormat: { time: true }\">\n <small>\n <ion-icon name=\"time-outline\"></ion-icon>\n {{ page.time | dateFromNow }}\n </small>\n \n </ion-text>\n </ion-card-subtitle>\n\n <!-- main page -->\n <ion-card-title class=\"ion-no-margin ion-no-padding\">\n <ion-item\n detail=\"true\"\n tappable\n class=\"text-1x\"\n [routerLink]=\"page.path\"\n routerDirection=\"root\"\n lines=\"none\"\n >\n <!-- page icon-->\n <ion-icon *ngIf=\"page.icon\" slot=\"start\" [name]=\"page.icon\"></ion-icon>\n <mat-icon *ngIf=\"page.matIcon\" slot=\"start\">{{ page.matIcon }}</mat-icon>\n\n <ion-label color=\"primary\" [innerHTML]=\"page.title\"></ion-label>\n </ion-item>\n </ion-card-title>\n </ion-card-header>\n\n <!-- children pages -->\n @if (page.children | isNotEmptyArray) {\n <ion-card-content class=\"ion-no-padding ion-padding-start\">\n <ion-list class=\"ion-no-padding\">\n @for (childPage of page.children; track childPage.path) {\n <ion-item\n detail=\"true\"\n tappable\n class=\"text-1x\"\n [routerLink]=\"childPage.path\"\n routerDirection=\"root\"\n >\n <!-- page icon-->\n <ion-icon *ngIf=\"childPage.icon\" slot=\"start\" color=\"dark\" [name]=\"childPage.icon\"></ion-icon>\n <mat-icon *ngIf=\"childPage.matIcon\" slot=\"start\" color=\"dark\">\n {{ childPage.matIcon }}\n </mat-icon>\n\n <ion-label color=\"dark\" [innerHTML]=\"childPage.title\"></ion-label>\n </ion-item>\n }\n </ion-list>\n </ion-card-content>\n }\n </ion-card>\n </ion-col>\n }\n </ion-row>\n </ion-grid>\n }\n\n <!-- Bottom banner -->\n @if (showPartnerBanner || showLegalInformation) {\n <ion-grid\n class=\"bottom-banner ion-text-center\"\n [class.floating]=\"!mobile && (pageHistory | isEmptyArray)\"\n @fadeInAnimation\n >\n <ion-row>\n <!-- partners logos -->\n @if (showPartnerBanner) {\n <ion-col size=\"12\" [sizeLg]=\"partnerBannerSize\" class=\"ion-text-center\">\n @if (showLegalInformation) {\n <ion-list class=\"legal-info\">\n <ion-list-header>{{ 'HOME.PARTNERS' | translate }}</ion-list-header>\n </ion-list>\n }\n <!-- partners -->\n @for (item of $partners | async; track $index) {\n <a href=\"{{ item.siteUrl }}\">\n <img class=\"logo\" src=\"{{ item.logo }}\" alt=\"{{ item.label }}\" [title]=\"item.label\" />\n </a>\n }\n </ion-col>\n }\n\n <!-- legal information -->\n @if (showLegalInformation) {\n <ion-col size=\"12\" size-sm=\"6\" size-lg=\"4\" [class.left-border]=\"showPartnerBanner\">\n <ion-list class=\"legal-info\">\n <ion-list-header class=\"ion-text-left\">{{ 'HOME.LEGAL_INFORMATION' | translate }}</ion-list-header>\n @for (item of legalInformation; track item.path) {\n <ion-item (click)=\"openMarkdownModal($event, item)\" lines=\"none\" [button]=\"true\">\n <ion-label>\n <p>\n {{ item.title | translate: item.titleArgs }}\n </p>\n </ion-label>\n </ion-item>\n }\n </ion-list>\n </ion-col>\n @if (showInstallLinks) {\n <ion-col size=\"12\" size-lg=\"3\" offset-lg=\"9\" [class.left-border]=\"showPartnerBanner\">\n <ion-list class=\"legal-info\">\n <ion-list-header>{{ 'HOME.INSTALL_APP' | translate }}</ion-list-header>\n <!-- TODO -->\n </ion-list>\n </ion-col>\n }\n }\n </ion-row>\n </ion-grid>\n }\n }\n\n <!-- image credits -->\n @if (contentCredits | isNotNilOrBlank) {\n <div class=\"content-credits\" [class.floating]=\"!mobile\">\n <ion-text>{{ contentCredits }}</ion-text>\n </div>\n }\n</ion-content>\n", styles: [":host{--ion-card-background-color: rgba(var(--ion-background-color-rgb), .7);--scrollbar-width: 0;--bottom-banner-height: 122px}h1,h2,h3,h4,h5{white-space:normal}.center,ion-content ion-card.welcome img{text-align:center;display:inline-block}ion-content{--background: transparent;background-size:cover;-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;background-color:var(--ion-background-color);display:inline-block;padding:15px}ion-content.has-scrollbar{--scrollbar-width: 8px}ion-content .loading-page{display:block;height:100%;width:100%;position:absolute;background-color:transparent;z-index:5;transition:background .5s linear;-webkit-transition:background 1.5s linear}ion-content .loading-page.hidden{background-color:rgba(var(--ion-color-primary),0)}ion-content ion-card{z-index:9;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}ion-content ion-card ion-card-header{display:block}ion-content ion-card ion-card-header ion-card-subtitle,ion-content ion-card ion-card-header ion-card-title{display:block;width:100%}ion-content ion-card.main{min-width:240px;max-width:400px;margin-left:auto;margin-right:auto}ion-content ion-card.welcome{background-color:var(--ion-card-background-color)}ion-content ion-card.welcome button{margin-top:16px}ion-content ion-card.welcome img{max-width:250px}ion-content .history-container{margin-left:auto;margin-right:auto}ion-content .history-container ion-card{display:inline-block;box-sizing:border-box;z-index:8;min-width:240px;max-width:400px;width:100%;margin-left:auto;margin-right:auto;background-color:var(--ion-card-background-color);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}ion-content .history-container ion-card ion-card-header ion-card-subtitle{height:40px}ion-content .history-container ion-card ion-card-header ion-card-subtitle button[float-start]{--mdc-icon-button-state-layer-size: 40px;padding:8px;z-index:99;margin:0}ion-content .history-container ion-card ion-card-header ion-card-subtitle ion-label{line-height:40px}ion-content .history-container ion-card ion-card-header ion-card-subtitle ion-label[float-end]{padding-right:16px;font-weight:400}ion-content .history-container ion-card ion-card-header ion-card-title ion-item{width:100%;--ion-item-background: $transparent;--ion-item-icon-color: var(--ion-color-primary);--ion-item-text-color: var(--ion-color-primary)}ion-content .history-container ion-card ion-card-header ion-card-title ion-item ion-icon[slot=start],ion-content .history-container ion-card ion-card-header ion-card-title ion-item mat-icon[slot=start]{margin-right:unset;margin-inline-end:16px!important;color:var(--ion-item-icon-color)!important;fill:currentColor;stroke:currentColor}ion-content .history-container ion-card ion-card-header ion-card-title ion-item ion-text,ion-content .history-container ion-card ion-card-header ion-card-title ion-item ion-label{color:var(--ion-item-text-color)!important;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;-ms-text-size-adjust:100%;text-size-adjust:100%}ion-content .history-container ion-card ion-card-content ion-list{--ion-item-background: var(--ion-color-transparent)}ion-content .history-container ion-card ion-card-content ion-list ion-item{--ion-item-icon-color: var(--ion-color-dark);--ion-item-text-color: var(--ion-color-dark)}ion-content .history-container ion-card ion-card-content ion-list ion-item ion-icon[slot=start],ion-content .history-container ion-card ion-card-content ion-list ion-item mat-icon[slot=start]{color:var(--ion-item-icon-color)!important;fill:currentColor;stroke:currentColor;margin-right:unset;margin-inline-end:16px!important}ion-content .history-container ion-card ion-card-content ion-list ion-item ion-text,ion-content .history-container ion-card ion-card-content ion-list ion-item ion-label{color:var(--ion-item-text-color)!important}ion-content .bottom-banner{--ion-card-background-color: rgba(var(--ion-background-color-rgb), .5);background-color:var(--ion-card-background-color);min-width:240px;z-index:0;border-radius:4px;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);margin:16px}ion-content .bottom-banner img.logo{max-height:50px;margin-left:8px}ion-content .bottom-banner ion-list-header{min-height:30px}ion-content .bottom-banner ion-item{--min-height: 28px}ion-content .bottom-banner ion-item ion-label{margin-top:3px!important;margin-bottom:3px!important}ion-content ion-text{text-align:center}@media screen and (max-width: 575px){ion-content ion-card{min-width:160px;width:calc(100% - 20px);max-width:100%;margin-left:10px;margin-right:10px}ion-content ion-card h1{margin-top:0;font-size:20px}ion-content ion-card ion-card-content ion-button{margin-top:8px}ion-content .bottom-banner.floating{display:block;position:unset}ion-content .bottom-banner img.logo{max-height:30px}}@media screen and (max-width: 767px) and (min-width: 576px){ion-content{min-height:555px}ion-content .bottom-banner img.logo{max-height:40px}}@media screen and (min-width: 768px){ion-content{min-height:calc(100% - var(--bottom-banner-height))}}@media screen and (min-width: 1200px){ion-content ion-col.feed{height:fit-content;max-height:calc(100vh - var(--ion-toolbar-height) - var(--bottom-banner-height) - var(--ion-padding) * 2);padding-inline-end:calc(var(--ion-padding) - 10px);overflow:hidden}ion-content .bottom-banner.floating{position:fixed;left:0;right:0;bottom:0;overflow-y:auto;max-height:var(--bottom-banner-height);margin-top:0}}.content-credits{float:right}.content-credits.floating{float:unset;position:fixed;bottom:0;right:var(--scrollbar-width, 0)}.content-credits ion-text{padding-inline-start:4px;padding-inline-end:4px;font-size:.7rem;background-color:rgba(var(--ion-background-color-rgb),.5);color:rgba(var(--ion-text-color-rgb),.7)}@media screen and (min-width: 992px){.left-border{border-left:1px solid var(--ion-color-medium)}}\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: "directive", type: i3$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i2$1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2$1.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i2$1.IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: i2$1.IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: i2$1.IonCardHeader, selector: "ion-card-header", inputs: ["color", "mode", "translucent"] }, { kind: "component", type: i2$1.IonCardSubtitle, selector: "ion-card-subtitle", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonCardTitle, selector: "ion-card-title", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i2$1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2$1.IonGrid, selector: "ion-grid", inputs: ["fixed"] }, { kind: "component", type: i2$1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2$1.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2$1.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2$1.IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: i2$1.IonListHeader, selector: "ion-list-header", inputs: ["color", "lines", "mode"] }, { kind: "component", type: i2$1.IonMenuToggle, selector: "ion-menu-toggle", inputs: ["autoHide", "menu"] }, { kind: "component", type: i2$1.IonRow, selector: "ion-row" }, { kind: "component", type: i2$1.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i2$1.RouterLinkDelegate, selector: ":not(a):not(area)[routerLink]" }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i8$2.RxIf, selector: "[rxIf]", inputs: ["rxIf", "rxIfStrategy", "rxIfElse", "rxIfThen", "rxIfSuspense", "rxIfComplete", "rxIfError", "rxIfContextTrigger", "rxIfNextTrigger", "rxIfSuspenseTrigger", "rxIfErrorTrigger", "rxIfCompleteTrigger", "rxIfParent", "rxIfPatchZone", "rxIfRenderCallback"] }, { kind: "component", type: i6$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i9.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i8$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i8$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i8$1.MatMenuContent, selector: "ng-template[matMenuContent]" }, { kind: "directive", type: i8$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "directive", type: NgInitDirective, selector: "[ngInit]", outputs: ["ngInit"] }, { kind: "component", type: ToolbarComponent, selector: "app-toolbar", inputs: ["progressBarMode", "title", "color", "class", "id", "backHref", "defaultBackHref", "hasValidate", "hasClose", "hasSearch", "canGoBack", "canShowMenu"], outputs: ["onValidate", "onClose", "onValidateAndClose", "onBackClick", "onSearch"] }, { kind: "directive", type: i1$6.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: AppInstallUpgradeCard, selector: "app-install-upgrade-card", inputs: ["isLogin", "showUpgradeWarning", "showOfflineWarning", "showInstallButton", "debug"] }, { kind: "component", type: UserEventNotificationIcon, selector: "app-user-event-notification-icon", inputs: ["titleI18n", "disabled", "filter", "autoHide", "headerActions", "footerActions", "style", "color", "unreadColor", "fill", "mobile", "listStyle", "debug"], outputs: ["showList"] }, { kind: "component", type: FeedsComponent, selector: "app-feed", inputs: ["debug", "mobile", "showHeader", "showReadMoreButton", "headerColor", "cardColor", "shape", "class", "itemId", "filterItem", "feeds", "urls", "maxAgeInMonths", "maxContentLength"], outputs: ["editItem", "deleteItem"] }, { kind: "pipe", type: i3$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }, { kind: "pipe", type: i19.RxPush, name: "push" }, { kind: "pipe", type: DateFormatPipe, name: "dateFormat" }, { kind: "pipe", type: DateFromNowPipe, name: "dateFromNow" }, { kind: "pipe", type: NotEmptyArrayPipe, name: "isNotEmptyArray" }, { kind: "pipe", type: EmptyArrayPipe, name: "isEmptyArray" }, { kind: "pipe", type: IsNotNilOrBlankPipe, name: "isNotNilOrBlank" }], animations: [fadeInAnimation, slideUpDownAnimation, slideInAnimation], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
34590
35507
|
}
|
|
34591
35508
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: HomePage, decorators: [{
|
|
34592
35509
|
type: Component,
|
|
34593
|
-
args: [{ selector: 'app-page-home', changeDetection: ChangeDetectionStrategy.OnPush, animations: [fadeInAnimation, slideUpDownAnimation, slideInAnimation], template: "<app-toolbar [canGoBack]=\"false\" visible-xs visible-sm visible-mobile>\n <ion-buttons slot=\"end\">\n @if (showNotificationIcon) {\n <app-user-event-notification-icon [autoHide]=\"autoHideNotificationIcon\"></app-user-event-notification-icon>\n }\n\n <!-- dark mode (if allow by the environment token) -->\n @if (settings.allowDarkMode) {\n <ion-button (click)=\"toggleDarkMode()\">\n <ion-icon slot=\"icon-only\" [name]=\"(darkMode$ | push) ? 'sunny' : 'moon'\"></ion-icon>\n </ion-button>\n }\n\n <!-- Change locale button -->\n <ion-button [matMenuTriggerFor]=\"localeMenu\">\n <ion-icon slot=\"start\" name=\"language\"></ion-icon>\n </ion-button>\n </ion-buttons>\n</app-toolbar>\n\n<!-- Change locale menu -->\n<mat-menu #localeMenu=\"matMenu\">\n <ng-template matMenuContent>\n @for (item of locales; track item.key) {\n <button mat-menu-item (click)=\"changeLanguage(item.key)\">\n <!--<mat-icon>{{ currentLocale === item.key ? 'checkmark' : undefined }}</mat-icon>-->\n <ion-label>{{ item.value }}</ion-label>\n </button>\n }\n </ng-template>\n</mat-menu>\n\n<ion-content [ngStyle]=\"contentStyle\" [class.has-scrollbar]=\"hasScrollbar\" no-padding-xs>\n <!-- loading spinner -->\n <div class=\"loading-page\" [class.cdk-visually-hidden]=\"!(loading$ | push)\">\n @if (showSpinner) {\n <div class=\"spinner\">\n <p [innerHTML]=\"'COMMON.LOADING_DOTS' | translate\"></p>\n <div class=\"sk-cube1 sk-cube\"></div>\n <div class=\"sk-cube2 sk-cube\"></div>\n <div class=\"sk-cube4 sk-cube\"></div>\n <div class=\"sk-cube3 sk-cube\"></div>\n </div>\n }\n </div>\n\n <!-- Desktop: translucent top toolbar -->\n @if (!mobile) {\n <div class=\"hidden-xs hidden-sm\">\n <ion-toolbar color=\"traansparent\" translucent>\n <ion-buttons slot=\"start\">\n <ion-menu-toggle>\n <ion-button color=\"light\" fill=\"clear\">\n <ion-icon slot=\"icon-only\" name=\"menu\"></ion-icon>\n </ion-button>\n </ion-menu-toggle>\n </ion-buttons>\n\n <ion-buttons slot=\"end\">\n @if (showNotificationIcon) {\n <app-user-event-notification-icon\n [style]=\"'ion-button'\"\n color=\"secondary\"\n unreadColor=\"tertiary\"\n fill=\"solid\"\n [autoHide]=\"autoHideNotificationIcon\"\n ></app-user-event-notification-icon>\n }\n\n <!-- dark mode (if allow by the environment token) -->\n @if (settings.allowDarkMode) {\n <ion-button\n color=\"secondary\"\n fill=\"solid\"\n (click)=\"toggleDarkMode()\"\n [title]=\"'HOME.BTN_DARK_MODE' | translate\"\n >\n <ion-icon slot=\"icon-only\" [name]=\"(darkMode$ | push) ? 'moon' : 'sunny'\"></ion-icon>\n </ion-button>\n }\n <!-- change locale button -->\n <ion-button\n color=\"secondary\"\n fill=\"solid\"\n [matMenuTriggerFor]=\"localeMenu\"\n [title]=\"'SETTINGS.LOCALE' | translate\"\n >\n <ion-icon slot=\"icon-only\" name=\"language\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </div>\n }\n\n <!-- Install (and upgrade) card -->\n <app-install-upgrade-card [isLogin]=\"isLogin\" [showInstallButton]=\"true\"></app-install-upgrade-card>\n\n @if (!(loading$ | push)) {\n @let hasFeed = hasFeed$ | async;\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col size=\"0\" [sizeXl]=\"hasFeed ? 3 : 0\"></ion-col>\n <ion-col>\n <!-- Welcome card -->\n <ion-card class=\"main welcome ion-padding ion-text-center ion-align-self-center\" @fadeInAnimation>\n <ion-card-header>\n <ion-card-title class=\"ion-text-center\">\n <span *ngIf=\"isWeb\" [innerHTML]=\"'HOME.WELCOME_WEB' | translate: { appName: appName }\"></span>\n <span *ngIf=\"!isWeb\" [innerHTML]=\"'HOME.WELCOME_APP' | translate: { appName: appName }\"></span>\n </ion-card-title>\n <ion-card-subtitle [innerHTML]=\"description\"></ion-card-subtitle>\n </ion-card-header>\n <ion-card-content class=\"ion-no-padding\">\n <ion-text color=\"primary\">\n <img *ngIf=\"logo\" [attr.src]=\"logo\" alt=\"Logo\" />\n </ion-text>\n <!-- register help text -->\n <ion-text *ngIf=\"!isLogin && canRegister\">\n <br />\n <span translate>HOME.REGISTER_HELP</span>\n </ion-text>\n <div class=\"ion-padding-top\">\n <!-- If NOT login -->\n <ng-container *ngIf=\"!isLogin; else loginButtons\">\n <ion-button *ngIf=\"canRegister\" expand=\"block\" color=\"tertiary\" (click)=\"register()\">\n <span translate>HOME.BTN_REGISTER</span>\n </ion-button>\n <ion-button expand=\"block\" color=\"light\" [routerLink]=\"['/']\" (click)=\"login()\">\n <span translate>AUTH.BTN_LOGIN</span>\n </ion-button>\n </ng-container>\n\n <!-- If user login -->\n <ng-template #loginButtons>\n <!-- Feature buttons -->\n <ng-container *rxIf=\"$filteredButtons; let buttons\">\n <ng-container *ngFor=\"let item of buttons\">\n <ion-button\n *ngIf=\"item.path\"\n expand=\"block\"\n color=\"tertiary\"\n [class]=\"item.cssClass\"\n [routerLink]=\"item.path\"\n routerDirection=\"root\"\n >\n <ion-icon slot=\"start\" class=\"ion-float-start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" class=\"ion-float-start\" *ngIf=\"item.matIcon\">\n {{ item.matIcon }}\n </mat-icon>\n <ion-text>{{ 'HOME.BTN_DATA_ENTRY' | translate: { name: (item.title | translate) } }}</ion-text>\n </ion-button>\n\n <!-- divider -->\n <div *ngIf=\"!item.path && !item.action\" [class]=\"item.cssClass\">\n <ion-label translate>{{ item.title }} </ion-label>\n </div>\n </ng-container>\n\n <!--<p *ngIf=\"buttons.length\" class=\"visible-mobile\"> </p>-->\n </ng-container>\n\n <ion-button *ngIf=\"showAccountButton\" expand=\"block\" color=\"secondary\" [routerLink]=\"['/account']\">\n <ion-icon slot=\"start\" class=\"ion-float-start\" name=\"person-circle\"></ion-icon>\n <ion-text translate>HOME.BTN_MY_ACCOUNT</ion-text>\n </ion-button>\n\n <p hidden-xs hidden-sm hidden-mobile>\n <ion-text\n [innerHTML]=\"'HOME.NOT_THIS_ACCOUNT_QUESTION' | translate: { displayName: accountName }\"\n ></ion-text>\n <br />\n <ion-text>\n <a href=\"#\" (click)=\"logout($event)\">\n <span translate>HOME.BTN_DISCONNECT</span>\n </a>\n </ion-text>\n </p>\n </ng-template>\n </div>\n </ion-card-content>\n </ion-card>\n </ion-col>\n <ion-col size=\"0\" [sizeXl]=\"hasFeed ? 1 : 0\"></ion-col>\n <ion-col [class.feed]=\"hasFeed\" [size]=\"hasFeed ? 12 : 0\" [sizeXl]=\"hasFeed ? 4 : 0\">\n @if (showFeed) {\n @if (mobile) {\n <app-feed\n #feed\n shape=\"round\"\n [feedUrls]=\"feedUrls\"\n [maxAgeInMonths]=\"feedMaxAgeInMonths\"\n [maxContentLength]=\"feedMaxContentLength\"\n (ngInit)=\"initFeed(feed)\"\n @fadeInAnimation\n ></app-feed>\n } @else {\n <app-feed\n #feed\n shape=\"round\"\n [debug]=\"false\"\n [feedUrls]=\"feedUrls\"\n [maxAgeInMonths]=\"feedMaxAgeInMonths\"\n [maxContentLength]=\"feedMaxContentLength\"\n (ngInit)=\"initFeed(feed)\"\n @slideInAnimation\n @fadeInAnimation\n ></app-feed>\n }\n }\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Page history -->\n @let pageHistory = isLogin && (pageHistory$ | push);\n @if (pageHistory | isNotEmptyArray) {\n <ion-grid class=\"history-container ion-align-self-center\">\n <ion-row>\n @for (page of pageHistory; track page.path) {\n <ion-col size=\"12\" size-xl=\"\" class=\"ion-text-center\">\n <ion-card class=\"ion-align-self-start ion-text-start\" @fadeInAnimation>\n <ion-card-header class=\"ion-no-padding\">\n <!-- top bar -->\n <ion-card-subtitle>\n <button\n type=\"button\"\n tabindex=\"-1\"\n (click)=\"removePageHistory(page.path)\"\n mat-icon-button\n class=\"ion-float-start ion-no-margin close-button\"\n >\n <mat-icon>close</mat-icon>\n </button>\n <ion-label [innerHTML]=\"page.subtitle | translate\"></ion-label>\n <ion-text class=\"ion-float-end\" [title]=\"page.time | dateFormat: { time: true }\">\n <small>\n <ion-icon name=\"time-outline\"></ion-icon>\n {{ page.time | dateFromNow }}\n </small>\n \n </ion-text>\n </ion-card-subtitle>\n\n <!-- main page -->\n <ion-card-title class=\"ion-no-margin ion-no-padding\">\n <ion-item\n detail=\"true\"\n tappable\n class=\"text-1x\"\n [routerLink]=\"page.path\"\n routerDirection=\"root\"\n lines=\"none\"\n >\n <!-- page icon-->\n <ion-icon *ngIf=\"page.icon\" slot=\"start\" [name]=\"page.icon\"></ion-icon>\n <mat-icon *ngIf=\"page.matIcon\" slot=\"start\">{{ page.matIcon }}</mat-icon>\n\n <ion-label color=\"primary\" [innerHTML]=\"page.title\"></ion-label>\n </ion-item>\n </ion-card-title>\n </ion-card-header>\n\n <!-- children pages -->\n @if (page.children | isNotEmptyArray) {\n <ion-card-content class=\"ion-no-padding ion-padding-start\">\n <ion-list class=\"ion-no-padding\">\n @for (childPage of page.children; track childPage.path) {\n <ion-item\n detail=\"true\"\n tappable\n class=\"text-1x\"\n [routerLink]=\"childPage.path\"\n routerDirection=\"root\"\n >\n <!-- page icon-->\n <ion-icon *ngIf=\"childPage.icon\" slot=\"start\" color=\"dark\" [name]=\"childPage.icon\"></ion-icon>\n <mat-icon *ngIf=\"childPage.matIcon\" slot=\"start\" color=\"dark\">\n {{ childPage.matIcon }}\n </mat-icon>\n\n <ion-label color=\"dark\" [innerHTML]=\"childPage.title\"></ion-label>\n </ion-item>\n }\n </ion-list>\n </ion-card-content>\n }\n </ion-card>\n </ion-col>\n }\n </ion-row>\n </ion-grid>\n }\n\n <!-- Bottom banner -->\n @if (showPartnerBanner || showLegalInformation) {\n <ion-grid\n class=\"bottom-banner ion-text-center\"\n [class.floating]=\"!mobile && (pageHistory | isEmptyArray)\"\n @fadeInAnimation\n >\n <ion-row>\n <!-- partners logos -->\n @if (showPartnerBanner) {\n <ion-col size=\"12\" [sizeLg]=\"partnerBannerSize\" class=\"ion-text-center\">\n @if (showLegalInformation) {\n <ion-list class=\"legal-info\">\n <ion-list-header>{{ 'HOME.PARTNERS' | translate }}</ion-list-header>\n </ion-list>\n }\n <!-- partners -->\n @for (item of $partners | async; track $index) {\n <a href=\"{{ item.siteUrl }}\">\n <img class=\"logo\" src=\"{{ item.logo }}\" alt=\"{{ item.label }}\" [title]=\"item.label\" />\n </a>\n }\n </ion-col>\n }\n\n <!-- legal information -->\n @if (showLegalInformation) {\n <ion-col size=\"12\" size-sm=\"6\" size-lg=\"4\" [class.left-border]=\"showPartnerBanner\">\n <ion-list class=\"legal-info\">\n <ion-list-header class=\"ion-text-left\">{{ 'HOME.LEGAL_INFORMATION' | translate }}</ion-list-header>\n @for (item of legalInformation; track item.path) {\n <ion-item (click)=\"openMarkdownModal($event, item)\" lines=\"none\" [button]=\"true\">\n <ion-label>\n <p>\n {{ item.title | translate: item.titleArgs }}\n </p>\n </ion-label>\n </ion-item>\n }\n </ion-list>\n </ion-col>\n @if (showInstallLinks) {\n <ion-col size=\"12\" size-lg=\"3\" offset-lg=\"9\" [class.left-border]=\"showPartnerBanner\">\n <ion-list class=\"legal-info\">\n <ion-list-header>{{ 'HOME.INSTALL_APP' | translate }}</ion-list-header>\n <!-- TODO -->\n </ion-list>\n </ion-col>\n }\n }\n </ion-row>\n </ion-grid>\n }\n }\n\n <!-- image credits -->\n @if (contentCredits | isNotNilOrBlank) {\n <div class=\"content-credits\" [class.floating]=\"!mobile\">\n <ion-text>{{ contentCredits }}</ion-text>\n </div>\n }\n</ion-content>\n", styles: [":host{--ion-card-background-color: rgba(var(--ion-background-color-rgb), .7);--scrollbar-width: 0;--bottom-banner-height: 122px}h1,h2,h3,h4,h5{white-space:normal}.center,ion-content ion-card.welcome img{text-align:center;display:inline-block}ion-content{--background: transparent;background-size:cover;-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;background-color:var(--ion-background-color);display:inline-block;padding:15px}ion-content.has-scrollbar{--scrollbar-width: 8px}ion-content .loading-page{display:block;height:100%;width:100%;position:absolute;background-color:transparent;z-index:5;transition:background .5s linear;-webkit-transition:background 1.5s linear}ion-content .loading-page.hidden{background-color:rgba(var(--ion-color-primary),0)}ion-content ion-card{z-index:9;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}ion-content ion-card ion-card-header{display:block}ion-content ion-card ion-card-header ion-card-subtitle,ion-content ion-card ion-card-header ion-card-title{display:block;width:100%}ion-content ion-card.main{min-width:240px;max-width:400px;margin-left:auto;margin-right:auto}ion-content ion-card.welcome{background-color:var(--ion-card-background-color)}ion-content ion-card.welcome button{margin-top:16px}ion-content ion-card.welcome img{max-width:250px}ion-content .history-container{margin-left:auto;margin-right:auto}ion-content .history-container ion-card{display:inline-block;box-sizing:border-box;z-index:8;min-width:240px;max-width:400px;width:100%;margin-left:auto;margin-right:auto;background-color:var(--ion-card-background-color);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}ion-content .history-container ion-card ion-card-header ion-card-subtitle{height:40px}ion-content .history-container ion-card ion-card-header ion-card-subtitle button[float-start]{--mdc-icon-button-state-layer-size: 40px;padding:8px;z-index:99;margin:0}ion-content .history-container ion-card ion-card-header ion-card-subtitle ion-label{line-height:40px}ion-content .history-container ion-card ion-card-header ion-card-subtitle ion-label[float-end]{padding-right:16px;font-weight:400}ion-content .history-container ion-card ion-card-header ion-card-title ion-item{width:100%;--ion-item-background: $transparent;--ion-item-icon-color: var(--ion-color-primary);--ion-item-text-color: var(--ion-color-primary)}ion-content .history-container ion-card ion-card-header ion-card-title ion-item ion-icon[slot=start],ion-content .history-container ion-card ion-card-header ion-card-title ion-item mat-icon[slot=start]{margin-right:unset;margin-inline-end:16px!important;color:var(--ion-item-icon-color)!important;fill:currentColor;stroke:currentColor}ion-content .history-container ion-card ion-card-header ion-card-title ion-item ion-text,ion-content .history-container ion-card ion-card-header ion-card-title ion-item ion-label{color:var(--ion-item-text-color)!important;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;-ms-text-size-adjust:100%;text-size-adjust:100%}ion-content .history-container ion-card ion-card-content ion-list{--ion-item-background: var(--ion-color-transparent)}ion-content .history-container ion-card ion-card-content ion-list ion-item{--ion-item-icon-color: var(--ion-color-dark);--ion-item-text-color: var(--ion-color-dark)}ion-content .history-container ion-card ion-card-content ion-list ion-item ion-icon[slot=start],ion-content .history-container ion-card ion-card-content ion-list ion-item mat-icon[slot=start]{color:var(--ion-item-icon-color)!important;fill:currentColor;stroke:currentColor;margin-right:unset;margin-inline-end:16px!important}ion-content .history-container ion-card ion-card-content ion-list ion-item ion-text,ion-content .history-container ion-card ion-card-content ion-list ion-item ion-label{color:var(--ion-item-text-color)!important}ion-content .bottom-banner{--ion-card-background-color: rgba(var(--ion-background-color-rgb), .5);background-color:var(--ion-card-background-color);min-width:240px;z-index:0;border-radius:4px;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);margin:16px}ion-content .bottom-banner img.logo{max-height:50px;margin-left:8px}ion-content .bottom-banner ion-list-header{min-height:30px}ion-content .bottom-banner ion-item{--min-height: 28px}ion-content .bottom-banner ion-item ion-label{margin-top:3px!important;margin-bottom:3px!important}ion-content ion-text{text-align:center}@media screen and (max-width: 575px){ion-content ion-card{min-width:160px;width:calc(100% - 20px);max-width:100%;margin-left:10px;margin-right:10px}ion-content ion-card h1{margin-top:0;font-size:20px}ion-content ion-card ion-card-content ion-button{margin-top:8px}ion-content .bottom-banner.floating{display:block;position:unset}ion-content .bottom-banner img.logo{max-height:30px}}@media screen and (max-width: 767px) and (min-width: 576px){ion-content{min-height:555px}ion-content .bottom-banner img.logo{max-height:40px}}@media screen and (min-width: 768px){ion-content{min-height:calc(100% - var(--bottom-banner-height))}}@media screen and (min-width: 1200px){ion-content ion-col.feed{height:fit-content;max-height:calc(100vh - var(--ion-toolbar-height) - var(--bottom-banner-height) - var(--ion-padding) * 2);padding-inline-end:calc(var(--ion-padding) - 10px)}ion-content .bottom-banner.floating{position:fixed;left:0;right:0;bottom:0;overflow-y:auto;max-height:var(--bottom-banner-height);margin-top:0}}.content-credits{float:right}.content-credits.floating{float:unset;position:fixed;bottom:0;right:var(--scrollbar-width, 0)}.content-credits ion-text{padding-inline-start:4px;padding-inline-end:4px;font-size:.7rem;background-color:rgba(var(--ion-background-color-rgb),.5);color:rgba(var(--ion-text-color-rgb),.7)}@media screen and (min-width: 992px){.left-border{border-left:1px solid var(--ion-color-medium)}}\n"] }]
|
|
35510
|
+
args: [{ selector: 'app-page-home', changeDetection: ChangeDetectionStrategy.OnPush, animations: [fadeInAnimation, slideUpDownAnimation, slideInAnimation], template: "<app-toolbar [canGoBack]=\"false\" visible-xs visible-sm visible-mobile>\n <ion-buttons slot=\"end\">\n @if (showNotificationIcon) {\n <app-user-event-notification-icon [autoHide]=\"autoHideNotificationIcon\"></app-user-event-notification-icon>\n }\n\n <!-- dark mode (if allow by the environment token) -->\n @if (settings.allowDarkMode) {\n <ion-button (click)=\"toggleDarkMode()\">\n <ion-icon slot=\"icon-only\" [name]=\"(darkMode$ | push) ? 'sunny' : 'moon'\"></ion-icon>\n </ion-button>\n }\n\n <!-- Change locale button -->\n <ion-button [matMenuTriggerFor]=\"localeMenu\">\n <ion-icon slot=\"start\" name=\"language\"></ion-icon>\n </ion-button>\n </ion-buttons>\n</app-toolbar>\n\n<!-- Change locale menu -->\n<mat-menu #localeMenu=\"matMenu\">\n <ng-template matMenuContent>\n @for (item of locales; track item.key) {\n <button mat-menu-item (click)=\"changeLanguage(item.key)\">\n <!--<mat-icon>{{ currentLocale === item.key ? 'checkmark' : undefined }}</mat-icon>-->\n <ion-label>{{ item.value }}</ion-label>\n </button>\n }\n </ng-template>\n</mat-menu>\n\n<ion-content [ngStyle]=\"contentStyle\" [class.has-scrollbar]=\"hasScrollbar\" no-padding-xs>\n <!-- loading spinner -->\n <div class=\"loading-page\" [class.cdk-visually-hidden]=\"!(loading$ | push)\">\n @if (showSpinner) {\n <div class=\"spinner\">\n <p [innerHTML]=\"'COMMON.LOADING_DOTS' | translate\"></p>\n <div class=\"sk-cube1 sk-cube\"></div>\n <div class=\"sk-cube2 sk-cube\"></div>\n <div class=\"sk-cube4 sk-cube\"></div>\n <div class=\"sk-cube3 sk-cube\"></div>\n </div>\n }\n </div>\n\n <!-- Desktop: translucent top toolbar -->\n @if (!mobile) {\n <div class=\"hidden-xs hidden-sm\">\n <ion-toolbar color=\"traansparent\" translucent>\n <ion-buttons slot=\"start\">\n <ion-menu-toggle>\n <ion-button color=\"light\" fill=\"clear\">\n <ion-icon slot=\"icon-only\" name=\"menu\"></ion-icon>\n </ion-button>\n </ion-menu-toggle>\n </ion-buttons>\n\n <ion-buttons slot=\"end\">\n @if (showNotificationIcon) {\n <app-user-event-notification-icon\n [style]=\"'ion-button'\"\n color=\"secondary\"\n unreadColor=\"tertiary\"\n fill=\"solid\"\n [autoHide]=\"autoHideNotificationIcon\"\n ></app-user-event-notification-icon>\n }\n\n <!-- dark mode (if allow by the environment token) -->\n @if (settings.allowDarkMode) {\n <ion-button\n color=\"secondary\"\n fill=\"solid\"\n (click)=\"toggleDarkMode()\"\n [title]=\"'HOME.BTN_DARK_MODE' | translate\"\n >\n <ion-icon slot=\"icon-only\" [name]=\"(darkMode$ | push) ? 'moon' : 'sunny'\"></ion-icon>\n </ion-button>\n }\n <!-- change locale button -->\n <ion-button\n color=\"secondary\"\n fill=\"solid\"\n [matMenuTriggerFor]=\"localeMenu\"\n [title]=\"'SETTINGS.LOCALE' | translate\"\n >\n <ion-icon slot=\"icon-only\" name=\"language\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </div>\n }\n\n <!-- Install (and upgrade) card -->\n <app-install-upgrade-card [isLogin]=\"isLogin\" [showInstallButton]=\"true\"></app-install-upgrade-card>\n\n @if (!(loading$ | push)) {\n @let hasFeed = hasFeed$ | async;\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col size=\"0\" [sizeXl]=\"hasFeed ? 3 : 0\"></ion-col>\n <ion-col>\n <!-- Welcome card -->\n <ion-card class=\"main welcome ion-padding ion-text-center ion-align-self-center\" @fadeInAnimation>\n <ion-card-header>\n <ion-card-title class=\"ion-text-center\">\n <span *ngIf=\"isWeb\" [innerHTML]=\"'HOME.WELCOME_WEB' | translate: { appName: appName }\"></span>\n <span *ngIf=\"!isWeb\" [innerHTML]=\"'HOME.WELCOME_APP' | translate: { appName: appName }\"></span>\n </ion-card-title>\n <ion-card-subtitle [innerHTML]=\"description\"></ion-card-subtitle>\n </ion-card-header>\n <ion-card-content class=\"ion-no-padding\">\n <ion-text color=\"primary\">\n <img *ngIf=\"logo\" [attr.src]=\"logo\" alt=\"Logo\" />\n </ion-text>\n <!-- register help text -->\n <ion-text *ngIf=\"!isLogin && canRegister\">\n <br />\n <span translate>HOME.REGISTER_HELP</span>\n </ion-text>\n <div class=\"ion-padding-top\">\n <!-- If NOT login -->\n <ng-container *ngIf=\"!isLogin; else loginButtons\">\n <ion-button *ngIf=\"canRegister\" expand=\"block\" color=\"tertiary\" (click)=\"register()\">\n <span translate>HOME.BTN_REGISTER</span>\n </ion-button>\n <ion-button expand=\"block\" color=\"light\" [routerLink]=\"['/']\" (click)=\"login()\">\n <span translate>AUTH.BTN_LOGIN</span>\n </ion-button>\n </ng-container>\n\n <!-- If user login -->\n <ng-template #loginButtons>\n <!-- Feature buttons -->\n <ng-container *rxIf=\"$filteredButtons; let buttons\">\n <ng-container *ngFor=\"let item of buttons\">\n <ion-button\n *ngIf=\"item.path\"\n expand=\"block\"\n color=\"tertiary\"\n [class]=\"item.cssClass\"\n [routerLink]=\"item.path\"\n routerDirection=\"root\"\n >\n <ion-icon slot=\"start\" class=\"ion-float-start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" class=\"ion-float-start\" *ngIf=\"item.matIcon\">\n {{ item.matIcon }}\n </mat-icon>\n <ion-text>{{ 'HOME.BTN_DATA_ENTRY' | translate: { name: (item.title | translate) } }}</ion-text>\n </ion-button>\n\n <!-- divider -->\n <div *ngIf=\"!item.path && !item.action\" [class]=\"item.cssClass\">\n <ion-label translate>{{ item.title }} </ion-label>\n </div>\n </ng-container>\n\n <!--<p *ngIf=\"buttons.length\" class=\"visible-mobile\"> </p>-->\n </ng-container>\n\n <ion-button *ngIf=\"showAccountButton\" expand=\"block\" color=\"secondary\" [routerLink]=\"['/account']\">\n <ion-icon slot=\"start\" class=\"ion-float-start\" name=\"person-circle\"></ion-icon>\n <ion-text translate>HOME.BTN_MY_ACCOUNT</ion-text>\n </ion-button>\n\n <p hidden-xs hidden-sm hidden-mobile>\n <ion-text\n [innerHTML]=\"'HOME.NOT_THIS_ACCOUNT_QUESTION' | translate: { displayName: accountName }\"\n ></ion-text>\n <br />\n <ion-text>\n <a href=\"#\" (click)=\"logout($event)\">\n <span translate>HOME.BTN_DISCONNECT</span>\n </a>\n </ion-text>\n </p>\n </ng-template>\n </div>\n </ion-card-content>\n </ion-card>\n </ion-col>\n <ion-col size=\"0\" [sizeXl]=\"hasFeed ? 1 : 0\"></ion-col>\n <ion-col [class.feed]=\"hasFeed\" [size]=\"hasFeed ? 12 : 0\" [sizeXl]=\"hasFeed ? 4 : 0\">\n @if (showFeed) {\n @if (mobile) {\n <app-feed\n #feed\n shape=\"round\"\n [urls]=\"feedUrls\"\n [maxAgeInMonths]=\"feedMaxAgeInMonths\"\n [maxContentLength]=\"feedMaxContentLength\"\n (ngInit)=\"initFeed(feed)\"\n @fadeInAnimation\n ></app-feed>\n } @else {\n <app-feed\n #feed\n shape=\"round\"\n [debug]=\"false\"\n [urls]=\"feedUrls\"\n [maxAgeInMonths]=\"feedMaxAgeInMonths\"\n [maxContentLength]=\"feedMaxContentLength\"\n (ngInit)=\"initFeed(feed)\"\n @slideInAnimation\n @fadeInAnimation\n ></app-feed>\n }\n }\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Page history -->\n @let pageHistory = isLogin && (pageHistory$ | push);\n @if (pageHistory | isNotEmptyArray) {\n <ion-grid class=\"history-container ion-align-self-center\">\n <ion-row>\n @for (page of pageHistory; track page.path) {\n <ion-col size=\"12\" size-xl=\"\" class=\"ion-text-center\">\n <ion-card class=\"ion-align-self-start ion-text-start\" @fadeInAnimation>\n <ion-card-header class=\"ion-no-padding\">\n <!-- top bar -->\n <ion-card-subtitle>\n <button\n type=\"button\"\n tabindex=\"-1\"\n (click)=\"removePageHistory(page.path)\"\n mat-icon-button\n class=\"ion-float-start ion-no-margin close-button\"\n >\n <mat-icon>close</mat-icon>\n </button>\n <ion-label [innerHTML]=\"page.subtitle | translate\"></ion-label>\n <ion-text class=\"ion-float-end\" [title]=\"page.time | dateFormat: { time: true }\">\n <small>\n <ion-icon name=\"time-outline\"></ion-icon>\n {{ page.time | dateFromNow }}\n </small>\n \n </ion-text>\n </ion-card-subtitle>\n\n <!-- main page -->\n <ion-card-title class=\"ion-no-margin ion-no-padding\">\n <ion-item\n detail=\"true\"\n tappable\n class=\"text-1x\"\n [routerLink]=\"page.path\"\n routerDirection=\"root\"\n lines=\"none\"\n >\n <!-- page icon-->\n <ion-icon *ngIf=\"page.icon\" slot=\"start\" [name]=\"page.icon\"></ion-icon>\n <mat-icon *ngIf=\"page.matIcon\" slot=\"start\">{{ page.matIcon }}</mat-icon>\n\n <ion-label color=\"primary\" [innerHTML]=\"page.title\"></ion-label>\n </ion-item>\n </ion-card-title>\n </ion-card-header>\n\n <!-- children pages -->\n @if (page.children | isNotEmptyArray) {\n <ion-card-content class=\"ion-no-padding ion-padding-start\">\n <ion-list class=\"ion-no-padding\">\n @for (childPage of page.children; track childPage.path) {\n <ion-item\n detail=\"true\"\n tappable\n class=\"text-1x\"\n [routerLink]=\"childPage.path\"\n routerDirection=\"root\"\n >\n <!-- page icon-->\n <ion-icon *ngIf=\"childPage.icon\" slot=\"start\" color=\"dark\" [name]=\"childPage.icon\"></ion-icon>\n <mat-icon *ngIf=\"childPage.matIcon\" slot=\"start\" color=\"dark\">\n {{ childPage.matIcon }}\n </mat-icon>\n\n <ion-label color=\"dark\" [innerHTML]=\"childPage.title\"></ion-label>\n </ion-item>\n }\n </ion-list>\n </ion-card-content>\n }\n </ion-card>\n </ion-col>\n }\n </ion-row>\n </ion-grid>\n }\n\n <!-- Bottom banner -->\n @if (showPartnerBanner || showLegalInformation) {\n <ion-grid\n class=\"bottom-banner ion-text-center\"\n [class.floating]=\"!mobile && (pageHistory | isEmptyArray)\"\n @fadeInAnimation\n >\n <ion-row>\n <!-- partners logos -->\n @if (showPartnerBanner) {\n <ion-col size=\"12\" [sizeLg]=\"partnerBannerSize\" class=\"ion-text-center\">\n @if (showLegalInformation) {\n <ion-list class=\"legal-info\">\n <ion-list-header>{{ 'HOME.PARTNERS' | translate }}</ion-list-header>\n </ion-list>\n }\n <!-- partners -->\n @for (item of $partners | async; track $index) {\n <a href=\"{{ item.siteUrl }}\">\n <img class=\"logo\" src=\"{{ item.logo }}\" alt=\"{{ item.label }}\" [title]=\"item.label\" />\n </a>\n }\n </ion-col>\n }\n\n <!-- legal information -->\n @if (showLegalInformation) {\n <ion-col size=\"12\" size-sm=\"6\" size-lg=\"4\" [class.left-border]=\"showPartnerBanner\">\n <ion-list class=\"legal-info\">\n <ion-list-header class=\"ion-text-left\">{{ 'HOME.LEGAL_INFORMATION' | translate }}</ion-list-header>\n @for (item of legalInformation; track item.path) {\n <ion-item (click)=\"openMarkdownModal($event, item)\" lines=\"none\" [button]=\"true\">\n <ion-label>\n <p>\n {{ item.title | translate: item.titleArgs }}\n </p>\n </ion-label>\n </ion-item>\n }\n </ion-list>\n </ion-col>\n @if (showInstallLinks) {\n <ion-col size=\"12\" size-lg=\"3\" offset-lg=\"9\" [class.left-border]=\"showPartnerBanner\">\n <ion-list class=\"legal-info\">\n <ion-list-header>{{ 'HOME.INSTALL_APP' | translate }}</ion-list-header>\n <!-- TODO -->\n </ion-list>\n </ion-col>\n }\n }\n </ion-row>\n </ion-grid>\n }\n }\n\n <!-- image credits -->\n @if (contentCredits | isNotNilOrBlank) {\n <div class=\"content-credits\" [class.floating]=\"!mobile\">\n <ion-text>{{ contentCredits }}</ion-text>\n </div>\n }\n</ion-content>\n", styles: [":host{--ion-card-background-color: rgba(var(--ion-background-color-rgb), .7);--scrollbar-width: 0;--bottom-banner-height: 122px}h1,h2,h3,h4,h5{white-space:normal}.center,ion-content ion-card.welcome img{text-align:center;display:inline-block}ion-content{--background: transparent;background-size:cover;-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;background-color:var(--ion-background-color);display:inline-block;padding:15px}ion-content.has-scrollbar{--scrollbar-width: 8px}ion-content .loading-page{display:block;height:100%;width:100%;position:absolute;background-color:transparent;z-index:5;transition:background .5s linear;-webkit-transition:background 1.5s linear}ion-content .loading-page.hidden{background-color:rgba(var(--ion-color-primary),0)}ion-content ion-card{z-index:9;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}ion-content ion-card ion-card-header{display:block}ion-content ion-card ion-card-header ion-card-subtitle,ion-content ion-card ion-card-header ion-card-title{display:block;width:100%}ion-content ion-card.main{min-width:240px;max-width:400px;margin-left:auto;margin-right:auto}ion-content ion-card.welcome{background-color:var(--ion-card-background-color)}ion-content ion-card.welcome button{margin-top:16px}ion-content ion-card.welcome img{max-width:250px}ion-content .history-container{margin-left:auto;margin-right:auto}ion-content .history-container ion-card{display:inline-block;box-sizing:border-box;z-index:8;min-width:240px;max-width:400px;width:100%;margin-left:auto;margin-right:auto;background-color:var(--ion-card-background-color);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}ion-content .history-container ion-card ion-card-header ion-card-subtitle{height:40px}ion-content .history-container ion-card ion-card-header ion-card-subtitle button[float-start]{--mdc-icon-button-state-layer-size: 40px;padding:8px;z-index:99;margin:0}ion-content .history-container ion-card ion-card-header ion-card-subtitle ion-label{line-height:40px}ion-content .history-container ion-card ion-card-header ion-card-subtitle ion-label[float-end]{padding-right:16px;font-weight:400}ion-content .history-container ion-card ion-card-header ion-card-title ion-item{width:100%;--ion-item-background: $transparent;--ion-item-icon-color: var(--ion-color-primary);--ion-item-text-color: var(--ion-color-primary)}ion-content .history-container ion-card ion-card-header ion-card-title ion-item ion-icon[slot=start],ion-content .history-container ion-card ion-card-header ion-card-title ion-item mat-icon[slot=start]{margin-right:unset;margin-inline-end:16px!important;color:var(--ion-item-icon-color)!important;fill:currentColor;stroke:currentColor}ion-content .history-container ion-card ion-card-header ion-card-title ion-item ion-text,ion-content .history-container ion-card ion-card-header ion-card-title ion-item ion-label{color:var(--ion-item-text-color)!important;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;-ms-text-size-adjust:100%;text-size-adjust:100%}ion-content .history-container ion-card ion-card-content ion-list{--ion-item-background: var(--ion-color-transparent)}ion-content .history-container ion-card ion-card-content ion-list ion-item{--ion-item-icon-color: var(--ion-color-dark);--ion-item-text-color: var(--ion-color-dark)}ion-content .history-container ion-card ion-card-content ion-list ion-item ion-icon[slot=start],ion-content .history-container ion-card ion-card-content ion-list ion-item mat-icon[slot=start]{color:var(--ion-item-icon-color)!important;fill:currentColor;stroke:currentColor;margin-right:unset;margin-inline-end:16px!important}ion-content .history-container ion-card ion-card-content ion-list ion-item ion-text,ion-content .history-container ion-card ion-card-content ion-list ion-item ion-label{color:var(--ion-item-text-color)!important}ion-content .bottom-banner{--ion-card-background-color: rgba(var(--ion-background-color-rgb), .5);background-color:var(--ion-card-background-color);min-width:240px;z-index:0;border-radius:4px;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);margin:16px}ion-content .bottom-banner img.logo{max-height:50px;margin-left:8px}ion-content .bottom-banner ion-list-header{min-height:30px}ion-content .bottom-banner ion-item{--min-height: 28px}ion-content .bottom-banner ion-item ion-label{margin-top:3px!important;margin-bottom:3px!important}ion-content ion-text{text-align:center}@media screen and (max-width: 575px){ion-content ion-card{min-width:160px;width:calc(100% - 20px);max-width:100%;margin-left:10px;margin-right:10px}ion-content ion-card h1{margin-top:0;font-size:20px}ion-content ion-card ion-card-content ion-button{margin-top:8px}ion-content .bottom-banner.floating{display:block;position:unset}ion-content .bottom-banner img.logo{max-height:30px}}@media screen and (max-width: 767px) and (min-width: 576px){ion-content{min-height:555px}ion-content .bottom-banner img.logo{max-height:40px}}@media screen and (min-width: 768px){ion-content{min-height:calc(100% - var(--bottom-banner-height))}}@media screen and (min-width: 1200px){ion-content ion-col.feed{height:fit-content;max-height:calc(100vh - var(--ion-toolbar-height) - var(--bottom-banner-height) - var(--ion-padding) * 2);padding-inline-end:calc(var(--ion-padding) - 10px);overflow:hidden}ion-content .bottom-banner.floating{position:fixed;left:0;right:0;bottom:0;overflow-y:auto;max-height:var(--bottom-banner-height);margin-top:0}}.content-credits{float:right}.content-credits.floating{float:unset;position:fixed;bottom:0;right:var(--scrollbar-width, 0)}.content-credits ion-text{padding-inline-start:4px;padding-inline-end:4px;font-size:.7rem;background-color:rgba(var(--ion-background-color-rgb),.5);color:rgba(var(--ion-text-color-rgb),.7)}@media screen and (min-width: 992px){.left-border{border-left:1px solid var(--ion-color-medium)}}\n"] }]
|
|
34594
35511
|
}], ctorParameters: () => [{ type: AccountService }, { type: i2$1.ModalController }, { type: i1$1.TranslateService }, { type: i2$1.ToastController }, { type: ConfigService }, { type: PlatformService }, { type: i0.ChangeDetectorRef }, { type: NetworkService }, { type: LocalSettingsService }, { type: Environment, decorators: [{
|
|
34595
35512
|
type: Inject,
|
|
34596
35513
|
args: [ENVIRONMENT]
|
|
@@ -34777,17 +35694,72 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
34777
35694
|
}]
|
|
34778
35695
|
}] });
|
|
34779
35696
|
|
|
35697
|
+
class FeedPage {
|
|
35698
|
+
settings;
|
|
35699
|
+
cd;
|
|
35700
|
+
feedService;
|
|
35701
|
+
environment;
|
|
35702
|
+
destroySubject = new Subject();
|
|
35703
|
+
loadingSubject = new BehaviorSubject(true);
|
|
35704
|
+
debug;
|
|
35705
|
+
title = 'SOCIAL.FEED.NEWS';
|
|
35706
|
+
feedUrls;
|
|
35707
|
+
feedItemId;
|
|
35708
|
+
constructor(settings, cd, feedService, environment) {
|
|
35709
|
+
this.settings = settings;
|
|
35710
|
+
this.cd = cd;
|
|
35711
|
+
this.feedService = feedService;
|
|
35712
|
+
this.environment = environment;
|
|
35713
|
+
this.debug = !environment?.production;
|
|
35714
|
+
}
|
|
35715
|
+
async ngOnInit() {
|
|
35716
|
+
this.feedService.ready();
|
|
35717
|
+
this.feedUrls = this.feedUrls ?? (await firstNotNilPromise(this.feedService.feedUrls$, { stop: this.destroySubject }));
|
|
35718
|
+
console.debug('[feed-page] Feed URLs:', this.feedUrls);
|
|
35719
|
+
this.loadingSubject.next(false);
|
|
35720
|
+
this.cd.markForCheck();
|
|
35721
|
+
}
|
|
35722
|
+
ngOnDestroy() {
|
|
35723
|
+
this.destroySubject.next();
|
|
35724
|
+
this.destroySubject.complete();
|
|
35725
|
+
}
|
|
35726
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FeedPage, deps: [{ token: LocalSettingsService }, { token: i0.ChangeDetectorRef }, { token: APP_FEED_SERVICE, optional: true }, { token: ENVIRONMENT, optional: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
35727
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: FeedPage, selector: "app-feed-page", inputs: { debug: "debug", title: "title", feedUrls: "feedUrls", feedItemId: "feedItemId" }, ngImport: i0, template: "<ion-header>\n <ion-toolbar color=\"primary\">\n <ion-buttons slot=\"start\">\n <ion-back-button></ion-back-button>\n </ion-buttons>\n\n <ion-title>{{ title | translate }}</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n <div class=\"ion-padding\">\n @if (loadingSubject | async) {\n <ion-spinner></ion-spinner>\n } @else {\n <app-feed [showHeader]=\"false\"\n [showReadMoreButton]=\"false\"\n [urls]=\"feedUrls\"\n cardColor=\"light\"\n [debug]=\"debug\"\n ></app-feed>\n }\n </div>\n</ion-content>\n", dependencies: [{ kind: "component", type: i2$1.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i2$1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2$1.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2$1.IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: i2$1.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: i2$1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonBackButton, selector: "ion-back-button" }, { kind: "component", type: FeedsComponent, selector: "app-feed", inputs: ["debug", "mobile", "showHeader", "showReadMoreButton", "headerColor", "cardColor", "shape", "class", "itemId", "filterItem", "feeds", "urls", "maxAgeInMonths", "maxContentLength"], outputs: ["editItem", "deleteItem"] }, { kind: "pipe", type: i3$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
35728
|
+
}
|
|
35729
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FeedPage, decorators: [{
|
|
35730
|
+
type: Component,
|
|
35731
|
+
args: [{ selector: 'app-feed-page', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ion-header>\n <ion-toolbar color=\"primary\">\n <ion-buttons slot=\"start\">\n <ion-back-button></ion-back-button>\n </ion-buttons>\n\n <ion-title>{{ title | translate }}</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n <div class=\"ion-padding\">\n @if (loadingSubject | async) {\n <ion-spinner></ion-spinner>\n } @else {\n <app-feed [showHeader]=\"false\"\n [showReadMoreButton]=\"false\"\n [urls]=\"feedUrls\"\n cardColor=\"light\"\n [debug]=\"debug\"\n ></app-feed>\n }\n </div>\n</ion-content>\n" }]
|
|
35732
|
+
}], ctorParameters: () => [{ type: LocalSettingsService }, { type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
|
|
35733
|
+
type: Optional
|
|
35734
|
+
}, {
|
|
35735
|
+
type: Inject,
|
|
35736
|
+
args: [APP_FEED_SERVICE]
|
|
35737
|
+
}] }, { type: Environment, decorators: [{
|
|
35738
|
+
type: Optional
|
|
35739
|
+
}, {
|
|
35740
|
+
type: Inject,
|
|
35741
|
+
args: [ENVIRONMENT]
|
|
35742
|
+
}] }], propDecorators: { debug: [{
|
|
35743
|
+
type: Input
|
|
35744
|
+
}], title: [{
|
|
35745
|
+
type: Input
|
|
35746
|
+
}], feedUrls: [{
|
|
35747
|
+
type: Input
|
|
35748
|
+
}], feedItemId: [{
|
|
35749
|
+
type: Input
|
|
35750
|
+
}] } });
|
|
35751
|
+
|
|
34780
35752
|
class FeedModule {
|
|
34781
35753
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FeedModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
34782
|
-
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: FeedModule, declarations: [FeedsComponent, FeedDirective], imports: [SharedModule, i1$1.TranslateModule, SharedDebugModule, SharedMarkdownModule], exports: [TranslateModule, FeedsComponent, FeedDirective] });
|
|
35754
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: FeedModule, declarations: [FeedsComponent, FeedPage, FeedDirective], imports: [SharedModule, i1$1.TranslateModule, SharedDebugModule, SharedMarkdownModule], exports: [TranslateModule, FeedsComponent, FeedPage, FeedDirective] });
|
|
34783
35755
|
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FeedModule, imports: [SharedModule, TranslateModule.forChild(), SharedDebugModule, SharedMarkdownModule, TranslateModule] });
|
|
34784
35756
|
}
|
|
34785
35757
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FeedModule, decorators: [{
|
|
34786
35758
|
type: NgModule,
|
|
34787
35759
|
args: [{
|
|
34788
35760
|
imports: [SharedModule, TranslateModule.forChild(), SharedDebugModule, SharedMarkdownModule],
|
|
34789
|
-
declarations: [FeedsComponent, FeedDirective],
|
|
34790
|
-
exports: [TranslateModule, FeedsComponent, FeedDirective],
|
|
35761
|
+
declarations: [FeedsComponent, FeedPage, FeedDirective],
|
|
35762
|
+
exports: [TranslateModule, FeedsComponent, FeedPage, FeedDirective],
|
|
34791
35763
|
}]
|
|
34792
35764
|
}] });
|
|
34793
35765
|
|
|
@@ -44381,369 +45353,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
44381
45353
|
type: Optional
|
|
44382
45354
|
}] }] });
|
|
44383
45355
|
|
|
44384
|
-
var PersonFilter_1;
|
|
44385
|
-
// @dynamic
|
|
44386
|
-
let PersonFilter = class PersonFilter extends EntityFilter {
|
|
44387
|
-
static { PersonFilter_1 = this; }
|
|
44388
|
-
static fromObject;
|
|
44389
|
-
static searchFilter(source) {
|
|
44390
|
-
return source && PersonFilter_1.fromObject(source).asFilterFn();
|
|
44391
|
-
}
|
|
44392
|
-
email;
|
|
44393
|
-
pubkey;
|
|
44394
|
-
searchText;
|
|
44395
|
-
statusIds;
|
|
44396
|
-
userProfiles;
|
|
44397
|
-
includedIds;
|
|
44398
|
-
excludedIds;
|
|
44399
|
-
searchAttribute;
|
|
44400
|
-
searchAttributes;
|
|
44401
|
-
constructor() {
|
|
44402
|
-
super(PersonFilter_1.TYPENAME);
|
|
44403
|
-
}
|
|
44404
|
-
fromObject(source, opts) {
|
|
44405
|
-
super.fromObject(source, opts);
|
|
44406
|
-
this.email = source.email;
|
|
44407
|
-
this.pubkey = source.pubkey;
|
|
44408
|
-
this.searchText = source.searchText;
|
|
44409
|
-
this.statusIds = source.statusIds || (isNotNil(source.statusId) ? [source.statusId] : undefined);
|
|
44410
|
-
this.userProfiles = source.userProfiles;
|
|
44411
|
-
this.excludedIds = source.excludedIds;
|
|
44412
|
-
this.searchAttribute = source.searchAttribute;
|
|
44413
|
-
this.searchAttributes = source.searchAttributes;
|
|
44414
|
-
}
|
|
44415
|
-
asObject(opts) {
|
|
44416
|
-
const target = super.asObject(opts);
|
|
44417
|
-
target.email = this.email;
|
|
44418
|
-
target.pubkey = this.pubkey;
|
|
44419
|
-
target.searchText = this.searchText;
|
|
44420
|
-
target.statusIds = this.statusIds;
|
|
44421
|
-
target.userProfiles = this.userProfiles;
|
|
44422
|
-
target.excludedIds = this.excludedIds;
|
|
44423
|
-
target.searchAttribute = this.searchAttribute;
|
|
44424
|
-
target.searchAttributes = this.searchAttributes;
|
|
44425
|
-
return target;
|
|
44426
|
-
}
|
|
44427
|
-
buildFilter() {
|
|
44428
|
-
const filterFns = super.buildFilter();
|
|
44429
|
-
// Filter by status
|
|
44430
|
-
if (isNotEmptyArray(this.statusIds)) {
|
|
44431
|
-
filterFns.push((e) => this.statusIds.includes(e.statusId));
|
|
44432
|
-
}
|
|
44433
|
-
// Filter included ids
|
|
44434
|
-
const includedIds = this.includedIds;
|
|
44435
|
-
if (isNotEmptyArray(includedIds)) {
|
|
44436
|
-
filterFns.push((e) => isNotNil(e.id) && includedIds.includes(e.id));
|
|
44437
|
-
}
|
|
44438
|
-
// Filter excluded ids
|
|
44439
|
-
const excludedIds = this.excludedIds;
|
|
44440
|
-
if (isNotEmptyArray(excludedIds)) {
|
|
44441
|
-
filterFns.push((e) => isNil(e.id) || !excludedIds.includes(e.id));
|
|
44442
|
-
}
|
|
44443
|
-
// Search text
|
|
44444
|
-
const searchTextFilter = EntityUtils.searchTextFilter(this.searchAttribute || this.searchAttributes || ['lastName', 'firstName', 'department.name'], this.searchText);
|
|
44445
|
-
if (searchTextFilter)
|
|
44446
|
-
filterFns.push(searchTextFilter);
|
|
44447
|
-
return filterFns;
|
|
44448
|
-
}
|
|
44449
|
-
};
|
|
44450
|
-
PersonFilter = PersonFilter_1 = __decorate([
|
|
44451
|
-
EntityClass({ typename: 'PersonFilterVO' })
|
|
44452
|
-
], PersonFilter);
|
|
44453
|
-
|
|
44454
|
-
const MessageTypes = {
|
|
44455
|
-
INBOX_MESSAGE: 'INBOX_MESSAGE',
|
|
44456
|
-
EMAIL: 'EMAIL',
|
|
44457
|
-
FEED: 'FEED',
|
|
44458
|
-
};
|
|
44459
|
-
const MessageTypeList = Object.freeze([
|
|
44460
|
-
{
|
|
44461
|
-
id: MessageTypes.INBOX_MESSAGE,
|
|
44462
|
-
icon: 'notifications',
|
|
44463
|
-
label: 'SOCIAL.MESSAGE.TYPE_ENUM.INBOX_MESSAGE',
|
|
44464
|
-
},
|
|
44465
|
-
{
|
|
44466
|
-
id: MessageTypes.EMAIL,
|
|
44467
|
-
icon: 'mail',
|
|
44468
|
-
label: 'SOCIAL.MESSAGE.TYPE_ENUM.EMAIL',
|
|
44469
|
-
},
|
|
44470
|
-
{
|
|
44471
|
-
id: MessageTypes.FEED,
|
|
44472
|
-
icon: 'megaphone',
|
|
44473
|
-
label: 'SOCIAL.MESSAGE.TYPE_ENUM.FEED',
|
|
44474
|
-
},
|
|
44475
|
-
]);
|
|
44476
|
-
// @dynamic
|
|
44477
|
-
let Message = class Message extends Entity {
|
|
44478
|
-
static fromObject;
|
|
44479
|
-
type;
|
|
44480
|
-
issuer;
|
|
44481
|
-
recipients;
|
|
44482
|
-
recipientFilter;
|
|
44483
|
-
subject;
|
|
44484
|
-
body;
|
|
44485
|
-
constructor() {
|
|
44486
|
-
super();
|
|
44487
|
-
}
|
|
44488
|
-
fromObject(source, opts) {
|
|
44489
|
-
super.fromObject(source, opts);
|
|
44490
|
-
this.type = source.type;
|
|
44491
|
-
this.issuer = source.issuer && Person.fromObject(source.issuer);
|
|
44492
|
-
this.recipients = source.recipients && source.recipients.map(Person.fromObject);
|
|
44493
|
-
this.recipientFilter = (source.recipientFilter && PersonFilter.fromObject(source.recipientFilter)) || undefined;
|
|
44494
|
-
this.subject = source.subject;
|
|
44495
|
-
this.body = source.body;
|
|
44496
|
-
}
|
|
44497
|
-
asObject(opts) {
|
|
44498
|
-
const target = super.asObject(opts);
|
|
44499
|
-
target.recipients = this.recipients && this.recipients.map((p) => p.asObject(opts));
|
|
44500
|
-
target.recipientFilter = (this.recipientFilter && this.recipientFilter.asObject(opts)) || undefined;
|
|
44501
|
-
return target;
|
|
44502
|
-
}
|
|
44503
|
-
};
|
|
44504
|
-
Message = __decorate([
|
|
44505
|
-
EntityClass({ typename: 'MessageVO' })
|
|
44506
|
-
], Message);
|
|
44507
|
-
// @dynamic
|
|
44508
|
-
let MessageFilter = class MessageFilter extends EntityFilter {
|
|
44509
|
-
static fromObject;
|
|
44510
|
-
fromObject(source, opts) {
|
|
44511
|
-
super.fromObject(source, opts);
|
|
44512
|
-
}
|
|
44513
|
-
buildFilter() {
|
|
44514
|
-
return super.buildFilter();
|
|
44515
|
-
}
|
|
44516
|
-
};
|
|
44517
|
-
MessageFilter = __decorate([
|
|
44518
|
-
EntityClass({ typename: 'MessageFilterVO' })
|
|
44519
|
-
], MessageFilter);
|
|
44520
|
-
|
|
44521
|
-
class MessageForm extends AppForm {
|
|
44522
|
-
formBuilder;
|
|
44523
|
-
cd;
|
|
44524
|
-
mobile;
|
|
44525
|
-
suggestFn;
|
|
44526
|
-
subjectMinLength = 5;
|
|
44527
|
-
subjectMaxLength = 255;
|
|
44528
|
-
bodyMaxLength = 2000;
|
|
44529
|
-
bodyAutoHeight = true;
|
|
44530
|
-
canSelectType = false;
|
|
44531
|
-
canRecipientFilter = false;
|
|
44532
|
-
recipientFilterCount = 0;
|
|
44533
|
-
types = MessageTypeList;
|
|
44534
|
-
constructor(injector, formBuilder, cd) {
|
|
44535
|
-
super(injector);
|
|
44536
|
-
this.formBuilder = formBuilder;
|
|
44537
|
-
this.cd = cd;
|
|
44538
|
-
this.mobile = this.settings.mobile;
|
|
44539
|
-
}
|
|
44540
|
-
ngOnInit() {
|
|
44541
|
-
this.setForm(this.formBuilder.group({
|
|
44542
|
-
type: [MessageTypes.INBOX_MESSAGE, Validators.required],
|
|
44543
|
-
recipients: [null, Validators.required],
|
|
44544
|
-
recipientFilter: [null],
|
|
44545
|
-
subject: [
|
|
44546
|
-
null,
|
|
44547
|
-
this.subjectMaxLength
|
|
44548
|
-
? Validators.compose([Validators.required, Validators.minLength(this.subjectMinLength), Validators.maxLength(this.subjectMaxLength)])
|
|
44549
|
-
: Validators.required,
|
|
44550
|
-
],
|
|
44551
|
-
body: [null, this.bodyMaxLength ? Validators.compose([Validators.maxLength(this.bodyMaxLength)]) : Validators.required],
|
|
44552
|
-
}));
|
|
44553
|
-
this.registerSubscription(this._form
|
|
44554
|
-
.get('type')
|
|
44555
|
-
.valueChanges.pipe(filter(isNotNil))
|
|
44556
|
-
.subscribe((type) => this.updateFormGroup(this._form, { type })));
|
|
44557
|
-
// Person combo
|
|
44558
|
-
const personAttributes = this.settings.getFieldDisplayAttributes('person', ['lastName', 'firstName', 'department.name']);
|
|
44559
|
-
this.registerAutocompleteField('recipients', {
|
|
44560
|
-
showAllOnFocus: false,
|
|
44561
|
-
suggestFn: this.suggestFn,
|
|
44562
|
-
filter: {
|
|
44563
|
-
statusIds: [StatusIds.TEMPORARY, StatusIds.ENABLE],
|
|
44564
|
-
},
|
|
44565
|
-
attributes: personAttributes,
|
|
44566
|
-
columnNames: personAttributes.map((attr) => `USER.${changeCaseToUnderscore(attr).toUpperCase()}`),
|
|
44567
|
-
displayWith: PersonUtils.personToString,
|
|
44568
|
-
multiple: true,
|
|
44569
|
-
mobile: this.mobile,
|
|
44570
|
-
});
|
|
44571
|
-
}
|
|
44572
|
-
isSamePerson(o1, o2) {
|
|
44573
|
-
return EntityUtils.equals(o1, o2, 'id');
|
|
44574
|
-
}
|
|
44575
|
-
updateFormGroup(formGroup, opts) {
|
|
44576
|
-
console.debug('[message-form] Updating form group...', opts);
|
|
44577
|
-
// Recipient validator
|
|
44578
|
-
const recipientsRequired = toBoolean(opts?.recipientRequired, opts?.type !== MessageTypes.FEED);
|
|
44579
|
-
{
|
|
44580
|
-
const control = formGroup.get('recipients');
|
|
44581
|
-
if (recipientsRequired) {
|
|
44582
|
-
if (!control.hasValidator(Validators.required)) {
|
|
44583
|
-
control.addValidators(Validators.required);
|
|
44584
|
-
}
|
|
44585
|
-
control.enable();
|
|
44586
|
-
}
|
|
44587
|
-
else {
|
|
44588
|
-
if (control.hasValidator(Validators.required)) {
|
|
44589
|
-
control.removeValidators(Validators.required);
|
|
44590
|
-
}
|
|
44591
|
-
control.disable();
|
|
44592
|
-
}
|
|
44593
|
-
}
|
|
44594
|
-
// Recipient filter validator
|
|
44595
|
-
const recipientFilterRequired = this.canRecipientFilter && !recipientsRequired;
|
|
44596
|
-
{
|
|
44597
|
-
const control = formGroup.get('recipientFilter');
|
|
44598
|
-
if (recipientFilterRequired) {
|
|
44599
|
-
if (!control.hasValidator(Validators.required)) {
|
|
44600
|
-
control.addValidators(Validators.required);
|
|
44601
|
-
}
|
|
44602
|
-
control.enable();
|
|
44603
|
-
}
|
|
44604
|
-
else {
|
|
44605
|
-
if (control.hasValidator(Validators.required)) {
|
|
44606
|
-
control.removeValidators(Validators.required);
|
|
44607
|
-
}
|
|
44608
|
-
control.disable();
|
|
44609
|
-
}
|
|
44610
|
-
}
|
|
44611
|
-
formGroup.updateValueAndValidity();
|
|
44612
|
-
}
|
|
44613
|
-
markForCheck() {
|
|
44614
|
-
this.cd.markForCheck();
|
|
44615
|
-
}
|
|
44616
|
-
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 });
|
|
44617
|
-
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 });
|
|
44618
|
-
}
|
|
44619
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessageForm, decorators: [{
|
|
44620
|
-
type: Component,
|
|
44621
|
-
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"] }]
|
|
44622
|
-
}], ctorParameters: () => [{ type: i0.Injector }, { type: i1$3.UntypedFormBuilder }, { type: i0.ChangeDetectorRef }], propDecorators: { suggestFn: [{
|
|
44623
|
-
type: Input
|
|
44624
|
-
}], subjectMinLength: [{
|
|
44625
|
-
type: Input
|
|
44626
|
-
}], subjectMaxLength: [{
|
|
44627
|
-
type: Input
|
|
44628
|
-
}], bodyMaxLength: [{
|
|
44629
|
-
type: Input
|
|
44630
|
-
}], bodyAutoHeight: [{
|
|
44631
|
-
type: Input
|
|
44632
|
-
}], canSelectType: [{
|
|
44633
|
-
type: Input
|
|
44634
|
-
}], canRecipientFilter: [{
|
|
44635
|
-
type: Input
|
|
44636
|
-
}], recipientFilterCount: [{
|
|
44637
|
-
type: Input
|
|
44638
|
-
}] } });
|
|
44639
|
-
|
|
44640
|
-
class MessageModal {
|
|
44641
|
-
settings;
|
|
44642
|
-
viewCtrl;
|
|
44643
|
-
accountService;
|
|
44644
|
-
cd;
|
|
44645
|
-
mobile;
|
|
44646
|
-
suggestFn;
|
|
44647
|
-
data;
|
|
44648
|
-
canSelectType;
|
|
44649
|
-
canRecipientFilter;
|
|
44650
|
-
recipientFilterCount;
|
|
44651
|
-
form;
|
|
44652
|
-
constructor(settings, viewCtrl, accountService, cd) {
|
|
44653
|
-
this.settings = settings;
|
|
44654
|
-
this.viewCtrl = viewCtrl;
|
|
44655
|
-
this.accountService = accountService;
|
|
44656
|
-
this.cd = cd;
|
|
44657
|
-
this.mobile = this.settings.mobile;
|
|
44658
|
-
}
|
|
44659
|
-
ngOnInit() {
|
|
44660
|
-
this.canSelectType = toBoolean(this.canSelectType, this.accountService.isAdmin());
|
|
44661
|
-
}
|
|
44662
|
-
ngAfterViewInit() {
|
|
44663
|
-
setTimeout(() => {
|
|
44664
|
-
this.form.markAsReady({ emitEvent: false });
|
|
44665
|
-
if (this.data) {
|
|
44666
|
-
this.data.type = this.data.type || MessageTypes.INBOX_MESSAGE;
|
|
44667
|
-
this.form.setValue(this.data);
|
|
44668
|
-
}
|
|
44669
|
-
this.form.markAsLoaded();
|
|
44670
|
-
this.form.enable();
|
|
44671
|
-
});
|
|
44672
|
-
}
|
|
44673
|
-
cancel() {
|
|
44674
|
-
this.viewCtrl.dismiss();
|
|
44675
|
-
}
|
|
44676
|
-
async doSubmit() {
|
|
44677
|
-
if (this.form.disabled)
|
|
44678
|
-
return;
|
|
44679
|
-
if (!this.form.valid) {
|
|
44680
|
-
await AppFormUtils.waitWhilePending(this.form);
|
|
44681
|
-
if (this.form.invalid) {
|
|
44682
|
-
AppFormUtils.logFormErrors(this.form.form, '[message-modal] ');
|
|
44683
|
-
this.form.markAllAsTouched();
|
|
44684
|
-
return;
|
|
44685
|
-
}
|
|
44686
|
-
}
|
|
44687
|
-
this.markAsLoading();
|
|
44688
|
-
try {
|
|
44689
|
-
const data = this.form.value;
|
|
44690
|
-
// Disable the form
|
|
44691
|
-
this.form.disable();
|
|
44692
|
-
const entity = Message.fromObject(data);
|
|
44693
|
-
return this.viewCtrl.dismiss(entity);
|
|
44694
|
-
}
|
|
44695
|
-
catch (err) {
|
|
44696
|
-
this.form.error = (err && err.message) || err;
|
|
44697
|
-
this.markAsLoaded();
|
|
44698
|
-
// Enable the form
|
|
44699
|
-
this.form.enable();
|
|
44700
|
-
// Reset form error on next changes
|
|
44701
|
-
firstNotNilPromise(this.form.form.valueChanges).then(() => {
|
|
44702
|
-
this.form.error = null;
|
|
44703
|
-
this.markForCheck();
|
|
44704
|
-
});
|
|
44705
|
-
return;
|
|
44706
|
-
}
|
|
44707
|
-
}
|
|
44708
|
-
markForCheck() {
|
|
44709
|
-
this.cd.markForCheck();
|
|
44710
|
-
}
|
|
44711
|
-
markAsLoading(opts) {
|
|
44712
|
-
this.form.markAsLoading(opts);
|
|
44713
|
-
}
|
|
44714
|
-
markAsLoaded(opts) {
|
|
44715
|
-
this.form.markAsLoaded(opts);
|
|
44716
|
-
}
|
|
44717
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessageModal, deps: [{ token: LocalSettingsService }, { token: i2$1.ModalController }, { token: AccountService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
44718
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: MessageModal, selector: "app-message-modal", inputs: { suggestFn: "suggestFn", data: "data", canSelectType: "canSelectType", canRecipientFilter: "canRecipientFilter", recipientFilterCount: "recipientFilterCount" }, viewQueries: [{ propertyName: "form", first: true, predicate: ["form"], descendants: true, static: true }], ngImport: i0, template: "<ion-header>\n <ion-toolbar color=\"secondary\">\n <ion-buttons slot=\"start\">\n <ion-button class=\"back-button\" (click)=\"cancel()\" visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title>\n {{ 'SOCIAL.MESSAGE.NEW.TITLE' | translate }}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <ion-button\n class=\"back-button\"\n (click)=\"doSubmit()\"\n [disabled]=\"!form.valid\"\n visible-xs\n visible-sm\n visible-mobile\n >\n <ion-icon slot=\"icon-only\" name=\"checkmark\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n <ion-item *ngIf=\"form.error\" visible-xs visible-sm visible-mobile lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"form.error | translate\"></ion-label>\n </ion-item>\n\n <app-message-form\n #form\n (onSubmit)=\"doSubmit()\"\n (onCancel)=\"cancel()\"\n [canSelectType]=\"canSelectType\"\n [canRecipientFilter]=\"canRecipientFilter\"\n [recipientFilterCount]=\"recipientFilterCount\"\n [suggestFn]=\"suggestFn\"\n ></app-message-form>\n</ion-content>\n\n<ion-footer hidden-xs hidden-sm hidden-mobile>\n <ion-toolbar>\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col></ion-col>\n\n <!-- buttons -->\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n\n <ion-button\n [fill]=\"form.invalid ? 'clear' : 'solid'\"\n [disabled]=\"form.loading || form.invalid\"\n (keyup.enter)=\"doSubmit()\"\n (click)=\"doSubmit()\"\n color=\"tertiary\"\n >\n <ion-label translate>COMMON.BTN_SEND</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-toolbar>\n</ion-footer>\n", dependencies: [{ kind: "directive", type: i3$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2$1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2$1.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i2$1.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i2$1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2$1.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2$1.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2$1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2$1.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2$1.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2$1.IonRow, selector: "ion-row" }, { kind: "component", type: i2$1.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: i2$1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: MessageForm, selector: "app-message-form", inputs: ["suggestFn", "subjectMinLength", "subjectMaxLength", "bodyMaxLength", "bodyAutoHeight", "canSelectType", "canRecipientFilter", "recipientFilterCount"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
44719
|
-
}
|
|
44720
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessageModal, decorators: [{
|
|
44721
|
-
type: Component,
|
|
44722
|
-
args: [{ selector: 'app-message-modal', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ion-header>\n <ion-toolbar color=\"secondary\">\n <ion-buttons slot=\"start\">\n <ion-button class=\"back-button\" (click)=\"cancel()\" visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title>\n {{ 'SOCIAL.MESSAGE.NEW.TITLE' | translate }}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <ion-button\n class=\"back-button\"\n (click)=\"doSubmit()\"\n [disabled]=\"!form.valid\"\n visible-xs\n visible-sm\n visible-mobile\n >\n <ion-icon slot=\"icon-only\" name=\"checkmark\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n <ion-item *ngIf=\"form.error\" visible-xs visible-sm visible-mobile lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"form.error | translate\"></ion-label>\n </ion-item>\n\n <app-message-form\n #form\n (onSubmit)=\"doSubmit()\"\n (onCancel)=\"cancel()\"\n [canSelectType]=\"canSelectType\"\n [canRecipientFilter]=\"canRecipientFilter\"\n [recipientFilterCount]=\"recipientFilterCount\"\n [suggestFn]=\"suggestFn\"\n ></app-message-form>\n</ion-content>\n\n<ion-footer hidden-xs hidden-sm hidden-mobile>\n <ion-toolbar>\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col></ion-col>\n\n <!-- buttons -->\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n\n <ion-button\n [fill]=\"form.invalid ? 'clear' : 'solid'\"\n [disabled]=\"form.loading || form.invalid\"\n (keyup.enter)=\"doSubmit()\"\n (click)=\"doSubmit()\"\n color=\"tertiary\"\n >\n <ion-label translate>COMMON.BTN_SEND</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-toolbar>\n</ion-footer>\n" }]
|
|
44723
|
-
}], ctorParameters: () => [{ type: LocalSettingsService }, { type: i2$1.ModalController }, { type: AccountService }, { type: i0.ChangeDetectorRef }], propDecorators: { suggestFn: [{
|
|
44724
|
-
type: Input
|
|
44725
|
-
}], data: [{
|
|
44726
|
-
type: Input
|
|
44727
|
-
}], canSelectType: [{
|
|
44728
|
-
type: Input
|
|
44729
|
-
}], canRecipientFilter: [{
|
|
44730
|
-
type: Input
|
|
44731
|
-
}], recipientFilterCount: [{
|
|
44732
|
-
type: Input
|
|
44733
|
-
}], form: [{
|
|
44734
|
-
type: ViewChild,
|
|
44735
|
-
args: ['form', { static: true }]
|
|
44736
|
-
}] } });
|
|
44737
|
-
|
|
44738
45356
|
class MessageModule {
|
|
44739
45357
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessageModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
44740
|
-
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: MessageModule, declarations: [MessageModal, MessageForm], imports: [CommonModule, CoreModule, SharedModule, MatChipsModule], exports: [MessageModal] });
|
|
44741
|
-
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessageModule, imports: [CommonModule, CoreModule, SharedModule, MatChipsModule] });
|
|
45358
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.13", ngImport: i0, type: MessageModule, declarations: [MessageModal, MessageForm], imports: [CommonModule, CoreModule, SharedModule, MatChipsModule, SharedDebugModule], exports: [MessageModal] });
|
|
45359
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessageModule, imports: [CommonModule, CoreModule, SharedModule, MatChipsModule, SharedDebugModule] });
|
|
44742
45360
|
}
|
|
44743
45361
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessageModule, decorators: [{
|
|
44744
45362
|
type: NgModule,
|
|
44745
45363
|
args: [{
|
|
44746
|
-
imports: [CommonModule, CoreModule, SharedModule, MatChipsModule],
|
|
45364
|
+
imports: [CommonModule, CoreModule, SharedModule, MatChipsModule, SharedDebugModule],
|
|
44747
45365
|
declarations: [MessageModal, MessageForm],
|
|
44748
45366
|
exports: [MessageModal],
|
|
44749
45367
|
}]
|
|
@@ -45171,271 +45789,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
45171
45789
|
}]
|
|
45172
45790
|
}] });
|
|
45173
45791
|
|
|
45174
|
-
const Mutations = {
|
|
45175
|
-
send: gql$1 `
|
|
45176
|
-
mutation SendMessage($data: MessageVOInput) {
|
|
45177
|
-
done: sendMessage(message: $data)
|
|
45178
|
-
}
|
|
45179
|
-
`,
|
|
45180
|
-
};
|
|
45181
|
-
class MessageService extends BaseGraphqlService {
|
|
45182
|
-
graphql;
|
|
45183
|
-
translate;
|
|
45184
|
-
modalCtrl;
|
|
45185
|
-
toastController;
|
|
45186
|
-
environment;
|
|
45187
|
-
constructor(graphql, translate, modalCtrl, toastController, environment) {
|
|
45188
|
-
super(graphql, environment);
|
|
45189
|
-
this.graphql = graphql;
|
|
45190
|
-
this.translate = translate;
|
|
45191
|
-
this.modalCtrl = modalCtrl;
|
|
45192
|
-
this.toastController = toastController;
|
|
45193
|
-
this.environment = environment;
|
|
45194
|
-
// For DEV only
|
|
45195
|
-
this._debug = !environment.production;
|
|
45196
|
-
}
|
|
45197
|
-
/**
|
|
45198
|
-
* Send a message to recipient(s)
|
|
45199
|
-
*
|
|
45200
|
-
* @param entity
|
|
45201
|
-
* @param opts
|
|
45202
|
-
*/
|
|
45203
|
-
async send(entity, opts) {
|
|
45204
|
-
// Transform into json
|
|
45205
|
-
const data = entity.asObject(MINIFY_ENTITY_FOR_POD);
|
|
45206
|
-
const now = Date.now();
|
|
45207
|
-
if (this._debug)
|
|
45208
|
-
console.debug(`[message-service] Sending message...`);
|
|
45209
|
-
try {
|
|
45210
|
-
const { done } = await this.graphql.mutate({
|
|
45211
|
-
mutation: Mutations.send,
|
|
45212
|
-
variables: { data },
|
|
45213
|
-
error: { code: SocialErrorCodes.SEND_MESSAGE_ERROR, message: 'SOCIAL.ERROR.SEND_MESSAGE_ERROR' },
|
|
45214
|
-
});
|
|
45215
|
-
if (this._debug)
|
|
45216
|
-
console.debug(`[message-service] Send message [OK] in ${Date.now() - now}ms`);
|
|
45217
|
-
if (done && (!opts || opts.showToast !== false)) {
|
|
45218
|
-
await this.showToast({ type: 'info', message: 'SOCIAL.INFO.MESSAGE_SENT' });
|
|
45219
|
-
}
|
|
45220
|
-
return done;
|
|
45221
|
-
}
|
|
45222
|
-
catch (err) {
|
|
45223
|
-
const error = (err && err.message) || err;
|
|
45224
|
-
console.error(error);
|
|
45225
|
-
// Show error
|
|
45226
|
-
if (!opts || opts.showToast !== false) {
|
|
45227
|
-
const message = error || 'SOCIAL.ERROR.SEND_MESSAGE_ERROR';
|
|
45228
|
-
await this.showToast({ type: 'error', message });
|
|
45229
|
-
}
|
|
45230
|
-
return false;
|
|
45231
|
-
}
|
|
45232
|
-
}
|
|
45233
|
-
async openComposeModal(options) {
|
|
45234
|
-
const hasTopModal = !!(await this.modalCtrl.getTop());
|
|
45235
|
-
const modal = await this.modalCtrl.create({
|
|
45236
|
-
component: MessageModal,
|
|
45237
|
-
componentProps: options,
|
|
45238
|
-
cssClass: hasTopModal && 'stack-modal',
|
|
45239
|
-
});
|
|
45240
|
-
// Open the modal
|
|
45241
|
-
await modal.present();
|
|
45242
|
-
// On dismiss
|
|
45243
|
-
const { data } = await modal.onDidDismiss();
|
|
45244
|
-
if (!data || !(data instanceof Message))
|
|
45245
|
-
return true; // CANCELLED
|
|
45246
|
-
// Send message
|
|
45247
|
-
return await this.send(data, { showToast: options?.showToast });
|
|
45248
|
-
}
|
|
45249
|
-
/* -- protected methods -- */
|
|
45250
|
-
async showToast(opts) {
|
|
45251
|
-
return Toasts.show(this.toastController, this.translate, {
|
|
45252
|
-
type: 'info',
|
|
45253
|
-
message: 'SOCIAL.INFO.MESSAGE_SENT',
|
|
45254
|
-
...opts,
|
|
45255
|
-
});
|
|
45256
|
-
}
|
|
45257
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessageService, deps: [{ token: GraphqlService }, { token: i1$1.TranslateService }, { token: i2$1.ModalController }, { token: i2$1.ToastController }, { token: ENVIRONMENT, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
45258
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessageService, providedIn: 'root' });
|
|
45259
|
-
}
|
|
45260
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MessageService, decorators: [{
|
|
45261
|
-
type: Injectable,
|
|
45262
|
-
args: [{ providedIn: 'root' }]
|
|
45263
|
-
}], ctorParameters: () => [{ type: GraphqlService }, { type: i1$1.TranslateService }, { type: i2$1.ModalController }, { type: i2$1.ToastController }, { type: Environment, decorators: [{
|
|
45264
|
-
type: Optional
|
|
45265
|
-
}, {
|
|
45266
|
-
type: Inject,
|
|
45267
|
-
args: [ENVIRONMENT]
|
|
45268
|
-
}] }] });
|
|
45269
|
-
|
|
45270
|
-
const PersonFragments = {
|
|
45271
|
-
person: gql$1 `
|
|
45272
|
-
fragment PersonFragment on PersonVO {
|
|
45273
|
-
id
|
|
45274
|
-
firstName
|
|
45275
|
-
lastName
|
|
45276
|
-
email
|
|
45277
|
-
pubkey
|
|
45278
|
-
avatar
|
|
45279
|
-
statusId
|
|
45280
|
-
updateDate
|
|
45281
|
-
creationDate
|
|
45282
|
-
profiles
|
|
45283
|
-
username
|
|
45284
|
-
usernameExtranet
|
|
45285
|
-
department {
|
|
45286
|
-
id
|
|
45287
|
-
label
|
|
45288
|
-
name
|
|
45289
|
-
logo
|
|
45290
|
-
__typename
|
|
45291
|
-
}
|
|
45292
|
-
__typename
|
|
45293
|
-
}
|
|
45294
|
-
`,
|
|
45295
|
-
};
|
|
45296
|
-
// Load persons query
|
|
45297
|
-
const PersonQueries = {
|
|
45298
|
-
loadAll: gql$1 `
|
|
45299
|
-
query Persons($offset: Int, $size: Int, $sortBy: String, $sortDirection: String, $filter: PersonFilterVOInput) {
|
|
45300
|
-
data: persons(filter: $filter, offset: $offset, size: $size, sortBy: $sortBy, sortDirection: $sortDirection) {
|
|
45301
|
-
...PersonFragment
|
|
45302
|
-
}
|
|
45303
|
-
}
|
|
45304
|
-
${PersonFragments.person}
|
|
45305
|
-
`,
|
|
45306
|
-
loadAllWithTotal: gql$1 `
|
|
45307
|
-
query PersonsWithTotal($offset: Int, $size: Int, $sortBy: String, $sortDirection: String, $filter: PersonFilterVOInput) {
|
|
45308
|
-
data: persons(filter: $filter, offset: $offset, size: $size, sortBy: $sortBy, sortDirection: $sortDirection) {
|
|
45309
|
-
...PersonFragment
|
|
45310
|
-
}
|
|
45311
|
-
total: personsCount(filter: $filter)
|
|
45312
|
-
}
|
|
45313
|
-
${PersonFragments.person}
|
|
45314
|
-
`,
|
|
45315
|
-
};
|
|
45316
|
-
const PersonMutations = {
|
|
45317
|
-
saveAll: gql$1 `
|
|
45318
|
-
mutation savePersons($data: [PersonVOInput]) {
|
|
45319
|
-
data: savePersons(persons: $data) {
|
|
45320
|
-
...PersonFragment
|
|
45321
|
-
}
|
|
45322
|
-
}
|
|
45323
|
-
${PersonFragments.person}
|
|
45324
|
-
`,
|
|
45325
|
-
deleteAll: gql$1 `
|
|
45326
|
-
mutation deletePersons($ids: [Int]) {
|
|
45327
|
-
deletePersons(ids: $ids)
|
|
45328
|
-
}
|
|
45329
|
-
`,
|
|
45330
|
-
};
|
|
45331
|
-
class PersonService extends BaseEntityService {
|
|
45332
|
-
graphql;
|
|
45333
|
-
platform;
|
|
45334
|
-
network;
|
|
45335
|
-
entities;
|
|
45336
|
-
constructor(graphql, platform, network, entities) {
|
|
45337
|
-
super(graphql, platform, Person, PersonFilter, {
|
|
45338
|
-
queries: PersonQueries,
|
|
45339
|
-
mutations: PersonMutations,
|
|
45340
|
-
defaultSortBy: 'lastName',
|
|
45341
|
-
defaultSortDirection: 'asc',
|
|
45342
|
-
});
|
|
45343
|
-
this.graphql = graphql;
|
|
45344
|
-
this.platform = platform;
|
|
45345
|
-
this.network = network;
|
|
45346
|
-
this.entities = entities;
|
|
45347
|
-
// for DEV only -----
|
|
45348
|
-
this._debug = !environment.production;
|
|
45349
|
-
}
|
|
45350
|
-
async loadAll(offset, size, sortBy, sortDirection, filter, opts) {
|
|
45351
|
-
const offline = this.network.offline && (!opts || opts.fetchPolicy !== 'network-only');
|
|
45352
|
-
if (offline) {
|
|
45353
|
-
return this.loadAllLocally(offset, size, sortBy, sortDirection, filter, opts);
|
|
45354
|
-
}
|
|
45355
|
-
return super.loadAll(offset, size, sortBy, sortDirection, filter, opts);
|
|
45356
|
-
}
|
|
45357
|
-
async loadAllLocally(offset, size, sortBy, sortDirection, filter, opts) {
|
|
45358
|
-
filter = this.asFilter(filter);
|
|
45359
|
-
const variables = {
|
|
45360
|
-
offset: offset || 0,
|
|
45361
|
-
size: size || 100,
|
|
45362
|
-
sortBy: sortBy || this.defaultSortBy,
|
|
45363
|
-
sortDirection: sortDirection || this.defaultSortDirection,
|
|
45364
|
-
filter: filter && filter.asFilterFn(),
|
|
45365
|
-
};
|
|
45366
|
-
const { data, total } = await this.entities.loadAll('PersonVO', variables);
|
|
45367
|
-
const entities = this.fromObjects(data, opts);
|
|
45368
|
-
const res = { data: entities, total };
|
|
45369
|
-
// Add fetch more function
|
|
45370
|
-
const nextOffset = (offset || 0) + entities.length;
|
|
45371
|
-
if (nextOffset < total) {
|
|
45372
|
-
res.fetchMore = () => this.loadAllLocally(nextOffset, size, sortBy, sortDirection, filter, opts);
|
|
45373
|
-
}
|
|
45374
|
-
return res;
|
|
45375
|
-
}
|
|
45376
|
-
async suggest(value, filter, sortBy, sortDirection, opts) {
|
|
45377
|
-
if (EntityUtils.isNotEmpty(value, 'id'))
|
|
45378
|
-
return { data: [value] };
|
|
45379
|
-
value = (typeof value === 'string' && value !== '*' && value) || undefined;
|
|
45380
|
-
sortBy = sortBy || filter.searchAttribute || (filter.searchAttributes && filter.searchAttributes[0]);
|
|
45381
|
-
return this.loadAll(0, !value ? 30 : 10, sortBy, sortDirection, {
|
|
45382
|
-
...filter,
|
|
45383
|
-
searchText: value,
|
|
45384
|
-
statusIds: (filter && filter.statusIds) || [StatusIds.ENABLE, StatusIds.TEMPORARY],
|
|
45385
|
-
userProfiles: filter && filter.userProfiles,
|
|
45386
|
-
}, {
|
|
45387
|
-
withTotal: true /* need by autocomplete */,
|
|
45388
|
-
...opts,
|
|
45389
|
-
});
|
|
45390
|
-
}
|
|
45391
|
-
async executeImport(filter, opts) {
|
|
45392
|
-
const maxProgression = (opts && opts.maxProgression) || 100;
|
|
45393
|
-
filter = {
|
|
45394
|
-
...filter,
|
|
45395
|
-
statusIds: [StatusIds.ENABLE, StatusIds.TEMPORARY],
|
|
45396
|
-
userProfiles: ['SUPERVISOR', 'USER', 'GUEST'],
|
|
45397
|
-
};
|
|
45398
|
-
console.info('[person-service] Importing persons...');
|
|
45399
|
-
const res = await JobUtils.fetchAllPages((offset, size) => this.loadAll(offset, size, 'id', null, filter, {
|
|
45400
|
-
debug: false,
|
|
45401
|
-
fetchPolicy: 'network-only',
|
|
45402
|
-
withTotal: offset === 0, // Compute total only once
|
|
45403
|
-
toEntity: false,
|
|
45404
|
-
}), { progression: opts?.progression, maxProgression: maxProgression * 0.9 });
|
|
45405
|
-
// Save result locally
|
|
45406
|
-
await this.entities.saveAll(res.data, { entityName: 'PersonVO', reset: true });
|
|
45407
|
-
}
|
|
45408
|
-
async loadById(id, opts) {
|
|
45409
|
-
const { data } = await this.loadAll(0, 1, null, null, { includedIds: [id] }, { withTotal: false, ...opts });
|
|
45410
|
-
const source = isNotEmptyArray(data) ? data[0] : { id };
|
|
45411
|
-
return this.fromObject(source, opts);
|
|
45412
|
-
}
|
|
45413
|
-
async loadByPubkey(pubkey, opts) {
|
|
45414
|
-
const { data } = await this.loadAll(0, 1, null, null, { pubkey }, { withTotal: false, ...opts });
|
|
45415
|
-
const source = isNotEmptyArray(data) ? data[0] : { pubkey };
|
|
45416
|
-
return this.fromObject(source, opts);
|
|
45417
|
-
}
|
|
45418
|
-
/* -- protected methods -- */
|
|
45419
|
-
asObject(source) {
|
|
45420
|
-
if (!source)
|
|
45421
|
-
return undefined;
|
|
45422
|
-
if (!(source instanceof Person)) {
|
|
45423
|
-
source = Person.fromObject(source);
|
|
45424
|
-
}
|
|
45425
|
-
const target = source.asObject();
|
|
45426
|
-
// Not known in server GraphQL schema
|
|
45427
|
-
delete target.mainProfile;
|
|
45428
|
-
target.department = source.department?.asObject();
|
|
45429
|
-
return target;
|
|
45430
|
-
}
|
|
45431
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PersonService, deps: [{ token: GraphqlService }, { token: PlatformService }, { token: NetworkService }, { token: EntitiesStorage }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
45432
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PersonService, providedIn: 'root' });
|
|
45433
|
-
}
|
|
45434
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: PersonService, decorators: [{
|
|
45435
|
-
type: Injectable,
|
|
45436
|
-
args: [{ providedIn: 'root' }]
|
|
45437
|
-
}], ctorParameters: () => [{ type: GraphqlService }, { type: PlatformService }, { type: NetworkService }, { type: EntitiesStorage }] });
|
|
45438
|
-
|
|
45439
45792
|
class UsersPage extends AppTable {
|
|
45440
45793
|
accountService;
|
|
45441
45794
|
validatorService;
|
|
@@ -50037,11 +50390,11 @@ class FeedTestingPage {
|
|
|
50037
50390
|
this.cd.markForCheck();
|
|
50038
50391
|
}
|
|
50039
50392
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FeedTestingPage, deps: [{ token: LocalSettingsService }, { token: i0.ChangeDetectorRef }, { token: ENVIRONMENT, optional: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
50040
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: FeedTestingPage, selector: "app-feed-test", ngImport: i0, template: "<ion-header>\n <ion-toolbar color=\"primary\">\n <ion-buttons slot=\"start\">\n <ion-back-button></ion-back-button>\n </ion-buttons>\n\n <ion-title>Feed test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n <ion-grid class=\"form-container ion-padding-top\">\n <ion-row>\n <ion-col size=\"12\">\n <mat-form-field [subscriptSizing]=\"'dynamic'\">\n <mat-label>Feed URL(s)</mat-label>\n <mat-select [(value)]=\"feedUrls\" multiple>\n <mat-option *ngFor=\"let feedUrl of availableFeedUrls\" [value]=\"feedUrl\">\n {{ feedUrl }}\n </mat-option>\n <mat-option>(Use environment)</mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"3\">\n <mat-form-field [subscriptSizing]=\"'dynamic'\">\n <mat-label>Header color</mat-label>\n <mat-select [(value)]=\"headerColor\">\n <mat-option *ngFor=\"let color of availableColors\" [value]=\"color\">\n {{ color }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"3\">\n <mat-form-field [subscriptSizing]=\"'dynamic'\">\n <mat-label>Card color</mat-label>\n <mat-select [(value)]=\"cardColor\">\n <mat-option *ngFor=\"let color of availableColors\" [value]=\"color\">\n {{ color }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"3\">\n <mat-form-field [subscriptSizing]=\"'dynamic'\">\n <mat-label>Shape</mat-label>\n <mat-select [(value)]=\"shape\">\n <mat-option *ngFor=\"let shape of availableShapes\" [value]=\"shape\">\n {{ shape }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"3\">\n <mat-checkbox (change)=\"debug = $event.checked\" [checked]=\"debug\">Debug ?</mat-checkbox>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <div class=\"ion-padding\">\n <app-feed\n [
|
|
50393
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: FeedTestingPage, selector: "app-feed-test", ngImport: i0, template: "<ion-header>\n <ion-toolbar color=\"primary\">\n <ion-buttons slot=\"start\">\n <ion-back-button></ion-back-button>\n </ion-buttons>\n\n <ion-title>Feed test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n <ion-grid class=\"form-container ion-padding-top\">\n <ion-row>\n <ion-col size=\"12\">\n <mat-form-field [subscriptSizing]=\"'dynamic'\">\n <mat-label>Feed URL(s)</mat-label>\n <mat-select [(value)]=\"feedUrls\" multiple>\n <mat-option *ngFor=\"let feedUrl of availableFeedUrls\" [value]=\"feedUrl\">\n {{ feedUrl }}\n </mat-option>\n <mat-option>(Use environment)</mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"3\">\n <mat-form-field [subscriptSizing]=\"'dynamic'\">\n <mat-label>Header color</mat-label>\n <mat-select [(value)]=\"headerColor\">\n <mat-option *ngFor=\"let color of availableColors\" [value]=\"color\">\n {{ color }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"3\">\n <mat-form-field [subscriptSizing]=\"'dynamic'\">\n <mat-label>Card color</mat-label>\n <mat-select [(value)]=\"cardColor\">\n <mat-option *ngFor=\"let color of availableColors\" [value]=\"color\">\n {{ color }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"3\">\n <mat-form-field [subscriptSizing]=\"'dynamic'\">\n <mat-label>Shape</mat-label>\n <mat-select [(value)]=\"shape\">\n <mat-option *ngFor=\"let shape of availableShapes\" [value]=\"shape\">\n {{ shape }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"3\">\n <mat-checkbox (change)=\"debug = $event.checked\" [checked]=\"debug\">Debug ?</mat-checkbox>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <div class=\"ion-padding\">\n <app-feed\n [urls]=\"feedUrls\"\n [headerColor]=\"headerColor\"\n [cardColor]=\"cardColor\"\n [shape]=\"shape\"\n [debug]=\"debug\"\n ></app-feed>\n </div>\n</ion-content>\n", dependencies: [{ kind: "directive", type: i3$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: i2$1.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i2$1.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i2$1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2$1.IonGrid, selector: "ion-grid", inputs: ["fixed"] }, { kind: "component", type: i2$1.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2$1.IonRow, selector: "ion-row" }, { kind: "component", type: i2$1.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: i2$1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: i2$1.IonBackButton, selector: "ion-back-button" }, { 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: "component", type: i5.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { 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: FeedsComponent, selector: "app-feed", inputs: ["debug", "mobile", "showHeader", "showReadMoreButton", "headerColor", "cardColor", "shape", "class", "itemId", "filterItem", "feeds", "urls", "maxAgeInMonths", "maxContentLength"], outputs: ["editItem", "deleteItem"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
50041
50394
|
}
|
|
50042
50395
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FeedTestingPage, decorators: [{
|
|
50043
50396
|
type: Component,
|
|
50044
|
-
args: [{ selector: 'app-feed-test', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ion-header>\n <ion-toolbar color=\"primary\">\n <ion-buttons slot=\"start\">\n <ion-back-button></ion-back-button>\n </ion-buttons>\n\n <ion-title>Feed test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n <ion-grid class=\"form-container ion-padding-top\">\n <ion-row>\n <ion-col size=\"12\">\n <mat-form-field [subscriptSizing]=\"'dynamic'\">\n <mat-label>Feed URL(s)</mat-label>\n <mat-select [(value)]=\"feedUrls\" multiple>\n <mat-option *ngFor=\"let feedUrl of availableFeedUrls\" [value]=\"feedUrl\">\n {{ feedUrl }}\n </mat-option>\n <mat-option>(Use environment)</mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"3\">\n <mat-form-field [subscriptSizing]=\"'dynamic'\">\n <mat-label>Header color</mat-label>\n <mat-select [(value)]=\"headerColor\">\n <mat-option *ngFor=\"let color of availableColors\" [value]=\"color\">\n {{ color }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"3\">\n <mat-form-field [subscriptSizing]=\"'dynamic'\">\n <mat-label>Card color</mat-label>\n <mat-select [(value)]=\"cardColor\">\n <mat-option *ngFor=\"let color of availableColors\" [value]=\"color\">\n {{ color }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"3\">\n <mat-form-field [subscriptSizing]=\"'dynamic'\">\n <mat-label>Shape</mat-label>\n <mat-select [(value)]=\"shape\">\n <mat-option *ngFor=\"let shape of availableShapes\" [value]=\"shape\">\n {{ shape }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"3\">\n <mat-checkbox (change)=\"debug = $event.checked\" [checked]=\"debug\">Debug ?</mat-checkbox>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <div class=\"ion-padding\">\n <app-feed\n [
|
|
50397
|
+
args: [{ selector: 'app-feed-test', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ion-header>\n <ion-toolbar color=\"primary\">\n <ion-buttons slot=\"start\">\n <ion-back-button></ion-back-button>\n </ion-buttons>\n\n <ion-title>Feed test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n <ion-grid class=\"form-container ion-padding-top\">\n <ion-row>\n <ion-col size=\"12\">\n <mat-form-field [subscriptSizing]=\"'dynamic'\">\n <mat-label>Feed URL(s)</mat-label>\n <mat-select [(value)]=\"feedUrls\" multiple>\n <mat-option *ngFor=\"let feedUrl of availableFeedUrls\" [value]=\"feedUrl\">\n {{ feedUrl }}\n </mat-option>\n <mat-option>(Use environment)</mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"3\">\n <mat-form-field [subscriptSizing]=\"'dynamic'\">\n <mat-label>Header color</mat-label>\n <mat-select [(value)]=\"headerColor\">\n <mat-option *ngFor=\"let color of availableColors\" [value]=\"color\">\n {{ color }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"3\">\n <mat-form-field [subscriptSizing]=\"'dynamic'\">\n <mat-label>Card color</mat-label>\n <mat-select [(value)]=\"cardColor\">\n <mat-option *ngFor=\"let color of availableColors\" [value]=\"color\">\n {{ color }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"3\">\n <mat-form-field [subscriptSizing]=\"'dynamic'\">\n <mat-label>Shape</mat-label>\n <mat-select [(value)]=\"shape\">\n <mat-option *ngFor=\"let shape of availableShapes\" [value]=\"shape\">\n {{ shape }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"3\">\n <mat-checkbox (change)=\"debug = $event.checked\" [checked]=\"debug\">Debug ?</mat-checkbox>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <div class=\"ion-padding\">\n <app-feed\n [urls]=\"feedUrls\"\n [headerColor]=\"headerColor\"\n [cardColor]=\"cardColor\"\n [shape]=\"shape\"\n [debug]=\"debug\"\n ></app-feed>\n </div>\n</ion-content>\n" }]
|
|
50045
50398
|
}], ctorParameters: () => [{ type: LocalSettingsService }, { type: i0.ChangeDetectorRef }, { type: Environment, decorators: [{
|
|
50046
50399
|
type: Optional
|
|
50047
50400
|
}, {
|
|
@@ -50085,6 +50438,11 @@ const routes = [
|
|
|
50085
50438
|
pathMatch: 'full',
|
|
50086
50439
|
component: FeedTestingPage,
|
|
50087
50440
|
},
|
|
50441
|
+
{
|
|
50442
|
+
path: 'feed/page',
|
|
50443
|
+
pathMatch: 'full',
|
|
50444
|
+
component: FeedPage,
|
|
50445
|
+
},
|
|
50088
50446
|
];
|
|
50089
50447
|
class SocialTestingModule {
|
|
50090
50448
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SocialTestingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
@@ -50151,5 +50509,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
|
|
|
50151
50509
|
* Generated bundle index. Do not edit.
|
|
50152
50510
|
*/
|
|
50153
50511
|
|
|
50154
|
-
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, ArrayMapPipe, 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, MapToPipe, 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, TruncateHtmlPipe, 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, base64ArrayBuffer, 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, truncateHtml, uncapitalizeFirstLetter, undefinedIfNull, underscoreToChangeCase, updateValueAndValidity, waitFor, waitForFalse, waitForTrue, waitIdle, waitWhilePending };
|
|
50512
|
+
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, ArrayMapPipe, 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, FeedPage, 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, MapToPipe, 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, TruncateHtmlPipe, 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, base64ArrayBuffer, 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, truncateHtml, uncapitalizeFirstLetter, undefinedIfNull, underscoreToChangeCase, updateValueAndValidity, waitFor, waitForFalse, waitForTrue, waitIdle, waitWhilePending };
|
|
50155
50513
|
//# sourceMappingURL=sumaris-net.ngx-components.mjs.map
|