ngx-edu-sharing-ui 0.7.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/.browserslistrc +16 -0
- package/.eslintrc.json +44 -0
- package/README.md +40 -0
- package/assets/scss/mixins.scss +95 -0
- package/assets/scss/variables.scss +33 -0
- package/karma.conf.js +42 -0
- package/ng-package.json +10 -0
- package/package.json +19 -0
- package/src/lib/actionbar/actionbar.component.html +59 -0
- package/src/lib/actionbar/actionbar.component.scss +123 -0
- package/src/lib/actionbar/actionbar.component.ts +174 -0
- package/src/lib/common/edu-sharing-ui-common.module.ts +80 -0
- package/src/lib/directives/border-box-observer.directive.ts +75 -0
- package/src/lib/directives/check-text-overflow.directive.ts +61 -0
- package/src/lib/directives/drag-nodes/drag-nodes.ts +32 -0
- package/src/lib/directives/drag-nodes/nodes-drag-source.directive.ts +79 -0
- package/src/lib/directives/drag-nodes/nodes-drag.directive.ts +43 -0
- package/src/lib/directives/drag-nodes/nodes-drop-target.directive.ts +116 -0
- package/src/lib/directives/focus-state.directive.ts +34 -0
- package/src/lib/directives/icon.directive.ts +142 -0
- package/src/lib/directives/nodes-drop-target-legacy.directive.ts +155 -0
- package/src/lib/dropdown/dropdown.component.html +32 -0
- package/src/lib/dropdown/dropdown.component.scss +67 -0
- package/src/lib/dropdown/dropdown.component.ts +71 -0
- package/src/lib/edu-sharing-ui-configuration.ts +47 -0
- package/src/lib/edu-sharing-ui.module.ts +49 -0
- package/src/lib/list-items/available-widgets.ts +30 -0
- package/src/lib/list-items/format-duration.pipe.ts +17 -0
- package/src/lib/list-items/list-base/list-base.component.html +52 -0
- package/src/lib/list-items/list-base/list-base.component.ts +44 -0
- package/src/lib/list-items/list-collection-info/list-collection-info.component.html +48 -0
- package/src/lib/list-items/list-collection-info/list-collection-info.component.scss +8 -0
- package/src/lib/list-items/list-collection-info/list-collection-info.component.ts +24 -0
- package/src/lib/list-items/list-counts/list-counts.component.html +1 -0
- package/src/lib/list-items/list-counts/list-counts.component.scss +3 -0
- package/src/lib/list-items/list-counts/list-counts.component.ts +59 -0
- package/src/lib/list-items/list-items.module.ts +33 -0
- package/src/lib/list-items/list-node-license/list-node-license.component.html +8 -0
- package/src/lib/list-items/list-node-license/list-node-license.component.ts +47 -0
- package/src/lib/list-items/list-node-replication-source/list-node-replication-source.component.html +11 -0
- package/src/lib/list-items/list-node-replication-source/list-node-replication-source.component.ts +60 -0
- package/src/lib/list-items/list-node-workflow/list-node-workflow.component.html +3 -0
- package/src/lib/list-items/list-node-workflow/list-node-workflow.component.ts +21 -0
- package/src/lib/list-items/list-text/list-text.component.html +176 -0
- package/src/lib/list-items/list-text/list-text.component.scss +3 -0
- package/src/lib/list-items/list-text/list-text.component.ts +107 -0
- package/src/lib/list-items/list-widget.ts +52 -0
- package/src/lib/list-items/node-row/node-row.component.html +31 -0
- package/src/lib/list-items/node-row/node-row.component.scss +50 -0
- package/src/lib/list-items/node-row/node-row.component.ts +16 -0
- package/src/lib/list-items/node-source.pipe.ts +48 -0
- package/src/lib/node-entries/combined-data-source.ts +51 -0
- package/src/lib/node-entries/custom-templates-data-source.ts +6 -0
- package/src/lib/node-entries/drag-preview/drag-preview.component.html +6 -0
- package/src/lib/node-entries/drag-preview/drag-preview.component.scss +35 -0
- package/src/lib/node-entries/drag-preview/drag-preview.component.ts +15 -0
- package/src/lib/node-entries/entries-model.ts +120 -0
- package/src/lib/node-entries/items-cap.ts +54 -0
- package/src/lib/node-entries/list-item-label.pipe.ts +28 -0
- package/src/lib/node-entries/mixins.scss +23 -0
- package/src/lib/node-entries/node-cache.spec.ts +199 -0
- package/src/lib/node-entries/node-cache.ts +81 -0
- package/src/lib/node-entries/node-data-source-remote.ts +33 -0
- package/src/lib/node-entries/node-data-source.ts +148 -0
- package/src/lib/node-entries/node-entries-card/node-entries-card.component.html +167 -0
- package/src/lib/node-entries/node-entries-card/node-entries-card.component.scss +28 -0
- package/src/lib/node-entries/node-entries-card/node-entries-card.component.ts +132 -0
- package/src/lib/node-entries/node-entries-card/node-entries-card.main.scss +261 -0
- package/src/lib/node-entries/node-entries-card-grid/node-entries-card-grid.component.html +205 -0
- package/src/lib/node-entries/node-entries-card-grid/node-entries-card-grid.component.scss +181 -0
- package/src/lib/node-entries/node-entries-card-grid/node-entries-card-grid.component.ts +361 -0
- package/src/lib/node-entries/node-entries-card-small/node-entries-card-small.component.html +100 -0
- package/src/lib/node-entries/node-entries-card-small/node-entries-card-small.component.scss +46 -0
- package/src/lib/node-entries/node-entries-card-small/node-entries-card-small.component.ts +40 -0
- package/src/lib/node-entries/node-entries-global-options/node-entries-global-options.component.html +23 -0
- package/src/lib/node-entries/node-entries-global-options/node-entries-global-options.component.scss +58 -0
- package/src/lib/node-entries/node-entries-global-options/node-entries-global-options.component.ts +16 -0
- package/src/lib/node-entries/node-entries-global.service.ts +79 -0
- package/src/lib/node-entries/node-entries-table/column-chooser/column-chooser.component.html +25 -0
- package/src/lib/node-entries/node-entries-table/column-chooser/column-chooser.component.scss +32 -0
- package/src/lib/node-entries/node-entries-table/column-chooser/column-chooser.component.ts +31 -0
- package/src/lib/node-entries/node-entries-table/node-entries-table.component.html +270 -0
- package/src/lib/node-entries/node-entries-table/node-entries-table.component.scss +169 -0
- package/src/lib/node-entries/node-entries-table/node-entries-table.component.ts +333 -0
- package/src/lib/node-entries/node-entries-templates.service.ts +31 -0
- package/src/lib/node-entries/node-entries-wrapper.component.ts +363 -0
- package/src/lib/node-entries/node-entries.component.html +33 -0
- package/src/lib/node-entries/node-entries.component.scss +13 -0
- package/src/lib/node-entries/node-entries.component.ts +151 -0
- package/src/lib/node-entries/node-entries.module.ts +93 -0
- package/src/lib/node-entries/node-rating/node-rating.component.html +53 -0
- package/src/lib/node-entries/node-rating/node-rating.component.scss +31 -0
- package/src/lib/node-entries/node-rating/node-rating.component.ts +105 -0
- package/src/lib/node-entries/node-stats-badges/node-stats-badges.component.html +39 -0
- package/src/lib/node-entries/node-stats-badges/node-stats-badges.component.scss +44 -0
- package/src/lib/node-entries/node-stats-badges/node-stats-badges.component.ts +43 -0
- package/src/lib/node-entries/node-type-badge/node-type-badge.component.html +31 -0
- package/src/lib/node-entries/node-type-badge/node-type-badge.component.scss +5 -0
- package/src/lib/node-entries/node-type-badge/node-type-badge.component.ts +36 -0
- package/src/lib/node-entries/option-button/option-button.component.ts +42 -0
- package/src/lib/node-entries/preview-image/preview-image.component.html +19 -0
- package/src/lib/node-entries/preview-image/preview-image.component.scss +31 -0
- package/src/lib/node-entries/preview-image/preview-image.component.ts +47 -0
- package/src/lib/node-entries/sort-select-panel/sort-select-panel.component.html +27 -0
- package/src/lib/node-entries/sort-select-panel/sort-select-panel.component.scss +9 -0
- package/src/lib/node-entries/sort-select-panel/sort-select-panel.component.ts +26 -0
- package/src/lib/node-url/node-url.component.html +66 -0
- package/src/lib/node-url/node-url.component.scss +32 -0
- package/src/lib/node-url/node-url.component.ts +136 -0
- package/src/lib/pipes/file-size.pipe.ts +24 -0
- package/src/lib/pipes/format-date.pipe.ts +39 -0
- package/src/lib/pipes/node-icon.pipe.ts +11 -0
- package/src/lib/pipes/node-image-size.pipe.ts +18 -0
- package/src/lib/pipes/node-image.pipe.ts +71 -0
- package/src/lib/pipes/node-person-name.pipe.ts +41 -0
- package/src/lib/pipes/node-title.pipe.ts +12 -0
- package/src/lib/pipes/option-tooltip.pipe.ts +32 -0
- package/src/lib/pipes/replace-chars.pipe.ts +21 -0
- package/src/lib/pipes/vcard-name.pipe.ts +11 -0
- package/src/lib/services/abstract/app.service.ts +4 -0
- package/src/lib/services/abstract/keyboard-shortcuts.service.ts +10 -0
- package/src/lib/services/abstract/options-helper.service.ts +29 -0
- package/src/lib/services/abstract/toast.service.ts +5 -0
- package/src/lib/services/accessibility.service.ts +101 -0
- package/src/lib/services/local-events.service.ts +29 -0
- package/src/lib/services/node-entries.service.ts +172 -0
- package/src/lib/services/node-helper.service.ts +239 -0
- package/src/lib/services/nodes-drag-drop.service.ts +165 -0
- package/src/lib/services/options-helper-data.service.ts +186 -0
- package/src/lib/services/repo-url.service.ts +46 -0
- package/src/lib/services/temporary-storage.service.ts +58 -0
- package/src/lib/services/ui.service.ts +182 -0
- package/src/lib/sort-dropdown/sort-dropdown.component.html +22 -0
- package/src/lib/sort-dropdown/sort-dropdown.component.scss +47 -0
- package/src/lib/sort-dropdown/sort-dropdown.component.ts +42 -0
- package/src/lib/spinner/spinner.component.html +14 -0
- package/src/lib/spinner/spinner.component.scss +141 -0
- package/src/lib/spinner/spinner.component.ts +12 -0
- package/src/lib/translations/README.md +44 -0
- package/src/lib/translations/fallback-translation-handler.ts +7 -0
- package/src/lib/translations/languages.ts +6 -0
- package/src/lib/translations/translation-loader.spec.ts +352 -0
- package/src/lib/translations/translation-loader.ts +189 -0
- package/src/lib/translations/translation-source.ts +9 -0
- package/src/lib/translations/translations.module.ts +49 -0
- package/src/lib/translations/translations.service.spec.ts +152 -0
- package/src/lib/translations/translations.service.ts +188 -0
- package/src/lib/types/accessibillity.ts +15 -0
- package/src/lib/types/api-models.ts +4 -0
- package/src/lib/types/drag-drop.ts +22 -0
- package/src/lib/types/keyboard-shortcuts.ts +29 -0
- package/src/lib/types/list-item.ts +67 -0
- package/src/lib/types/option-item.ts +247 -0
- package/src/lib/types/workflow.ts +35 -0
- package/src/lib/util/DateHelper.spec.ts +112 -0
- package/src/lib/util/DateHelper.ts +197 -0
- package/src/lib/util/VCard.ts +277 -0
- package/src/lib/util/color-helper.ts +125 -0
- package/src/lib/util/duration-helper.spec.ts +35 -0
- package/src/lib/util/duration-helper.ts +98 -0
- package/src/lib/util/functions.ts +15 -0
- package/src/lib/util/helper.ts +60 -0
- package/src/lib/util/isNumeric.ts +13 -0
- package/src/lib/util/rest-helper.ts +28 -0
- package/src/lib/util/ui-animation.ts +154 -0
- package/src/lib/util/ui-constants.ts +20 -0
- package/src/module.ts +76 -0
- package/src/test.ts +28 -0
- package/tsconfig.lib.json +15 -0
- package/tsconfig.lib.prod.json +10 -0
- package/tsconfig.spec.json +17 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Created by Torsten on 28.02.2017.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export class VCard {
|
|
6
|
+
public static TYPE_PERSON = 0;
|
|
7
|
+
public static TYPE_ORG = 1;
|
|
8
|
+
// was the vcard altered
|
|
9
|
+
private isDirty = false;
|
|
10
|
+
private lines: string[];
|
|
11
|
+
constructor(vcard: string = null) {
|
|
12
|
+
if (vcard) {
|
|
13
|
+
this.lines = vcard.split('\n');
|
|
14
|
+
// this.remove("FN");
|
|
15
|
+
if (!this.get('BEGIN')) {
|
|
16
|
+
this.lines.splice(0, 0, 'BEGIN:VCARD');
|
|
17
|
+
}
|
|
18
|
+
if (!this.get('VERSION')) {
|
|
19
|
+
this.lines.splice(1, 0, 'VERSION:3.0');
|
|
20
|
+
}
|
|
21
|
+
if (!this.get('END')) {
|
|
22
|
+
this.lines.splice(this.lines.length, 0, 'END:VCARD');
|
|
23
|
+
}
|
|
24
|
+
this.isDirty = true;
|
|
25
|
+
} else {
|
|
26
|
+
this.lines = [];
|
|
27
|
+
this.lines.push('BEGIN:VCARD');
|
|
28
|
+
this.lines.push('VERSION:3.0');
|
|
29
|
+
this.lines.push('END:VCARD');
|
|
30
|
+
this.isDirty = false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* returns true if this vcard seems to have valid data
|
|
36
|
+
* @param {string} data
|
|
37
|
+
*/
|
|
38
|
+
public isValid() {
|
|
39
|
+
// return this.lines!=null && this.lines.length;
|
|
40
|
+
return (
|
|
41
|
+
this.givenname ||
|
|
42
|
+
this.surname ||
|
|
43
|
+
this.org ||
|
|
44
|
+
this.street ||
|
|
45
|
+
this.city ||
|
|
46
|
+
this.zip ||
|
|
47
|
+
this.country
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
public set givenname(data: string) {
|
|
51
|
+
this.set('Givenname', data);
|
|
52
|
+
}
|
|
53
|
+
public set surname(data: string) {
|
|
54
|
+
this.set('Surname', data);
|
|
55
|
+
}
|
|
56
|
+
public set title(data: string) {
|
|
57
|
+
this.set('TITLE', data);
|
|
58
|
+
}
|
|
59
|
+
public set org(data: string) {
|
|
60
|
+
this.set('ORG', data);
|
|
61
|
+
}
|
|
62
|
+
public set orgPhone(data: string) {
|
|
63
|
+
this.set('TEL;TYPE=WORK,VOICE', data);
|
|
64
|
+
}
|
|
65
|
+
public set url(data: string) {
|
|
66
|
+
this.set('URL', data);
|
|
67
|
+
}
|
|
68
|
+
public set email(data: string) {
|
|
69
|
+
this.set('EMAIL;TYPE=PREF,INTERNET', data);
|
|
70
|
+
}
|
|
71
|
+
public set uid(data: string) {
|
|
72
|
+
this.set('UID:urn:uuid', data);
|
|
73
|
+
}
|
|
74
|
+
public set orcid(data: string) {
|
|
75
|
+
this.set('X-ORCID', data);
|
|
76
|
+
}
|
|
77
|
+
public set gnduri(data: string) {
|
|
78
|
+
this.set('X-GND-URI', data);
|
|
79
|
+
}
|
|
80
|
+
public set ror(data: string) {
|
|
81
|
+
this.set('X-ROR', data);
|
|
82
|
+
}
|
|
83
|
+
public set wikidata(data: string) {
|
|
84
|
+
this.set('X-Wikidata', data);
|
|
85
|
+
}
|
|
86
|
+
public set street(data: string) {
|
|
87
|
+
this.set('ADR;TYPE=intl,postal,parcel,work', data, 2);
|
|
88
|
+
}
|
|
89
|
+
public set city(data: string) {
|
|
90
|
+
this.set('ADR;TYPE=intl,postal,parcel,work', data, 3);
|
|
91
|
+
}
|
|
92
|
+
public set region(data: string) {
|
|
93
|
+
this.set('ADR;TYPE=intl,postal,parcel,work', data, 4);
|
|
94
|
+
}
|
|
95
|
+
public set zip(data: string) {
|
|
96
|
+
this.set('ADR;TYPE=intl,postal,parcel,work', data, 5);
|
|
97
|
+
}
|
|
98
|
+
public set country(data: string) {
|
|
99
|
+
this.set('ADR;TYPE=intl,postal,parcel,work', data, 6);
|
|
100
|
+
}
|
|
101
|
+
public set contributeDate(data: string) {
|
|
102
|
+
this.set('X-ES-LOM-CONTRIBUTE-DATE', data);
|
|
103
|
+
}
|
|
104
|
+
public get givenname() {
|
|
105
|
+
return this.get('Givenname');
|
|
106
|
+
}
|
|
107
|
+
public get surname() {
|
|
108
|
+
return this.get('Surname');
|
|
109
|
+
}
|
|
110
|
+
public get orcid() {
|
|
111
|
+
return this.get('X-ORCID');
|
|
112
|
+
}
|
|
113
|
+
public get gnduri() {
|
|
114
|
+
return this.get('X-GND-URI');
|
|
115
|
+
}
|
|
116
|
+
public get ror() {
|
|
117
|
+
return this.get('X-ROR');
|
|
118
|
+
}
|
|
119
|
+
public get wikidata() {
|
|
120
|
+
return this.get('X-Wikidata');
|
|
121
|
+
}
|
|
122
|
+
public get title() {
|
|
123
|
+
return this.get('TITLE');
|
|
124
|
+
}
|
|
125
|
+
public get org() {
|
|
126
|
+
return this.get('ORG');
|
|
127
|
+
}
|
|
128
|
+
public get contributeDate() {
|
|
129
|
+
const string = this.get('X-ES-LOM-CONTRIBUTE-DATE');
|
|
130
|
+
if (string) return string.split('T')[0];
|
|
131
|
+
return string;
|
|
132
|
+
}
|
|
133
|
+
public get url() {
|
|
134
|
+
return this.get('URL');
|
|
135
|
+
}
|
|
136
|
+
public get orgPhone() {
|
|
137
|
+
return this.get('TEL;TYPE=WORK,VOICE');
|
|
138
|
+
}
|
|
139
|
+
public get email() {
|
|
140
|
+
return this.get('EMAIL;TYPE=PREF,INTERNET');
|
|
141
|
+
}
|
|
142
|
+
public get uid() {
|
|
143
|
+
return this.get('UID:urn:uuid');
|
|
144
|
+
}
|
|
145
|
+
public get street() {
|
|
146
|
+
return this.get('ADR;TYPE=intl,postal,parcel,work', 2);
|
|
147
|
+
}
|
|
148
|
+
public get city() {
|
|
149
|
+
return this.get('ADR;TYPE=intl,postal,parcel,work', 3);
|
|
150
|
+
}
|
|
151
|
+
public get region() {
|
|
152
|
+
return this.get('ADR;TYPE=intl,postal,parcel,work', 4);
|
|
153
|
+
}
|
|
154
|
+
public get zip() {
|
|
155
|
+
return this.get('ADR;TYPE=intl,postal,parcel,work', 5);
|
|
156
|
+
}
|
|
157
|
+
public get country() {
|
|
158
|
+
return this.get('ADR;TYPE=intl,postal,parcel,work', 6);
|
|
159
|
+
}
|
|
160
|
+
public toVCardString() {
|
|
161
|
+
// unaltered -> so return a null value
|
|
162
|
+
if (!this.isDirty) return null;
|
|
163
|
+
if (this.get('Givenname') || this.get('Surname'))
|
|
164
|
+
this.set('FN', this.get('Givenname', -1, '') + ' ' + this.get('Surname', -1, ''));
|
|
165
|
+
return this.lines.join('\n');
|
|
166
|
+
}
|
|
167
|
+
public getDisplayName() {
|
|
168
|
+
const string =
|
|
169
|
+
(this.title ?? '') + ' ' + (this.givenname ?? '') + ' ' + (this.surname ?? '');
|
|
170
|
+
if (string.trim() === '') {
|
|
171
|
+
return this.org || '';
|
|
172
|
+
}
|
|
173
|
+
return string;
|
|
174
|
+
}
|
|
175
|
+
public get(key: string, splitIndex = -1, fallback: string = null) {
|
|
176
|
+
if (key == 'Surname') {
|
|
177
|
+
splitIndex = 0;
|
|
178
|
+
key = 'N';
|
|
179
|
+
}
|
|
180
|
+
if (key == 'Givenname') {
|
|
181
|
+
splitIndex = 1;
|
|
182
|
+
key = 'N';
|
|
183
|
+
}
|
|
184
|
+
for (let line of this.lines) {
|
|
185
|
+
line = line.trim();
|
|
186
|
+
if (line.startsWith(key + ':')) {
|
|
187
|
+
const value = line.substring(key.length + 1).trim();
|
|
188
|
+
if (splitIndex != -1) return this.deEscape(value.split(';')[splitIndex]);
|
|
189
|
+
return this.deEscape(value);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return fallback;
|
|
193
|
+
}
|
|
194
|
+
public remove(key: string) {
|
|
195
|
+
for (let i = 0; i < this.lines.length; i++) {
|
|
196
|
+
if (this.lines[i].startsWith(key + ':')) {
|
|
197
|
+
this.lines.splice(i, 1);
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
public set(key: string, value: string, splitIndex = -1) {
|
|
204
|
+
// no value and empty vcard -> do nothing
|
|
205
|
+
if (!this.isDirty && !value) return;
|
|
206
|
+
if (key == 'Surname') {
|
|
207
|
+
splitIndex = 0;
|
|
208
|
+
key = 'N';
|
|
209
|
+
}
|
|
210
|
+
if (key == 'Givenname') {
|
|
211
|
+
splitIndex = 1;
|
|
212
|
+
key = 'N';
|
|
213
|
+
}
|
|
214
|
+
let i = 0;
|
|
215
|
+
for (let line of this.lines) {
|
|
216
|
+
line = line.trim();
|
|
217
|
+
if (line.startsWith(key + ':')) {
|
|
218
|
+
let lineValue = line.substring(key.length + 1).trim();
|
|
219
|
+
if (splitIndex != -1) {
|
|
220
|
+
const split = lineValue.split(';');
|
|
221
|
+
split[splitIndex] = this.escape(value);
|
|
222
|
+
lineValue = split.join(';');
|
|
223
|
+
} else {
|
|
224
|
+
lineValue = this.escape(value);
|
|
225
|
+
}
|
|
226
|
+
this.lines[i] = line.substring(0, key.length + 1) + lineValue;
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
i++;
|
|
230
|
+
}
|
|
231
|
+
let lineValue = this.escape(value);
|
|
232
|
+
if (splitIndex >= 0) {
|
|
233
|
+
lineValue = '';
|
|
234
|
+
while (lineValue.length < splitIndex) lineValue += ';';
|
|
235
|
+
lineValue += this.escape(value);
|
|
236
|
+
}
|
|
237
|
+
this.lines.splice(this.getNextLine(), 0, key + ':' + lineValue);
|
|
238
|
+
this.isDirty = true;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private getNextLine() {
|
|
242
|
+
let i = 0;
|
|
243
|
+
for (const line of this.lines) {
|
|
244
|
+
if (line.trim() == 'END:VCARD') return i - 1;
|
|
245
|
+
i++;
|
|
246
|
+
}
|
|
247
|
+
return this.lines.length - 1;
|
|
248
|
+
}
|
|
249
|
+
private deEscape(value: string) {
|
|
250
|
+
if (value == null) return '';
|
|
251
|
+
return value.replace(/\\\\/g, '\\').replace(/\\,/g, ',');
|
|
252
|
+
}
|
|
253
|
+
private escape(value: string) {
|
|
254
|
+
if (value == null) return '';
|
|
255
|
+
return value.replace(/\\/g, '\\\\').replace(/,/g, '\\,').replace(/;/g, ' ');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
public copy() {
|
|
259
|
+
return new VCard(this.toVCardString());
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Apply all data from an other vcard to this object
|
|
264
|
+
* @param other
|
|
265
|
+
*/
|
|
266
|
+
public apply(other: VCard) {
|
|
267
|
+
this.lines = other.lines;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
getType(): number {
|
|
271
|
+
return this.isValid()
|
|
272
|
+
? this.givenname || this.surname
|
|
273
|
+
? VCard.TYPE_PERSON
|
|
274
|
+
: VCard.TYPE_ORG
|
|
275
|
+
: VCard.TYPE_PERSON;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
export class ColorHelper {
|
|
2
|
+
public static cssColorToRgb(color: string): number[] {
|
|
3
|
+
color = color.trim();
|
|
4
|
+
if (color.startsWith('rgb')) {
|
|
5
|
+
let result = /rgb.?\(\s*([\d]*)\s*,\s*([\d]*)\s*,\s*([\d*]*)\s*/i.exec(color);
|
|
6
|
+
return result ? [parseInt(result[1]), parseInt(result[2]), parseInt(result[3])] : null;
|
|
7
|
+
}
|
|
8
|
+
let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color);
|
|
9
|
+
return result
|
|
10
|
+
? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)]
|
|
11
|
+
: null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* returns the estimated color brightness for a css color based on a pereceived brightness factor
|
|
16
|
+
* Value between [0,1] and -1 if the css string was not readable
|
|
17
|
+
* @param {string} color
|
|
18
|
+
* @returns {number}
|
|
19
|
+
*/
|
|
20
|
+
public static getColorBrightness(color: string) {
|
|
21
|
+
const rgb = ColorHelper.cssColorToRgb(color);
|
|
22
|
+
if (rgb) {
|
|
23
|
+
// return (rgb[0]*0.2126 + rgb[1]*0.7152 + rgb[2]*0.0722) / 255;
|
|
24
|
+
const a = rgb.map((v) => {
|
|
25
|
+
v /= 255;
|
|
26
|
+
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
27
|
+
});
|
|
28
|
+
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
|
|
29
|
+
}
|
|
30
|
+
return -1;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private static getRatio(l1: number, l2: number) {
|
|
34
|
+
// calculate the color contrast ratio
|
|
35
|
+
return l1 > l2 ? (l2 + 0.05) / (l1 + 0.05) : (l1 + 0.05) / (l2 + 0.05);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* returns 0 (black) or 1 (white)
|
|
39
|
+
* @param color
|
|
40
|
+
*/
|
|
41
|
+
public static getPreferredColor(color: string): PreferredColor {
|
|
42
|
+
if (!color) {
|
|
43
|
+
return PreferredColor.Black;
|
|
44
|
+
}
|
|
45
|
+
const brightness = ColorHelper.getColorBrightness(color);
|
|
46
|
+
const ratioBlack = ColorHelper.getRatio(0, brightness);
|
|
47
|
+
const ratioWhite = ColorHelper.getRatio(1, brightness);
|
|
48
|
+
return ratioBlack > ratioWhite ? PreferredColor.Black : PreferredColor.White;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public static rgbToHex(rgb: number[]): string {
|
|
52
|
+
return (
|
|
53
|
+
'#' +
|
|
54
|
+
ColorHelper.componentToHex(rgb[0]) +
|
|
55
|
+
ColorHelper.componentToHex(rgb[1]) +
|
|
56
|
+
ColorHelper.componentToHex(rgb[2])
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
public static componentToHex(c: number) {
|
|
60
|
+
var hex = Math.max(0, Math.min(Math.round(c), 255)).toString(16);
|
|
61
|
+
return hex.length == 1 ? '0' + hex : hex;
|
|
62
|
+
}
|
|
63
|
+
public static rgbToHsl(rgb: number[]) {
|
|
64
|
+
const r = rgb[0] / 255;
|
|
65
|
+
const g = rgb[1] / 255;
|
|
66
|
+
const b = rgb[2] / 255;
|
|
67
|
+
const max = Math.max(r, g, b);
|
|
68
|
+
const min = Math.min(r, g, b);
|
|
69
|
+
// tslint:disable-next-line:one-variable-per-declaration prefer-const
|
|
70
|
+
let h,
|
|
71
|
+
s,
|
|
72
|
+
l = (max + min) / 2;
|
|
73
|
+
if (max === min) {
|
|
74
|
+
h = s = 0;
|
|
75
|
+
} else {
|
|
76
|
+
const d = max - min;
|
|
77
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
78
|
+
|
|
79
|
+
switch (max) {
|
|
80
|
+
case r:
|
|
81
|
+
h = (g - b) / d + (g < b ? 6 : 0);
|
|
82
|
+
break;
|
|
83
|
+
case g:
|
|
84
|
+
h = (b - r) / d + 2;
|
|
85
|
+
break;
|
|
86
|
+
case b:
|
|
87
|
+
h = (r - g) / d + 4;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
h /= 6;
|
|
91
|
+
}
|
|
92
|
+
return [h, s, l];
|
|
93
|
+
}
|
|
94
|
+
private static hue2rgb(p: number, q: number, t: number) {
|
|
95
|
+
if (t < 0) t += 1;
|
|
96
|
+
if (t > 1) t -= 1;
|
|
97
|
+
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
|
98
|
+
if (t < 1 / 2) return q;
|
|
99
|
+
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
|
100
|
+
return p;
|
|
101
|
+
}
|
|
102
|
+
public static hslToRgb(hsl: number[]) {
|
|
103
|
+
const h = hsl[0];
|
|
104
|
+
const s = hsl[1];
|
|
105
|
+
const l = hsl[2];
|
|
106
|
+
// tslint:disable-next-line:one-variable-per-declaration
|
|
107
|
+
let r, g, b;
|
|
108
|
+
if (s === 0) {
|
|
109
|
+
r = g = b = l;
|
|
110
|
+
} else {
|
|
111
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
112
|
+
const p = 2 * l - q;
|
|
113
|
+
|
|
114
|
+
r = ColorHelper.hue2rgb(p, q, h + 1 / 3);
|
|
115
|
+
g = ColorHelper.hue2rgb(p, q, h);
|
|
116
|
+
b = ColorHelper.hue2rgb(p, q, h - 1 / 3);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return [r * 255, g * 255, b * 255];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
export enum PreferredColor {
|
|
123
|
+
Black,
|
|
124
|
+
White,
|
|
125
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { DurationFormat, DurationHelper } from './duration-helper';
|
|
2
|
+
|
|
3
|
+
describe('testing convert duration', () => {
|
|
4
|
+
it('converting hh:mm:ss', () => {
|
|
5
|
+
expect(DurationHelper.getDurationInSeconds(null)).toEqual(0);
|
|
6
|
+
expect(DurationHelper.getDurationInSeconds('')).toEqual(0);
|
|
7
|
+
expect(DurationHelper.getDurationInSeconds('00:01:00')).toEqual(60);
|
|
8
|
+
expect(DurationHelper.getDurationInSeconds('01:01:01')).toEqual(3600 + 60 + 1);
|
|
9
|
+
});
|
|
10
|
+
it('converting mm:ss', () => {
|
|
11
|
+
expect(DurationHelper.getDurationInSeconds('00:01')).toEqual(1);
|
|
12
|
+
expect(DurationHelper.getDurationInSeconds('01:01')).toEqual(60 + 1);
|
|
13
|
+
});
|
|
14
|
+
it('converting PT', () => {
|
|
15
|
+
expect(DurationHelper.getDurationInSeconds('PT1H1M1S')).toEqual(3600 + 60 + 1);
|
|
16
|
+
expect(DurationHelper.getDurationInSeconds('PT1M1S')).toEqual(60 + 1);
|
|
17
|
+
expect(DurationHelper.getDurationInSeconds('PT1S')).toEqual(1);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
describe('testing format duration', () => {
|
|
21
|
+
it('formatting colon', () => {
|
|
22
|
+
expect(DurationHelper.getDurationFormatted('0:0:1')).toEqual('00:00:01');
|
|
23
|
+
expect(DurationHelper.getDurationFormatted('0:1:0')).toEqual('00:01:00');
|
|
24
|
+
expect(DurationHelper.getDurationFormatted('1:1:1')).toEqual('01:01:01');
|
|
25
|
+
});
|
|
26
|
+
it('formatting Hms', () => {
|
|
27
|
+
expect(DurationHelper.getDurationFormatted('0:0:1', DurationFormat.Hms)).toEqual('1s');
|
|
28
|
+
expect(DurationHelper.getDurationFormatted('0:1:0', DurationFormat.Hms)).toEqual('1m');
|
|
29
|
+
expect(DurationHelper.getDurationFormatted('1:1:1', DurationFormat.Hms)).toEqual(
|
|
30
|
+
'1h 1m 1s',
|
|
31
|
+
);
|
|
32
|
+
expect(DurationHelper.getDurationFormatted('1:0:0', DurationFormat.Hms)).toEqual('1h');
|
|
33
|
+
expect(DurationHelper.getDurationFormatted('0:0:0', DurationFormat.Hms)).toEqual('');
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
export enum DurationFormat {
|
|
2
|
+
/**
|
|
3
|
+
* format with colon, i.e. H:MM:SS
|
|
4
|
+
*/
|
|
5
|
+
Colon = 'colon',
|
|
6
|
+
/**
|
|
7
|
+
* format with Hh Mm Ss
|
|
8
|
+
*/
|
|
9
|
+
Hms = 'hms',
|
|
10
|
+
}
|
|
11
|
+
export class DurationHelper {
|
|
12
|
+
public static getDurationInSeconds(value: string): number {
|
|
13
|
+
// PT1H5M23S
|
|
14
|
+
// or 00:00:00
|
|
15
|
+
// or 00:00
|
|
16
|
+
if (!value) return 0;
|
|
17
|
+
try {
|
|
18
|
+
let result = value.split(':');
|
|
19
|
+
if (result.length == 3) {
|
|
20
|
+
let h = result[0] ? parseInt(result[0]) : 0;
|
|
21
|
+
let m = result[1] ? parseInt(result[1]) : 0;
|
|
22
|
+
let s = result[2] ? parseInt(result[2]) : 0;
|
|
23
|
+
let time = h * 60 * 60 + m * 60 + s;
|
|
24
|
+
return time;
|
|
25
|
+
}
|
|
26
|
+
if (result.length == 2) {
|
|
27
|
+
let m = result[0] ? parseInt(result[0]) : 0;
|
|
28
|
+
let s = result[1] ? parseInt(result[1]) : 0;
|
|
29
|
+
let time = m * 60 + s;
|
|
30
|
+
return time;
|
|
31
|
+
}
|
|
32
|
+
} catch (e) {
|
|
33
|
+
return value as unknown as number;
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
let regexp = new RegExp('PT(\\d+H)?(\\d+M)?(\\d+S)?');
|
|
37
|
+
let result = regexp.exec(value);
|
|
38
|
+
let h = result[1] ? parseInt(result[1]) : 0;
|
|
39
|
+
let m = result[2] ? parseInt(result[2]) : 0;
|
|
40
|
+
let s = result[3] ? parseInt(result[3]) : 0;
|
|
41
|
+
let time = h * 60 * 60 + m * 60 + s;
|
|
42
|
+
return time;
|
|
43
|
+
} catch (e) {
|
|
44
|
+
return value as unknown as number;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
public static getDurationFormatted(
|
|
48
|
+
duration: string,
|
|
49
|
+
format: DurationFormat = DurationFormat.Colon,
|
|
50
|
+
): string {
|
|
51
|
+
let time = DurationHelper.getDurationInSeconds(duration);
|
|
52
|
+
if (!time) return '';
|
|
53
|
+
let h = Math.floor(time / 60 / 60);
|
|
54
|
+
let m = Math.floor(Math.floor(time / 60) % 60);
|
|
55
|
+
let s = Math.floor(time % 60);
|
|
56
|
+
let options: Intl.NumberFormatOptions = {
|
|
57
|
+
minimumIntegerDigits: 2,
|
|
58
|
+
maximumFractionDigits: 0,
|
|
59
|
+
};
|
|
60
|
+
let numberFormat = new Intl.NumberFormat([], options);
|
|
61
|
+
let str = '';
|
|
62
|
+
/*
|
|
63
|
+
if(h>0) {
|
|
64
|
+
str = format.format(h) + "h";
|
|
65
|
+
}
|
|
66
|
+
if(m>0) {
|
|
67
|
+
if (str)
|
|
68
|
+
str += " ";
|
|
69
|
+
str += format.format(m) + "m";
|
|
70
|
+
}
|
|
71
|
+
if(s>0) {
|
|
72
|
+
if (str)
|
|
73
|
+
str += " ";
|
|
74
|
+
str += format.format(s) + "s";
|
|
75
|
+
}
|
|
76
|
+
*/
|
|
77
|
+
if (format === DurationFormat.Colon) {
|
|
78
|
+
str =
|
|
79
|
+
numberFormat.format(h) +
|
|
80
|
+
':' +
|
|
81
|
+
numberFormat.format(m) +
|
|
82
|
+
':' +
|
|
83
|
+
numberFormat.format(s);
|
|
84
|
+
} else {
|
|
85
|
+
if (h > 0) {
|
|
86
|
+
str += h + 'h';
|
|
87
|
+
}
|
|
88
|
+
if (m > 0) {
|
|
89
|
+
str += ' ' + m + 'm';
|
|
90
|
+
}
|
|
91
|
+
if (s > 0) {
|
|
92
|
+
str += ' ' + s + 's';
|
|
93
|
+
}
|
|
94
|
+
str = str.trim();
|
|
95
|
+
}
|
|
96
|
+
return str;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function notNull<T>(value: T): boolean {
|
|
2
|
+
return value !== undefined && value !== null;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function isTrue(value: boolean): boolean {
|
|
6
|
+
return value ?? false;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function microTick(): Promise<void> {
|
|
10
|
+
return Promise.resolve();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function macroTick(): Promise<void> {
|
|
14
|
+
return new Promise((resolve) => setTimeout(() => resolve()));
|
|
15
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { isNumeric } from './isNumeric';
|
|
2
|
+
import { isArray } from 'lodash';
|
|
3
|
+
|
|
4
|
+
export class Helper {
|
|
5
|
+
public static deepCopy(data: any) {
|
|
6
|
+
if (data == null) return null;
|
|
7
|
+
return JSON.parse(JSON.stringify(data));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
public static deepCopyArray(data: any[]) {
|
|
11
|
+
if (!Array.isArray(data)) return data;
|
|
12
|
+
return data.slice();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Returns true if both objects have the same values stored
|
|
17
|
+
* will not work for classes including methods or similar dynamic data
|
|
18
|
+
* @param object1
|
|
19
|
+
* @param object2
|
|
20
|
+
* @returns {boolean}
|
|
21
|
+
*/
|
|
22
|
+
public static objectEquals(object1: any, object2: any) {
|
|
23
|
+
if (object1 == null) return object2 == null;
|
|
24
|
+
if (object2 == null) return object1 == null;
|
|
25
|
+
return JSON.stringify(object1) == JSON.stringify(object2);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* get data from an object based on a dotted path
|
|
30
|
+
* also supports arrays like "array.0.key"
|
|
31
|
+
* @param nested the object to return the data from
|
|
32
|
+
* @param path the path of the field location in dotted notation
|
|
33
|
+
*/
|
|
34
|
+
public static getDotPathFromNestedObject(nested: any, path: string) {
|
|
35
|
+
const split = path.split('.');
|
|
36
|
+
let obj = nested;
|
|
37
|
+
for (let key of split) {
|
|
38
|
+
if (isNumeric(key)) {
|
|
39
|
+
obj = obj?.[parseInt(key)];
|
|
40
|
+
} else {
|
|
41
|
+
if (isArray(obj)) {
|
|
42
|
+
return obj;
|
|
43
|
+
}
|
|
44
|
+
obj = obj?.[key];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return obj;
|
|
48
|
+
}
|
|
49
|
+
public static filterObjectPropertyNested(obj: any, property: string[]) {
|
|
50
|
+
for (let i in obj) {
|
|
51
|
+
if (!obj.hasOwnProperty(i)) continue;
|
|
52
|
+
if (property.includes(i)) {
|
|
53
|
+
delete obj[i];
|
|
54
|
+
} else if (typeof obj[i] === 'object') {
|
|
55
|
+
Helper.filterObjectPropertyNested(obj[i], property);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return obj;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copy paste from rxjs/util/isNumeric since importing it from there will trigger a warning about
|
|
3
|
+
* CommonJS or AMD dependencies and indeed increase the bundle size a bit.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// From https://github.com/ReactiveX/rxjs/blob/6.x/src/internal/util/isArray.ts
|
|
7
|
+
const isArray = (() =>
|
|
8
|
+
Array.isArray || (<T>(x: any): x is T[] => x && typeof x.length === 'number'))();
|
|
9
|
+
|
|
10
|
+
// From https://github.com/ReactiveX/rxjs/blob/6.x/src/internal/util/isNumeric.ts
|
|
11
|
+
export function isNumeric(val: any): val is number | string {
|
|
12
|
+
return !isArray(val) && val - parseFloat(val) + 1 >= 0;
|
|
13
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Node, RestConstants } from 'ngx-edu-sharing-api';
|
|
2
|
+
/**
|
|
3
|
+
* Different helper functions, may be used globally
|
|
4
|
+
*/
|
|
5
|
+
export class RestHelper {
|
|
6
|
+
protected static SPACES_STORE_REF = 'workspace://SpacesStore/';
|
|
7
|
+
public static getName(node: Node): string {
|
|
8
|
+
if (node.name) return node.name;
|
|
9
|
+
if (node.title) return node.title;
|
|
10
|
+
if (node.ref) return node.ref.id;
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
public static getTitle(node: Node): string {
|
|
14
|
+
if (node?.title) return node.title;
|
|
15
|
+
if (node?.name) {
|
|
16
|
+
return node?.name;
|
|
17
|
+
}
|
|
18
|
+
if (node?.properties) {
|
|
19
|
+
return RestHelper.getTitleFromProperties(node?.properties);
|
|
20
|
+
}
|
|
21
|
+
return '';
|
|
22
|
+
}
|
|
23
|
+
public static getTitleFromProperties(properties: any): string {
|
|
24
|
+
return properties[RestConstants.LOM_PROP_TITLE]
|
|
25
|
+
? properties[RestConstants.LOM_PROP_TITLE]
|
|
26
|
+
: properties[RestConstants.CM_NAME];
|
|
27
|
+
}
|
|
28
|
+
}
|