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.
Files changed (171) hide show
  1. package/.browserslistrc +16 -0
  2. package/.eslintrc.json +44 -0
  3. package/README.md +40 -0
  4. package/assets/scss/mixins.scss +95 -0
  5. package/assets/scss/variables.scss +33 -0
  6. package/karma.conf.js +42 -0
  7. package/ng-package.json +10 -0
  8. package/package.json +19 -0
  9. package/src/lib/actionbar/actionbar.component.html +59 -0
  10. package/src/lib/actionbar/actionbar.component.scss +123 -0
  11. package/src/lib/actionbar/actionbar.component.ts +174 -0
  12. package/src/lib/common/edu-sharing-ui-common.module.ts +80 -0
  13. package/src/lib/directives/border-box-observer.directive.ts +75 -0
  14. package/src/lib/directives/check-text-overflow.directive.ts +61 -0
  15. package/src/lib/directives/drag-nodes/drag-nodes.ts +32 -0
  16. package/src/lib/directives/drag-nodes/nodes-drag-source.directive.ts +79 -0
  17. package/src/lib/directives/drag-nodes/nodes-drag.directive.ts +43 -0
  18. package/src/lib/directives/drag-nodes/nodes-drop-target.directive.ts +116 -0
  19. package/src/lib/directives/focus-state.directive.ts +34 -0
  20. package/src/lib/directives/icon.directive.ts +142 -0
  21. package/src/lib/directives/nodes-drop-target-legacy.directive.ts +155 -0
  22. package/src/lib/dropdown/dropdown.component.html +32 -0
  23. package/src/lib/dropdown/dropdown.component.scss +67 -0
  24. package/src/lib/dropdown/dropdown.component.ts +71 -0
  25. package/src/lib/edu-sharing-ui-configuration.ts +47 -0
  26. package/src/lib/edu-sharing-ui.module.ts +49 -0
  27. package/src/lib/list-items/available-widgets.ts +30 -0
  28. package/src/lib/list-items/format-duration.pipe.ts +17 -0
  29. package/src/lib/list-items/list-base/list-base.component.html +52 -0
  30. package/src/lib/list-items/list-base/list-base.component.ts +44 -0
  31. package/src/lib/list-items/list-collection-info/list-collection-info.component.html +48 -0
  32. package/src/lib/list-items/list-collection-info/list-collection-info.component.scss +8 -0
  33. package/src/lib/list-items/list-collection-info/list-collection-info.component.ts +24 -0
  34. package/src/lib/list-items/list-counts/list-counts.component.html +1 -0
  35. package/src/lib/list-items/list-counts/list-counts.component.scss +3 -0
  36. package/src/lib/list-items/list-counts/list-counts.component.ts +59 -0
  37. package/src/lib/list-items/list-items.module.ts +33 -0
  38. package/src/lib/list-items/list-node-license/list-node-license.component.html +8 -0
  39. package/src/lib/list-items/list-node-license/list-node-license.component.ts +47 -0
  40. package/src/lib/list-items/list-node-replication-source/list-node-replication-source.component.html +11 -0
  41. package/src/lib/list-items/list-node-replication-source/list-node-replication-source.component.ts +60 -0
  42. package/src/lib/list-items/list-node-workflow/list-node-workflow.component.html +3 -0
  43. package/src/lib/list-items/list-node-workflow/list-node-workflow.component.ts +21 -0
  44. package/src/lib/list-items/list-text/list-text.component.html +176 -0
  45. package/src/lib/list-items/list-text/list-text.component.scss +3 -0
  46. package/src/lib/list-items/list-text/list-text.component.ts +107 -0
  47. package/src/lib/list-items/list-widget.ts +52 -0
  48. package/src/lib/list-items/node-row/node-row.component.html +31 -0
  49. package/src/lib/list-items/node-row/node-row.component.scss +50 -0
  50. package/src/lib/list-items/node-row/node-row.component.ts +16 -0
  51. package/src/lib/list-items/node-source.pipe.ts +48 -0
  52. package/src/lib/node-entries/combined-data-source.ts +51 -0
  53. package/src/lib/node-entries/custom-templates-data-source.ts +6 -0
  54. package/src/lib/node-entries/drag-preview/drag-preview.component.html +6 -0
  55. package/src/lib/node-entries/drag-preview/drag-preview.component.scss +35 -0
  56. package/src/lib/node-entries/drag-preview/drag-preview.component.ts +15 -0
  57. package/src/lib/node-entries/entries-model.ts +120 -0
  58. package/src/lib/node-entries/items-cap.ts +54 -0
  59. package/src/lib/node-entries/list-item-label.pipe.ts +28 -0
  60. package/src/lib/node-entries/mixins.scss +23 -0
  61. package/src/lib/node-entries/node-cache.spec.ts +199 -0
  62. package/src/lib/node-entries/node-cache.ts +81 -0
  63. package/src/lib/node-entries/node-data-source-remote.ts +33 -0
  64. package/src/lib/node-entries/node-data-source.ts +148 -0
  65. package/src/lib/node-entries/node-entries-card/node-entries-card.component.html +167 -0
  66. package/src/lib/node-entries/node-entries-card/node-entries-card.component.scss +28 -0
  67. package/src/lib/node-entries/node-entries-card/node-entries-card.component.ts +132 -0
  68. package/src/lib/node-entries/node-entries-card/node-entries-card.main.scss +261 -0
  69. package/src/lib/node-entries/node-entries-card-grid/node-entries-card-grid.component.html +205 -0
  70. package/src/lib/node-entries/node-entries-card-grid/node-entries-card-grid.component.scss +181 -0
  71. package/src/lib/node-entries/node-entries-card-grid/node-entries-card-grid.component.ts +361 -0
  72. package/src/lib/node-entries/node-entries-card-small/node-entries-card-small.component.html +100 -0
  73. package/src/lib/node-entries/node-entries-card-small/node-entries-card-small.component.scss +46 -0
  74. package/src/lib/node-entries/node-entries-card-small/node-entries-card-small.component.ts +40 -0
  75. package/src/lib/node-entries/node-entries-global-options/node-entries-global-options.component.html +23 -0
  76. package/src/lib/node-entries/node-entries-global-options/node-entries-global-options.component.scss +58 -0
  77. package/src/lib/node-entries/node-entries-global-options/node-entries-global-options.component.ts +16 -0
  78. package/src/lib/node-entries/node-entries-global.service.ts +79 -0
  79. package/src/lib/node-entries/node-entries-table/column-chooser/column-chooser.component.html +25 -0
  80. package/src/lib/node-entries/node-entries-table/column-chooser/column-chooser.component.scss +32 -0
  81. package/src/lib/node-entries/node-entries-table/column-chooser/column-chooser.component.ts +31 -0
  82. package/src/lib/node-entries/node-entries-table/node-entries-table.component.html +270 -0
  83. package/src/lib/node-entries/node-entries-table/node-entries-table.component.scss +169 -0
  84. package/src/lib/node-entries/node-entries-table/node-entries-table.component.ts +333 -0
  85. package/src/lib/node-entries/node-entries-templates.service.ts +31 -0
  86. package/src/lib/node-entries/node-entries-wrapper.component.ts +363 -0
  87. package/src/lib/node-entries/node-entries.component.html +33 -0
  88. package/src/lib/node-entries/node-entries.component.scss +13 -0
  89. package/src/lib/node-entries/node-entries.component.ts +151 -0
  90. package/src/lib/node-entries/node-entries.module.ts +93 -0
  91. package/src/lib/node-entries/node-rating/node-rating.component.html +53 -0
  92. package/src/lib/node-entries/node-rating/node-rating.component.scss +31 -0
  93. package/src/lib/node-entries/node-rating/node-rating.component.ts +105 -0
  94. package/src/lib/node-entries/node-stats-badges/node-stats-badges.component.html +39 -0
  95. package/src/lib/node-entries/node-stats-badges/node-stats-badges.component.scss +44 -0
  96. package/src/lib/node-entries/node-stats-badges/node-stats-badges.component.ts +43 -0
  97. package/src/lib/node-entries/node-type-badge/node-type-badge.component.html +31 -0
  98. package/src/lib/node-entries/node-type-badge/node-type-badge.component.scss +5 -0
  99. package/src/lib/node-entries/node-type-badge/node-type-badge.component.ts +36 -0
  100. package/src/lib/node-entries/option-button/option-button.component.ts +42 -0
  101. package/src/lib/node-entries/preview-image/preview-image.component.html +19 -0
  102. package/src/lib/node-entries/preview-image/preview-image.component.scss +31 -0
  103. package/src/lib/node-entries/preview-image/preview-image.component.ts +47 -0
  104. package/src/lib/node-entries/sort-select-panel/sort-select-panel.component.html +27 -0
  105. package/src/lib/node-entries/sort-select-panel/sort-select-panel.component.scss +9 -0
  106. package/src/lib/node-entries/sort-select-panel/sort-select-panel.component.ts +26 -0
  107. package/src/lib/node-url/node-url.component.html +66 -0
  108. package/src/lib/node-url/node-url.component.scss +32 -0
  109. package/src/lib/node-url/node-url.component.ts +136 -0
  110. package/src/lib/pipes/file-size.pipe.ts +24 -0
  111. package/src/lib/pipes/format-date.pipe.ts +39 -0
  112. package/src/lib/pipes/node-icon.pipe.ts +11 -0
  113. package/src/lib/pipes/node-image-size.pipe.ts +18 -0
  114. package/src/lib/pipes/node-image.pipe.ts +71 -0
  115. package/src/lib/pipes/node-person-name.pipe.ts +41 -0
  116. package/src/lib/pipes/node-title.pipe.ts +12 -0
  117. package/src/lib/pipes/option-tooltip.pipe.ts +32 -0
  118. package/src/lib/pipes/replace-chars.pipe.ts +21 -0
  119. package/src/lib/pipes/vcard-name.pipe.ts +11 -0
  120. package/src/lib/services/abstract/app.service.ts +4 -0
  121. package/src/lib/services/abstract/keyboard-shortcuts.service.ts +10 -0
  122. package/src/lib/services/abstract/options-helper.service.ts +29 -0
  123. package/src/lib/services/abstract/toast.service.ts +5 -0
  124. package/src/lib/services/accessibility.service.ts +101 -0
  125. package/src/lib/services/local-events.service.ts +29 -0
  126. package/src/lib/services/node-entries.service.ts +172 -0
  127. package/src/lib/services/node-helper.service.ts +239 -0
  128. package/src/lib/services/nodes-drag-drop.service.ts +165 -0
  129. package/src/lib/services/options-helper-data.service.ts +186 -0
  130. package/src/lib/services/repo-url.service.ts +46 -0
  131. package/src/lib/services/temporary-storage.service.ts +58 -0
  132. package/src/lib/services/ui.service.ts +182 -0
  133. package/src/lib/sort-dropdown/sort-dropdown.component.html +22 -0
  134. package/src/lib/sort-dropdown/sort-dropdown.component.scss +47 -0
  135. package/src/lib/sort-dropdown/sort-dropdown.component.ts +42 -0
  136. package/src/lib/spinner/spinner.component.html +14 -0
  137. package/src/lib/spinner/spinner.component.scss +141 -0
  138. package/src/lib/spinner/spinner.component.ts +12 -0
  139. package/src/lib/translations/README.md +44 -0
  140. package/src/lib/translations/fallback-translation-handler.ts +7 -0
  141. package/src/lib/translations/languages.ts +6 -0
  142. package/src/lib/translations/translation-loader.spec.ts +352 -0
  143. package/src/lib/translations/translation-loader.ts +189 -0
  144. package/src/lib/translations/translation-source.ts +9 -0
  145. package/src/lib/translations/translations.module.ts +49 -0
  146. package/src/lib/translations/translations.service.spec.ts +152 -0
  147. package/src/lib/translations/translations.service.ts +188 -0
  148. package/src/lib/types/accessibillity.ts +15 -0
  149. package/src/lib/types/api-models.ts +4 -0
  150. package/src/lib/types/drag-drop.ts +22 -0
  151. package/src/lib/types/keyboard-shortcuts.ts +29 -0
  152. package/src/lib/types/list-item.ts +67 -0
  153. package/src/lib/types/option-item.ts +247 -0
  154. package/src/lib/types/workflow.ts +35 -0
  155. package/src/lib/util/DateHelper.spec.ts +112 -0
  156. package/src/lib/util/DateHelper.ts +197 -0
  157. package/src/lib/util/VCard.ts +277 -0
  158. package/src/lib/util/color-helper.ts +125 -0
  159. package/src/lib/util/duration-helper.spec.ts +35 -0
  160. package/src/lib/util/duration-helper.ts +98 -0
  161. package/src/lib/util/functions.ts +15 -0
  162. package/src/lib/util/helper.ts +60 -0
  163. package/src/lib/util/isNumeric.ts +13 -0
  164. package/src/lib/util/rest-helper.ts +28 -0
  165. package/src/lib/util/ui-animation.ts +154 -0
  166. package/src/lib/util/ui-constants.ts +20 -0
  167. package/src/module.ts +76 -0
  168. package/src/test.ts +28 -0
  169. package/tsconfig.lib.json +15 -0
  170. package/tsconfig.lib.prod.json +10 -0
  171. 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
+ }