ngx-transforms 0.0.5 → 0.2.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/fesm2022/ngx-transforms.mjs +1467 -606
- package/fesm2022/ngx-transforms.mjs.map +1 -1
- package/package.json +19 -3
- package/types/ngx-transforms.d.ts +681 -300
|
@@ -60,8 +60,6 @@ import * as QRCode from 'qrcode';
|
|
|
60
60
|
* @example
|
|
61
61
|
* // With inverted colors
|
|
62
62
|
* {{ 'DARK' | asciiArt:{ inverted: true, charset: CharsetPreset.MINIMAL } }}
|
|
63
|
-
*
|
|
64
|
-
* @author Mofiro Jean
|
|
65
63
|
*/
|
|
66
64
|
class AsciiArtPipe {
|
|
67
65
|
generator;
|
|
@@ -118,59 +116,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
118
116
|
}]
|
|
119
117
|
}], ctorParameters: () => [] });
|
|
120
118
|
|
|
121
|
-
/**
|
|
122
|
-
* BarcodePipe: Generates a barcode from a string value.
|
|
123
|
-
*
|
|
124
|
-
* @param {string} value - The value to encode (e.g., '123456789').
|
|
125
|
-
* @param {BarcodeOptions} [options={}] - Configuration options.
|
|
126
|
-
*
|
|
127
|
-
* @returns {Promise<SafeHtml | SafeResourceUrl>} - SVG markup or image data URL.
|
|
128
|
-
*
|
|
129
|
-
* @example
|
|
130
|
-
* <div [innerHTML]="'123456789' | barcode:{elementType:'svg',format:'CODE128'} | async"></div>
|
|
131
|
-
* <img [src]="'123456789' | barcode:{elementType:'img'} | async" />
|
|
132
|
-
*
|
|
133
|
-
* @author Mofiro Jean
|
|
134
|
-
*/
|
|
135
|
-
class BarcodePipe {
|
|
136
|
-
sanitizer = inject(DomSanitizer);
|
|
137
|
-
async transform(value, options = {}) {
|
|
138
|
-
const { elementType = 'svg', format = 'CODE128', lineColor = '#000000', width = 2, height = 100, displayValue = true, } = options;
|
|
139
|
-
if (!value) {
|
|
140
|
-
return '';
|
|
141
|
-
}
|
|
142
|
-
// Sanitize the value to prevent XSS
|
|
143
|
-
const sanitizedValue = value.replace(/</g, '<').replace(/>/g, '>');
|
|
144
|
-
try {
|
|
145
|
-
const config = { format, lineColor, width, height, displayValue };
|
|
146
|
-
if (elementType === 'svg') {
|
|
147
|
-
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
148
|
-
JsBarcode(svg, sanitizedValue, config);
|
|
149
|
-
return this.sanitizer.bypassSecurityTrustHtml(svg.outerHTML);
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
const canvas = document.createElement('canvas');
|
|
153
|
-
JsBarcode(canvas, sanitizedValue, config);
|
|
154
|
-
const dataUrl = canvas.toDataURL('image/png');
|
|
155
|
-
return this.sanitizer.bypassSecurityTrustResourceUrl(dataUrl);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
catch (error) {
|
|
159
|
-
console.error('Barcode generation failed:', error);
|
|
160
|
-
return '';
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BarcodePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
164
|
-
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: BarcodePipe, isStandalone: true, name: "barcode" });
|
|
165
|
-
}
|
|
166
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BarcodePipe, decorators: [{
|
|
167
|
-
type: Pipe,
|
|
168
|
-
args: [{
|
|
169
|
-
name: 'barcode',
|
|
170
|
-
standalone: true,
|
|
171
|
-
}]
|
|
172
|
-
}] });
|
|
173
|
-
|
|
174
119
|
/**
|
|
175
120
|
* CamelCasePipe: Converts text to camelCase (e.g., "hello world" → "helloWorld").
|
|
176
121
|
*
|
|
@@ -181,8 +126,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
181
126
|
* ```html
|
|
182
127
|
* {{ 'hello world' | camelCase }} <!-- Outputs: helloWorld -->
|
|
183
128
|
* ```
|
|
184
|
-
*
|
|
185
|
-
* @author Mofiro Jean
|
|
186
129
|
*/
|
|
187
130
|
class CamelCasePipe {
|
|
188
131
|
transform(value) {
|
|
@@ -210,48 +153,608 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
210
153
|
}]
|
|
211
154
|
}] });
|
|
212
155
|
|
|
213
|
-
// Pre-compiled regex patterns for performance
|
|
214
|
-
const HEX_6_PATTERN = /^#([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/;
|
|
215
|
-
const HEX_8_PATTERN = /^#([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/;
|
|
216
|
-
const HEX_3_PATTERN = /^#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/;
|
|
217
|
-
const HEX_4_PATTERN = /^#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/;
|
|
218
|
-
const RGB_PATTERN = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i;
|
|
219
|
-
const RGBA_PATTERN = /^rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*([\d.]+)\s*\)$/i;
|
|
220
156
|
/**
|
|
221
|
-
*
|
|
157
|
+
* HighlightPipe: Highlights occurrences of a search term within a string.
|
|
158
|
+
*
|
|
159
|
+
* This Angular pipe transforms a string input by wrapping all occurrences of a specified
|
|
160
|
+
* search term with a `<span>` element that has the class "highlight".
|
|
161
|
+
* It uses the Angular `DomSanitizer` to bypass security and render the highlighted HTML.
|
|
162
|
+
*
|
|
163
|
+
* @param {string} value - The input string in which to highlight the search term.
|
|
164
|
+
* @param {string} searchTerm - The string to search for and highlight.
|
|
165
|
+
* @returns {SafeHtml} - The input string with the search term highlighted, or an empty string if input or searchTerm are falsy.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* {{ 'This is a test string' | highlight: 'test' }} // Returns 'This is a <span class="highlight">test</span> string'
|
|
169
|
+
* {{ 'This is a test TEST string' | highlight: 'test' }} // Returns 'This is a <span class="highlight">test</span> <span class="highlight">TEST</span> string'
|
|
170
|
+
* {{ 'This is a test string' | highlight: '' }} // Returns 'This is a test string'
|
|
171
|
+
* {{ null | highlight: 'test' }} // Returns ''
|
|
172
|
+
* {{ undefined | highlight: 'test' }} // Returns ''
|
|
222
173
|
*/
|
|
223
|
-
|
|
224
|
-
|
|
174
|
+
class HighlightPipe {
|
|
175
|
+
sanitizer = inject(DomSanitizer);
|
|
176
|
+
transform(value, searchTerm) {
|
|
177
|
+
if (!value || !searchTerm) {
|
|
178
|
+
return this.sanitizer.bypassSecurityTrustHtml(value || '');
|
|
179
|
+
}
|
|
180
|
+
const escapedSearch = searchTerm.replace(/[.*+?${}()|[\\]/g, '\\$&');
|
|
181
|
+
const regex = new RegExp(`(${escapedSearch})`, 'gi');
|
|
182
|
+
const highlighed = value.replace(regex, '<span class="highlight">$1</span>');
|
|
183
|
+
return this.sanitizer.bypassSecurityTrustHtml(highlighed);
|
|
184
|
+
}
|
|
185
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: HighlightPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
186
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: HighlightPipe, isStandalone: true, name: "highlight" });
|
|
225
187
|
}
|
|
188
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: HighlightPipe, decorators: [{
|
|
189
|
+
type: Pipe,
|
|
190
|
+
args: [{
|
|
191
|
+
name: 'highlight',
|
|
192
|
+
standalone: true
|
|
193
|
+
}]
|
|
194
|
+
}] });
|
|
195
|
+
|
|
226
196
|
/**
|
|
227
|
-
*
|
|
197
|
+
* InitialsPipe: Extracts initials from a name.
|
|
198
|
+
*
|
|
199
|
+
* @param {string} value - The full name.
|
|
200
|
+
*
|
|
201
|
+
* @returns {string} - The initials (e.g., 'John Doe' → 'JD').
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* {{ 'John Doe' | initials }} // Outputs: JD
|
|
205
|
+
* {{ 'Mary Jane Watson' | initials }} // Outputs: MJW
|
|
228
206
|
*/
|
|
229
|
-
|
|
230
|
-
|
|
207
|
+
class InitialsPipe {
|
|
208
|
+
transform(value) {
|
|
209
|
+
if (!value)
|
|
210
|
+
return '';
|
|
211
|
+
return value
|
|
212
|
+
.trim()
|
|
213
|
+
.split(/\s+/)
|
|
214
|
+
.map(word => word.charAt(0).toUpperCase())
|
|
215
|
+
.join('');
|
|
216
|
+
}
|
|
217
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: InitialsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
218
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: InitialsPipe, isStandalone: true, name: "initials" });
|
|
231
219
|
}
|
|
220
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: InitialsPipe, decorators: [{
|
|
221
|
+
type: Pipe,
|
|
222
|
+
args: [{
|
|
223
|
+
name: 'initials',
|
|
224
|
+
standalone: true
|
|
225
|
+
}]
|
|
226
|
+
}] });
|
|
227
|
+
|
|
232
228
|
/**
|
|
233
|
-
* Converts
|
|
229
|
+
* KebabCasePipe: Converts text to kebab-case (e.g., "hello world" → "hello-world").
|
|
230
|
+
*
|
|
231
|
+
* @param {string} value - The input string to transform.
|
|
232
|
+
* @returns {string} The string in kebab-case, or an empty string if input is invalid.
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```html
|
|
236
|
+
* {{ 'hello world' | kebabCase }} <!-- Outputs: hello-world -->
|
|
237
|
+
* ```
|
|
234
238
|
*/
|
|
235
|
-
|
|
236
|
-
|
|
239
|
+
class KebabCasePipe {
|
|
240
|
+
transform(value) {
|
|
241
|
+
if (!value || typeof value !== 'string')
|
|
242
|
+
return '';
|
|
243
|
+
return value
|
|
244
|
+
.trim()
|
|
245
|
+
.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2') // Add hyphen between camelCase words
|
|
246
|
+
.toLowerCase()
|
|
247
|
+
.replace(/[^a-z0-9-]+/g, '-') // Replace non-alphanumeric (except hyphen) with hyphen
|
|
248
|
+
.replace(/^-|-$/g, ''); // Remove leading/trailing hyphens
|
|
249
|
+
}
|
|
250
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: KebabCasePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
251
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: KebabCasePipe, isStandalone: true, name: "kebabCase" });
|
|
237
252
|
}
|
|
253
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: KebabCasePipe, decorators: [{
|
|
254
|
+
type: Pipe,
|
|
255
|
+
args: [{
|
|
256
|
+
name: 'kebabCase',
|
|
257
|
+
standalone: true
|
|
258
|
+
}]
|
|
259
|
+
}] });
|
|
260
|
+
|
|
238
261
|
/**
|
|
239
|
-
* Converts
|
|
262
|
+
* MorseCodePipe: Converts text to Morse code.
|
|
263
|
+
*
|
|
264
|
+
* @param {string} value - The text to convert to Morse code.
|
|
265
|
+
*
|
|
266
|
+
* @returns {string} - The Morse code representation (e.g., 'SOS' → '... --- ...').
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* {{ 'SOS' | morseCode }} // Outputs: '... --- ...'
|
|
270
|
+
* {{ 'HELP' | morseCode }} // Outputs: '.... . .-.. .--.'
|
|
271
|
+
* <p>{{ userInput | morseCode }}</p>
|
|
240
272
|
*/
|
|
241
|
-
|
|
242
|
-
|
|
273
|
+
class MorseCodePipe {
|
|
274
|
+
morseCodeMap = {
|
|
275
|
+
'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.',
|
|
276
|
+
'G': '--.', 'H': '....', 'I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..',
|
|
277
|
+
'M': '--', 'N': '-.', 'O': '---', 'P': '.--.', 'Q': '--.-', 'R': '.-.',
|
|
278
|
+
'S': '...', 'T': '-', 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-',
|
|
279
|
+
'Y': '-.--', 'Z': '--..', '0': '-----', '1': '.----', '2': '..---',
|
|
280
|
+
'3': '...--', '4': '....-', '5': '.....', '6': '-....', '7': '--...',
|
|
281
|
+
'8': '---..', '9': '----.'
|
|
282
|
+
};
|
|
283
|
+
transform(value) {
|
|
284
|
+
if (!value || typeof value !== 'string') {
|
|
285
|
+
return '';
|
|
286
|
+
}
|
|
287
|
+
return value
|
|
288
|
+
.toUpperCase()
|
|
289
|
+
.split('')
|
|
290
|
+
.map(char => this.morseCodeMap[char] || '')
|
|
291
|
+
.filter(code => code)
|
|
292
|
+
.join(' ');
|
|
293
|
+
}
|
|
294
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: MorseCodePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
295
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: MorseCodePipe, isStandalone: true, name: "morseCode" });
|
|
243
296
|
}
|
|
297
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: MorseCodePipe, decorators: [{
|
|
298
|
+
type: Pipe,
|
|
299
|
+
args: [{
|
|
300
|
+
name: 'morseCode',
|
|
301
|
+
standalone: true
|
|
302
|
+
}]
|
|
303
|
+
}] });
|
|
304
|
+
|
|
244
305
|
/**
|
|
245
|
-
*
|
|
306
|
+
* ReplacePipe: A custom Angular pipe that either highlights or replaces text based on a pattern.
|
|
307
|
+
*
|
|
308
|
+
* - If `isReplace` is `false`, it highlights occurrences of the pattern (if `highlightClass` is provided).
|
|
309
|
+
* - If `isReplace` is `true`, it replaces occurrences of the pattern with the replacement string, optionally highlighting the replacement.
|
|
310
|
+
*
|
|
311
|
+
* @param {string} value - The input string to transform.
|
|
312
|
+
* @param {string | RegExp} pattern - The pattern to match (string or RegExp). If an empty string, the value is returned as-is.
|
|
313
|
+
* @param {string} replacement - The string to replace matches with.
|
|
314
|
+
* @param {string} [highlightClass] - Optional CSS class for highlighting matched or replaced text (e.g., 'highlight').
|
|
315
|
+
* @param {boolean} [isReplace=true] - Whether to perform replacement (true) or only highlight matches (false).
|
|
316
|
+
*
|
|
317
|
+
* @returns {string | SafeHtml} - Returns the transformed string or SafeHtml with highlights.
|
|
246
318
|
*/
|
|
247
|
-
|
|
248
|
-
|
|
319
|
+
class ReplacePipe {
|
|
320
|
+
sanitizer = inject(DomSanitizer);
|
|
321
|
+
transform(value, pattern, replacement, highlightClass, isReplace = true) {
|
|
322
|
+
if (!value)
|
|
323
|
+
return '';
|
|
324
|
+
// handles empty string pattern
|
|
325
|
+
if (!pattern || (typeof pattern === 'string' && pattern.trim() === '')) {
|
|
326
|
+
return value;
|
|
327
|
+
}
|
|
328
|
+
const finalPattern = typeof pattern === 'string' ? new RegExp(pattern, 'gi') : pattern;
|
|
329
|
+
if (!highlightClass) {
|
|
330
|
+
return isReplace ? value.replace(finalPattern, replacement) : value;
|
|
331
|
+
}
|
|
332
|
+
// Sanitize the replacement to prevent XSS
|
|
333
|
+
const sanitizedReplacement = replacement.replace(/</g, '<').replace(/>/g, '>');
|
|
334
|
+
if (isReplace) {
|
|
335
|
+
const highlightedReplacement = `<span class="${highlightClass}">${sanitizedReplacement}</span>`;
|
|
336
|
+
const replaced = value.replace(finalPattern, highlightedReplacement);
|
|
337
|
+
return this.sanitizer.bypassSecurityTrustHtml(replaced);
|
|
338
|
+
}
|
|
339
|
+
const highlightedMatch = `<span class="${highlightClass}">$&</span>`;
|
|
340
|
+
const result = value.replace(finalPattern, highlightedMatch);
|
|
341
|
+
return this.sanitizer.bypassSecurityTrustHtml(result);
|
|
342
|
+
}
|
|
343
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ReplacePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
344
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: ReplacePipe, isStandalone: true, name: "replace" });
|
|
249
345
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
346
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ReplacePipe, decorators: [{
|
|
347
|
+
type: Pipe,
|
|
348
|
+
args: [{
|
|
349
|
+
name: 'replace',
|
|
350
|
+
standalone: true
|
|
351
|
+
}]
|
|
352
|
+
}] });
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* SnakeCasePipe: Converts text to snake_case (e.g., "hello world" → "hello_world").
|
|
356
|
+
*
|
|
357
|
+
* @param {string} value - The input string to transform.
|
|
358
|
+
* @returns {string} The string in snake_case, or an empty string if input is invalid.
|
|
359
|
+
*
|
|
360
|
+
* @example
|
|
361
|
+
* ```html
|
|
362
|
+
* {{ 'hello world' | snakeCase }} <!-- Outputs: hello_world -->
|
|
363
|
+
* ```
|
|
364
|
+
*/
|
|
365
|
+
class SnakeCasePipe {
|
|
366
|
+
transform(value) {
|
|
367
|
+
if (!value || typeof value !== 'string')
|
|
368
|
+
return '';
|
|
369
|
+
return value
|
|
370
|
+
.trim()
|
|
371
|
+
.replace(/([A-Z])/g, '_$1') // Convert camelCase to snake_case (e.g., helloWorld -> hello_World)
|
|
372
|
+
.toLowerCase() // Convert everything to lowercase
|
|
373
|
+
.replace(/[\s-]+/g, '_') // Replace spaces and hyphens with underscores
|
|
374
|
+
.replace(/[^a-z0-9_]+/g, '') // Remove all non-alphanumeric and non-underscore characters
|
|
375
|
+
.replace(/_+/g, '_') // Collapse multiple underscores
|
|
376
|
+
.replace(/^_|_$/g, ''); // Remove leading/trailing underscores
|
|
377
|
+
}
|
|
378
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: SnakeCasePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
379
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: SnakeCasePipe, isStandalone: true, name: "snakeCase" });
|
|
380
|
+
}
|
|
381
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: SnakeCasePipe, decorators: [{
|
|
382
|
+
type: Pipe,
|
|
383
|
+
args: [{
|
|
384
|
+
name: 'snakeCase',
|
|
385
|
+
standalone: true
|
|
386
|
+
}]
|
|
387
|
+
}] });
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* TitleCasePipe: Capitalizes the first letter of each word in a string.
|
|
391
|
+
*
|
|
392
|
+
* @param {string} value - The input string to transform.
|
|
393
|
+
* @returns {string} The string with each word capitalized, or an empty string if input is invalid.
|
|
394
|
+
*
|
|
395
|
+
* @example
|
|
396
|
+
* ```html
|
|
397
|
+
* {{ 'hello world' | titleCase }} <!-- Outputs: Hello World -->
|
|
398
|
+
* ```
|
|
399
|
+
*/
|
|
400
|
+
class TitleCasePipe {
|
|
401
|
+
transform(value) {
|
|
402
|
+
if (!value || typeof value !== 'string')
|
|
403
|
+
return '';
|
|
404
|
+
return value
|
|
405
|
+
.split(' ')
|
|
406
|
+
.filter(word => word.length > 0)
|
|
407
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
408
|
+
.join(' ');
|
|
409
|
+
}
|
|
410
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: TitleCasePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
411
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: TitleCasePipe, isStandalone: true, name: "titleCase" });
|
|
412
|
+
}
|
|
413
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: TitleCasePipe, decorators: [{
|
|
414
|
+
type: Pipe,
|
|
415
|
+
args: [{
|
|
416
|
+
name: 'titleCase',
|
|
417
|
+
standalone: true
|
|
418
|
+
}]
|
|
419
|
+
}] });
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* TruncatePipe: Truncates a string to a specified maximum length, optionally preserving words.
|
|
423
|
+
*
|
|
424
|
+
* This Angular pipe transforms a string input by truncating it to the given `maxLength`.
|
|
425
|
+
* It provides options to customize the ellipsis and preserve word boundaries.
|
|
426
|
+
*
|
|
427
|
+
* @param {string} value - The input string to be truncated.
|
|
428
|
+
* @param {number} [maxLength=10] - The maximum length of the truncated string. Defaults to 10.
|
|
429
|
+
* @param {string} [ellipsis='...'] - The string to append to the truncated portion. Defaults to '...'.
|
|
430
|
+
* @param {boolean} [preserveWords=false] - If true, truncates at the last space before `maxLength` to avoid cutting words. Defaults to false.
|
|
431
|
+
* @returns {string} - The truncated string. Returns an empty string if the input is null, undefined, or not a string.
|
|
432
|
+
*
|
|
433
|
+
* @example
|
|
434
|
+
* {{ 'This is a long sentence' | truncate }} // Returns 'This is a...'
|
|
435
|
+
* {{ 'This is a long sentence' | truncate: 20 }} // Returns 'This is a long sente...'
|
|
436
|
+
* {{ 'This is a long sentence' | truncate: 15: ' [more]' }} // Returns 'This is a long [more]'
|
|
437
|
+
* {{ 'This is a long sentence' | truncate: 15: '...' : true }} // Returns 'This is a...'
|
|
438
|
+
* {{ 'This is a long sentence' | truncate: 20: '...' : true }} // Returns 'This is a long...'
|
|
439
|
+
* {{ null | truncate }} // Returns ''
|
|
440
|
+
* {{ undefined | truncate }} // Returns ''
|
|
441
|
+
*/
|
|
442
|
+
class TruncatePipe {
|
|
443
|
+
transform(value, maxLength = 10, ellipsis = '...', preserveWords = false) {
|
|
444
|
+
if (!value || typeof value !== 'string') {
|
|
445
|
+
return '';
|
|
446
|
+
}
|
|
447
|
+
if (value.length <= maxLength) {
|
|
448
|
+
return value;
|
|
449
|
+
}
|
|
450
|
+
const charsToKeep = maxLength - ellipsis.length;
|
|
451
|
+
// If maxLength is too small to even include the ellipsis, just return the ellipsis.
|
|
452
|
+
if (charsToKeep < 0) {
|
|
453
|
+
return ellipsis;
|
|
454
|
+
}
|
|
455
|
+
let truncated = value.substring(0, charsToKeep);
|
|
456
|
+
if (preserveWords) {
|
|
457
|
+
const lastSpaceIndex = truncated.lastIndexOf(' ');
|
|
458
|
+
// If a space is found and it's not the very beginning of the string
|
|
459
|
+
if (lastSpaceIndex !== -1 && lastSpaceIndex !== 0) {
|
|
460
|
+
truncated = truncated.substring(0, lastSpaceIndex);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
return truncated.trim() + ellipsis;
|
|
464
|
+
}
|
|
465
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: TruncatePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
466
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: TruncatePipe, isStandalone: true, name: "truncate" });
|
|
467
|
+
}
|
|
468
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: TruncatePipe, decorators: [{
|
|
469
|
+
type: Pipe,
|
|
470
|
+
args: [{
|
|
471
|
+
name: 'truncate',
|
|
472
|
+
standalone: true
|
|
473
|
+
}]
|
|
474
|
+
}] });
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* CreditCardMaskPipe: Masks all but the last four digits of a string, optionally controlled by a boolean flag.
|
|
478
|
+
* By default, masking is applied.
|
|
479
|
+
*
|
|
480
|
+
* @param {string} value - The input string to mask (e.g., credit card number).
|
|
481
|
+
* @param {boolean} shouldMask - (Optional) Determines if masking should be applied. Defaults to true.
|
|
482
|
+
* @returns {string} - The masked string or the original value if `shouldMask` is false or the value is too short.
|
|
483
|
+
*
|
|
484
|
+
* @example
|
|
485
|
+
* {{ '1234567890123456' | creditCardMask }} // Outputs: **** **** **** 3456
|
|
486
|
+
* {{ '1234-5678-9012-3456' | creditCardMask }} // Outputs: **** **** **** 3456
|
|
487
|
+
* {{ '1234567890123456' | creditCardMask: true }} // Outputs: **** **** **** 3456
|
|
488
|
+
* {{ '1234567890123456' | creditCardMask: false }} // Outputs: 1234567890123456
|
|
489
|
+
*/
|
|
490
|
+
class CreditCardMaskPipe {
|
|
491
|
+
transform(value, shouldMask = true) {
|
|
492
|
+
if (!value) {
|
|
493
|
+
return value;
|
|
494
|
+
}
|
|
495
|
+
if (shouldMask) {
|
|
496
|
+
const cleanedValue = value.replace(/[\s-]/g, '');
|
|
497
|
+
const cleanedLength = cleanedValue.length;
|
|
498
|
+
if (cleanedLength < 4) {
|
|
499
|
+
return value;
|
|
500
|
+
}
|
|
501
|
+
const visibleDigits = cleanedValue.slice(-4);
|
|
502
|
+
const maskedSection = '*'.repeat(cleanedLength - 4);
|
|
503
|
+
const groupedMask = maskedSection.match(/.{1,4}/g)?.join(' ') ?? '';
|
|
504
|
+
return `${groupedMask} ${visibleDigits}`.trim();
|
|
505
|
+
}
|
|
506
|
+
return value;
|
|
507
|
+
}
|
|
508
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: CreditCardMaskPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
509
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: CreditCardMaskPipe, isStandalone: true, name: "creditCardMask" });
|
|
510
|
+
}
|
|
511
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: CreditCardMaskPipe, decorators: [{
|
|
512
|
+
type: Pipe,
|
|
513
|
+
args: [{
|
|
514
|
+
name: 'creditCardMask',
|
|
515
|
+
standalone: true,
|
|
516
|
+
}]
|
|
517
|
+
}] });
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* EmailMaskPipe: Masks the local part of an email address, revealing only the first and last characters.
|
|
521
|
+
*
|
|
522
|
+
* This Angular pipe transforms an email address string by replacing the characters between the first and last characters of the local part (before the '@') with "***".
|
|
523
|
+
* If the local part is 2 characters or less, it masks all characters except the first.
|
|
524
|
+
*
|
|
525
|
+
* @param {string} value - The email address string to be masked.
|
|
526
|
+
* @returns {string} - The masked email address, or the original value if it's not a valid email or falsy.
|
|
527
|
+
*
|
|
528
|
+
* @example
|
|
529
|
+
* {{ 'test@example.com' | emailMask }} // Returns 't***t@example.com'
|
|
530
|
+
* {{ 'te@example.com' | emailMask }} // Returns 't***@example.com'
|
|
531
|
+
* {{ 't@example.com' | emailMask }} // Returns 't***@example.com'
|
|
532
|
+
* {{ 'example.com' | emailMask }} // Returns 'example.com'
|
|
533
|
+
* {{ null | emailMask }} // Returns ''
|
|
534
|
+
* {{ undefined | emailMask }} // Returns ''
|
|
535
|
+
*/
|
|
536
|
+
class EmailMaskPipe {
|
|
537
|
+
transform(value) {
|
|
538
|
+
if (!value || !value.includes('@')) {
|
|
539
|
+
return value || '';
|
|
540
|
+
}
|
|
541
|
+
const [local, domain] = value.split('@');
|
|
542
|
+
if (local.length <= 2) {
|
|
543
|
+
return `${local[0]}***@${domain}`;
|
|
544
|
+
}
|
|
545
|
+
const firstChar = local[0];
|
|
546
|
+
const lastChar = local[local.length - 1];
|
|
547
|
+
return `${firstChar}***${lastChar}@${domain}`;
|
|
548
|
+
}
|
|
549
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailMaskPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
550
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: EmailMaskPipe, isStandalone: true, name: "emailMask" });
|
|
551
|
+
}
|
|
552
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EmailMaskPipe, decorators: [{
|
|
553
|
+
type: Pipe,
|
|
554
|
+
args: [{
|
|
555
|
+
name: 'emailMask',
|
|
556
|
+
standalone: true
|
|
557
|
+
}]
|
|
558
|
+
}] });
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Converts special HTML characters in a string to their corresponding HTML entities.
|
|
562
|
+
* This prevents the browser from interpreting the input as HTML, rendering it as plain text.
|
|
563
|
+
*
|
|
564
|
+
* @param {string} value - The input string containing HTML to escape.
|
|
565
|
+
* @returns {string} The string with special HTML characters escaped, or an empty string if input is invalid.
|
|
566
|
+
*
|
|
567
|
+
* @example
|
|
568
|
+
* ```html
|
|
569
|
+
* {{ '<p>Hello</p>' | htmlEscape }} <!-- Outputs: <p>Hello</p> -->
|
|
570
|
+
* ```
|
|
571
|
+
*/
|
|
572
|
+
class HtmlEscapePipe {
|
|
573
|
+
transform(value) {
|
|
574
|
+
if (!value || typeof value !== 'string')
|
|
575
|
+
return '';
|
|
576
|
+
const escapeMap = {
|
|
577
|
+
'&': '&',
|
|
578
|
+
'<': '<',
|
|
579
|
+
'>': '>',
|
|
580
|
+
'"': '"',
|
|
581
|
+
"'": '''
|
|
582
|
+
};
|
|
583
|
+
return value.replace(/[&<>"']/g, char => escapeMap[char]);
|
|
584
|
+
}
|
|
585
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: HtmlEscapePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
586
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: HtmlEscapePipe, isStandalone: true, name: "htmlEscape" });
|
|
587
|
+
}
|
|
588
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: HtmlEscapePipe, decorators: [{
|
|
589
|
+
type: Pipe,
|
|
590
|
+
args: [{
|
|
591
|
+
name: 'htmlEscape',
|
|
592
|
+
standalone: true
|
|
593
|
+
}]
|
|
594
|
+
}] });
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Sanitizes HTML input to remove unsafe elements while allowing safe HTML to be rendered.
|
|
598
|
+
* Uses Angular's DomSanitizer to mark the output as trusted for use in [innerHTML].
|
|
599
|
+
*
|
|
600
|
+
* @param {string} value - The input string containing HTML to sanitize.
|
|
601
|
+
* @returns {SafeHtml} The sanitized HTML marked as safe, or an empty string if input is invalid.
|
|
602
|
+
*
|
|
603
|
+
* @remarks
|
|
604
|
+
* WARNING: Use with caution. Only apply to trusted input to avoid XSS risks.
|
|
605
|
+
* Ensure input is pre-validated or sourced from a secure origin (e.g., a controlled rich-text editor).
|
|
606
|
+
*
|
|
607
|
+
* @example
|
|
608
|
+
* ```html
|
|
609
|
+
* <div [innerHTML]="'<p>Hello</p><script>alert(1)</script>' | htmlSanitize"></div>
|
|
610
|
+
* <!-- Renders: <p>Hello</p> (script tag removed) -->
|
|
611
|
+
* ```
|
|
612
|
+
*/
|
|
613
|
+
class HtmlSanitizePipe {
|
|
614
|
+
sanitizer = inject(DomSanitizer);
|
|
615
|
+
transform(value) {
|
|
616
|
+
if (!value || typeof value !== 'string')
|
|
617
|
+
return this.sanitizer.bypassSecurityTrustHtml('');
|
|
618
|
+
return this.sanitizer.sanitize(0, value) || this.sanitizer.bypassSecurityTrustHtml('');
|
|
619
|
+
}
|
|
620
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: HtmlSanitizePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
621
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: HtmlSanitizePipe, isStandalone: true, name: "htmlSanitize" });
|
|
622
|
+
}
|
|
623
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: HtmlSanitizePipe, decorators: [{
|
|
624
|
+
type: Pipe,
|
|
625
|
+
args: [{
|
|
626
|
+
name: 'htmlSanitize',
|
|
627
|
+
standalone: true
|
|
628
|
+
}]
|
|
629
|
+
}] });
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* IpAddressMaskPipe: Masks the last two octets of an IPv4 address.
|
|
633
|
+
*
|
|
634
|
+
* @param {string} value - The IPv4 address (e.g., 192.168.1.1).
|
|
635
|
+
* @param {boolean} shouldMask - (Optional) Determines if masking should be applied. Defaults to true..
|
|
636
|
+
*
|
|
637
|
+
* @returns {string} - The masked IP address (e.g., 192.168.*.*).
|
|
638
|
+
*
|
|
639
|
+
* @example
|
|
640
|
+
* {{ '192.168.1.1' | ipAddressMask }} // Outputs: 192.168.*.*
|
|
641
|
+
* {{ '10.0.0.255' | ipAddressMask }} // Outputs: 10.0.*.*
|
|
642
|
+
*/
|
|
643
|
+
class IpAddressMaskPipe {
|
|
644
|
+
transform(value, shouldMask = true) {
|
|
645
|
+
if (!value || !/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(value)) {
|
|
646
|
+
return value;
|
|
647
|
+
}
|
|
648
|
+
if (shouldMask) {
|
|
649
|
+
const parts = value.split('.');
|
|
650
|
+
return `${parts[0]}.${parts[1]}.*.*`;
|
|
651
|
+
}
|
|
652
|
+
return value;
|
|
653
|
+
}
|
|
654
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: IpAddressMaskPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
655
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: IpAddressMaskPipe, isStandalone: true, name: "ipAddressMask" });
|
|
656
|
+
}
|
|
657
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: IpAddressMaskPipe, decorators: [{
|
|
658
|
+
type: Pipe,
|
|
659
|
+
args: [{
|
|
660
|
+
name: 'ipAddressMask',
|
|
661
|
+
standalone: true
|
|
662
|
+
}]
|
|
663
|
+
}] });
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* BarcodePipe: Generates a barcode from a string value.
|
|
667
|
+
*
|
|
668
|
+
* @param {string} value - The value to encode (e.g., '123456789').
|
|
669
|
+
* @param {BarcodeOptions} [options={}] - Configuration options.
|
|
670
|
+
*
|
|
671
|
+
* @returns {Promise<SafeHtml | SafeResourceUrl>} - SVG markup or image data URL.
|
|
672
|
+
*
|
|
673
|
+
* @example
|
|
674
|
+
* <div [innerHTML]="'123456789' | barcode:{elementType:'svg',format:'CODE128'} | async"></div>
|
|
675
|
+
* <img [src]="'123456789' | barcode:{elementType:'img'} | async" />
|
|
676
|
+
*/
|
|
677
|
+
class BarcodePipe {
|
|
678
|
+
sanitizer = inject(DomSanitizer);
|
|
679
|
+
async transform(value, options = {}) {
|
|
680
|
+
const { elementType = 'svg', format = 'CODE128', lineColor = '#000000', width = 2, height = 100, displayValue = true, } = options;
|
|
681
|
+
if (!value) {
|
|
682
|
+
return '';
|
|
683
|
+
}
|
|
684
|
+
// Sanitize the value to prevent XSS
|
|
685
|
+
const sanitizedValue = value.replace(/</g, '<').replace(/>/g, '>');
|
|
686
|
+
try {
|
|
687
|
+
const config = { format, lineColor, width, height, displayValue };
|
|
688
|
+
if (elementType === 'svg') {
|
|
689
|
+
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
690
|
+
JsBarcode(svg, sanitizedValue, config);
|
|
691
|
+
return this.sanitizer.bypassSecurityTrustHtml(svg.outerHTML);
|
|
692
|
+
}
|
|
693
|
+
else {
|
|
694
|
+
const canvas = document.createElement('canvas');
|
|
695
|
+
JsBarcode(canvas, sanitizedValue, config);
|
|
696
|
+
const dataUrl = canvas.toDataURL('image/png');
|
|
697
|
+
return this.sanitizer.bypassSecurityTrustResourceUrl(dataUrl);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
catch (error) {
|
|
701
|
+
console.error('Barcode generation failed:', error);
|
|
702
|
+
return '';
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BarcodePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
706
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: BarcodePipe, isStandalone: true, name: "barcode" });
|
|
707
|
+
}
|
|
708
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: BarcodePipe, decorators: [{
|
|
709
|
+
type: Pipe,
|
|
710
|
+
args: [{
|
|
711
|
+
name: 'barcode',
|
|
712
|
+
standalone: true,
|
|
713
|
+
}]
|
|
714
|
+
}] });
|
|
715
|
+
|
|
716
|
+
// Pre-compiled regex patterns for performance
|
|
717
|
+
const HEX_6_PATTERN = /^#([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/;
|
|
718
|
+
const HEX_8_PATTERN = /^#([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/;
|
|
719
|
+
const HEX_3_PATTERN = /^#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/;
|
|
720
|
+
const HEX_4_PATTERN = /^#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/;
|
|
721
|
+
const RGB_PATTERN = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i;
|
|
722
|
+
const RGBA_PATTERN = /^rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*([\d.]+)\s*\)$/i;
|
|
723
|
+
/**
|
|
724
|
+
* Clamps a value between 0 and 255 for valid RGB channel values.
|
|
725
|
+
*/
|
|
726
|
+
function clampChannel(value) {
|
|
727
|
+
return Math.max(0, Math.min(255, Math.round(value)));
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Clamps alpha value between 0 and 1.
|
|
731
|
+
*/
|
|
732
|
+
function clampAlpha(value) {
|
|
733
|
+
return Math.max(0, Math.min(1, value));
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Converts a single hex character to its full two-character representation.
|
|
737
|
+
*/
|
|
738
|
+
function expandHexChar(char) {
|
|
739
|
+
return char + char;
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Converts a number to a two-character hex string.
|
|
743
|
+
*/
|
|
744
|
+
function toHex(value) {
|
|
745
|
+
return clampChannel(value).toString(16).padStart(2, '0').toUpperCase();
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Converts alpha (0-1) to hex (00-FF).
|
|
749
|
+
*/
|
|
750
|
+
function alphaToHex(alpha) {
|
|
751
|
+
return Math.round(clampAlpha(alpha) * 255).toString(16).padStart(2, '0').toUpperCase();
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Converts hex alpha (00-FF) to decimal (0-1).
|
|
755
|
+
*/
|
|
756
|
+
function hexToAlpha(hex) {
|
|
757
|
+
return Math.round((parseInt(hex, 16) / 255) * 100) / 100;
|
|
255
758
|
}
|
|
256
759
|
/**
|
|
257
760
|
* Parses any supported color format into RGBA components.
|
|
@@ -361,8 +864,6 @@ function parseColor(value) {
|
|
|
361
864
|
* // Alpha channel support
|
|
362
865
|
* {{ '#FF000080' | colorConvert:'rgba' }} // rgba(255, 0, 0, 0.5)
|
|
363
866
|
* {{ 'rgba(255, 0, 0, 0.5)' | colorConvert:'hex' }} // #FF000080
|
|
364
|
-
*
|
|
365
|
-
* @author Mofiro Jean
|
|
366
867
|
*/
|
|
367
868
|
class ColorConvertPipe {
|
|
368
869
|
transform(value, target) {
|
|
@@ -395,8 +896,66 @@ class ColorConvertPipe {
|
|
|
395
896
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ColorConvertPipe, decorators: [{
|
|
396
897
|
type: Pipe,
|
|
397
898
|
args: [{
|
|
398
|
-
name: 'colorConvert',
|
|
399
|
-
standalone: true,
|
|
899
|
+
name: 'colorConvert',
|
|
900
|
+
standalone: true,
|
|
901
|
+
}]
|
|
902
|
+
}] });
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* GravatarPipe: Generates Gravatar URLs from email addresses.
|
|
906
|
+
*
|
|
907
|
+
* @param {string} value - The email address.
|
|
908
|
+
* @param {number} [size=80] - The avatar size in pixels.
|
|
909
|
+
*
|
|
910
|
+
* @returns {string} - The Gravatar URL.
|
|
911
|
+
*
|
|
912
|
+
* @example
|
|
913
|
+
* <img [src]="'user@example.com' | gravatar:100" />
|
|
914
|
+
*/
|
|
915
|
+
class GravatarPipe {
|
|
916
|
+
transform(value, size = 80) {
|
|
917
|
+
if (!value)
|
|
918
|
+
return `https://www.gravatar.com/avatar/?s=${size}`;
|
|
919
|
+
const hash = md5(value.trim().toLowerCase());
|
|
920
|
+
return `https://www.gravatar.com/avatar/${hash}?s=${size}`;
|
|
921
|
+
}
|
|
922
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: GravatarPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
923
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: GravatarPipe, isStandalone: true, name: "gravatar" });
|
|
924
|
+
}
|
|
925
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: GravatarPipe, decorators: [{
|
|
926
|
+
type: Pipe,
|
|
927
|
+
args: [{
|
|
928
|
+
name: 'gravatar',
|
|
929
|
+
standalone: true
|
|
930
|
+
}]
|
|
931
|
+
}] });
|
|
932
|
+
|
|
933
|
+
/**
|
|
934
|
+
* QrCodePipe: Generates a QR code from a string.
|
|
935
|
+
*
|
|
936
|
+
* @param {string} value - The string to encode.
|
|
937
|
+
* @param {QrCodeOptions} [options] - The QR code options.
|
|
938
|
+
*
|
|
939
|
+
* @returns {Promise<string>} - A promise that resolves with the QR code data URL.
|
|
940
|
+
*
|
|
941
|
+
* @example
|
|
942
|
+
* <img [src]="'Hello, World!' | qrCode | async" />
|
|
943
|
+
*/
|
|
944
|
+
class QrCodePipe {
|
|
945
|
+
transform(value, options) {
|
|
946
|
+
if (!value) {
|
|
947
|
+
return Promise.resolve('');
|
|
948
|
+
}
|
|
949
|
+
return QRCode.toDataURL(value, options);
|
|
950
|
+
}
|
|
951
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: QrCodePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
952
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: QrCodePipe, isStandalone: true, name: "qrCode" });
|
|
953
|
+
}
|
|
954
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: QrCodePipe, decorators: [{
|
|
955
|
+
type: Pipe,
|
|
956
|
+
args: [{
|
|
957
|
+
name: 'qrCode',
|
|
958
|
+
standalone: true
|
|
400
959
|
}]
|
|
401
960
|
}] });
|
|
402
961
|
|
|
@@ -424,51 +983,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
424
983
|
}]
|
|
425
984
|
}] });
|
|
426
985
|
|
|
427
|
-
/**
|
|
428
|
-
* CreditCardMaskPipe: Masks all but the last four digits of a string, optionally controlled by a boolean flag.
|
|
429
|
-
* By default, masking is applied.
|
|
430
|
-
*
|
|
431
|
-
* @param {string} value - The input string to mask (e.g., credit card number).
|
|
432
|
-
* @param {boolean} shouldMask - (Optional) Determines if masking should be applied. Defaults to true.
|
|
433
|
-
* @returns {string} - The masked string or the original value if `shouldMask` is false or the value is too short.
|
|
434
|
-
*
|
|
435
|
-
* @example
|
|
436
|
-
* {{ '1234567890123456' | creditCardMask }} // Outputs: **** **** **** 3456
|
|
437
|
-
* {{ '1234-5678-9012-3456' | creditCardMask }} // Outputs: **** **** **** 3456
|
|
438
|
-
* {{ '1234567890123456' | creditCardMask: true }} // Outputs: **** **** **** 3456
|
|
439
|
-
* {{ '1234567890123456' | creditCardMask: false }} // Outputs: 1234567890123456
|
|
440
|
-
*
|
|
441
|
-
* @author Mofiro Jean
|
|
442
|
-
*/
|
|
443
|
-
class CreditCardMaskPipe {
|
|
444
|
-
transform(value, shouldMask = true) {
|
|
445
|
-
if (!value) {
|
|
446
|
-
return value;
|
|
447
|
-
}
|
|
448
|
-
if (shouldMask) {
|
|
449
|
-
const cleanedValue = value.replace(/[\s-]/g, '');
|
|
450
|
-
const cleanedLength = cleanedValue.length;
|
|
451
|
-
if (cleanedLength < 4) {
|
|
452
|
-
return value;
|
|
453
|
-
}
|
|
454
|
-
const visibleDigits = cleanedValue.slice(-4);
|
|
455
|
-
const maskedSection = '*'.repeat(cleanedLength - 4);
|
|
456
|
-
const groupedMask = maskedSection.match(/.{1,4}/g)?.join(' ') ?? '';
|
|
457
|
-
return `${groupedMask} ${visibleDigits}`.trim();
|
|
458
|
-
}
|
|
459
|
-
return value;
|
|
460
|
-
}
|
|
461
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: CreditCardMaskPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
462
|
-
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: CreditCardMaskPipe, isStandalone: true, name: "creditCardMask" });
|
|
463
|
-
}
|
|
464
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: CreditCardMaskPipe, decorators: [{
|
|
465
|
-
type: Pipe,
|
|
466
|
-
args: [{
|
|
467
|
-
name: 'creditCardMask',
|
|
468
|
-
standalone: true,
|
|
469
|
-
}]
|
|
470
|
-
}] });
|
|
471
|
-
|
|
472
986
|
/**
|
|
473
987
|
* DeviceTypePipe: Detects the device type based on the user agent string.
|
|
474
988
|
*
|
|
@@ -505,741 +1019,1088 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
505
1019
|
}] });
|
|
506
1020
|
|
|
507
1021
|
/**
|
|
508
|
-
*
|
|
1022
|
+
* JsonPrettyPipe: Formats JSON data with indentation and syntax highlighting.
|
|
509
1023
|
*
|
|
510
|
-
*
|
|
511
|
-
*
|
|
1024
|
+
* @param {string | object} value - The JSON string or object to format.
|
|
1025
|
+
* @param {number} [spaces=2] - Number of spaces for indentation.
|
|
512
1026
|
*
|
|
513
|
-
* @
|
|
514
|
-
* @returns {string} - The masked email address, or the original value if it's not a valid email or falsy.
|
|
1027
|
+
* @returns {SafeHtml} - Formatted HTML with color-coded JSON.
|
|
515
1028
|
*
|
|
516
1029
|
* @example
|
|
517
|
-
* {{ '
|
|
518
|
-
*
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
1030
|
+
* {{ '{"name": "John", "age": 30}' | jsonPretty }} // Outputs: Colorful, indented JSON
|
|
1031
|
+
* <pre [innerHTML]="data | jsonPretty:4"></pre> // 4-space indentation
|
|
1032
|
+
*/
|
|
1033
|
+
class JsonPrettyPipe {
|
|
1034
|
+
sanitizer = inject(DomSanitizer);
|
|
1035
|
+
transform(value, spaces = 2, highlightProperty) {
|
|
1036
|
+
let jsonString;
|
|
1037
|
+
try {
|
|
1038
|
+
if (typeof value === 'object') {
|
|
1039
|
+
jsonString = JSON.stringify(value, null, spaces);
|
|
1040
|
+
}
|
|
1041
|
+
else if (value && typeof value === 'string') {
|
|
1042
|
+
jsonString = JSON.stringify(JSON.parse(value), null, spaces);
|
|
1043
|
+
}
|
|
1044
|
+
else {
|
|
1045
|
+
throw new Error('Invalid or empty input');
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
catch (e) {
|
|
1049
|
+
return this.sanitizer.bypassSecurityTrustHtml('<span class="json-error">Invalid JSON: ' + (e instanceof Error ? e.message : 'Unknown error') + '</span>');
|
|
1050
|
+
}
|
|
1051
|
+
const escapedJson = jsonString
|
|
1052
|
+
.replace(/&/g, '&')
|
|
1053
|
+
.replace(/</g, '<')
|
|
1054
|
+
.replace(/>/g, '>');
|
|
1055
|
+
let finalJson = this.highlightJson(escapedJson);
|
|
1056
|
+
if (highlightProperty) {
|
|
1057
|
+
const lines = finalJson.split('\n');
|
|
1058
|
+
const highlightedLines = lines.map(line => {
|
|
1059
|
+
const searchString = `<span class="json-key">"${highlightProperty}"</span>`;
|
|
1060
|
+
if (line.includes(searchString)) {
|
|
1061
|
+
return `<span class="highlight-line">${line}</span>`;
|
|
1062
|
+
}
|
|
1063
|
+
return line;
|
|
1064
|
+
});
|
|
1065
|
+
finalJson = highlightedLines.join('\n');
|
|
1066
|
+
}
|
|
1067
|
+
return this.sanitizer.bypassSecurityTrustHtml(`<pre class="json-pretty">${finalJson}</pre>`);
|
|
1068
|
+
}
|
|
1069
|
+
highlightJson(json) {
|
|
1070
|
+
let result = json.replace(/"([^"\\]*(?:\\.[^"\\]*)*)"/g, (match, p1, offset) => {
|
|
1071
|
+
const remainingString = json.substring(offset + match.length);
|
|
1072
|
+
const isKey = /^\s*:/.test(remainingString);
|
|
1073
|
+
return isKey
|
|
1074
|
+
? `<span class="json-key">${match}</span>`
|
|
1075
|
+
: `<span class="json-string">${match}</span>`;
|
|
1076
|
+
});
|
|
1077
|
+
// Highlight numbers
|
|
1078
|
+
result = result.replace(/\b-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b/g, '<span class="json-number">$&</span>');
|
|
1079
|
+
// Highlight booleans
|
|
1080
|
+
result = result.replace(/\b(true|false)\b/g, '<span class="json-boolean">$&</span>');
|
|
1081
|
+
// Highlight null
|
|
1082
|
+
result = result.replace(/\bnull\b/g, '<span class="json-null">$&</span>');
|
|
1083
|
+
// Highlight punctuation
|
|
1084
|
+
result = result.replace(/[{}[\]]/g, '<span class="json-punctuation">$&</span>');
|
|
1085
|
+
return result;
|
|
1086
|
+
}
|
|
1087
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: JsonPrettyPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1088
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: JsonPrettyPipe, isStandalone: true, name: "jsonPretty" });
|
|
1089
|
+
}
|
|
1090
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: JsonPrettyPipe, decorators: [{
|
|
1091
|
+
type: Pipe,
|
|
1092
|
+
args: [{
|
|
1093
|
+
name: 'jsonPretty',
|
|
1094
|
+
standalone: true
|
|
1095
|
+
}]
|
|
1096
|
+
}] });
|
|
1097
|
+
|
|
1098
|
+
/**
|
|
1099
|
+
* TextToSpeechPipe: Converts text to speech using the Web Speech API.
|
|
1100
|
+
*
|
|
1101
|
+
* @param {string} value - The text to convert to speech.
|
|
1102
|
+
* @param {string} [lang='en-US'] - The language (local) for speech synthesis.
|
|
1103
|
+
*
|
|
1104
|
+
* @returns {void} - Triggers speech synthesis (no return value).
|
|
523
1105
|
*
|
|
524
|
-
* @
|
|
1106
|
+
* @example
|
|
1107
|
+
* <div>{{ Hello World' | textToSpeech }}</div>
|
|
1108
|
+
* <div>{{ 'Bonjour' | textToSpeech:'fr-FR' }}h</div>
|
|
525
1109
|
*/
|
|
526
|
-
class
|
|
527
|
-
transform(value) {
|
|
528
|
-
if (!value || !
|
|
529
|
-
return
|
|
1110
|
+
class TextToSpeechPipe {
|
|
1111
|
+
transform(value, lang = 'en-US') {
|
|
1112
|
+
if (!value || typeof window === 'undefined' || !window.speechSynthesis)
|
|
1113
|
+
return;
|
|
1114
|
+
const uttrance = new SpeechSynthesisUtterance(value);
|
|
1115
|
+
uttrance.lang = lang;
|
|
1116
|
+
window.speechSynthesis.speak(uttrance);
|
|
1117
|
+
}
|
|
1118
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: TextToSpeechPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1119
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: TextToSpeechPipe, isStandalone: true, name: "textToSpeech" });
|
|
1120
|
+
}
|
|
1121
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: TextToSpeechPipe, decorators: [{
|
|
1122
|
+
type: Pipe,
|
|
1123
|
+
args: [{
|
|
1124
|
+
name: 'textToSpeech',
|
|
1125
|
+
standalone: true
|
|
1126
|
+
}]
|
|
1127
|
+
}] });
|
|
1128
|
+
|
|
1129
|
+
/**
|
|
1130
|
+
* TimeAgo: Converts a date into a localized time string.
|
|
1131
|
+
*
|
|
1132
|
+
* Use the in-built Intl.RelativeTimeFormat to convert a date into a localized time string.
|
|
1133
|
+
* It was chosen over moment.js because it's more lightweight and supports more locales.
|
|
1134
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat
|
|
1135
|
+
*
|
|
1136
|
+
* @param {Date | number | string} value - The date to convert.
|
|
1137
|
+
* @param {string} [local='en'] - BCP 47 local code (e.g., 'en', 'fr', 'es').
|
|
1138
|
+
*
|
|
1139
|
+
* @returns {string} - The localized time string.
|
|
1140
|
+
*
|
|
1141
|
+
* @example
|
|
1142
|
+
* {{ date | timeAgo }} // '5 minutes ago'
|
|
1143
|
+
* {{ date | timeAgo:'fr' }} // 'il y a 5 minutes'
|
|
1144
|
+
*
|
|
1145
|
+
* @note Pure pipe - output won't automatically update as time passes.
|
|
1146
|
+
* Use signals or periodic change detection to re-trigger.
|
|
1147
|
+
* */
|
|
1148
|
+
class TimeAgoPipePipe {
|
|
1149
|
+
static THRESHOLDS = [
|
|
1150
|
+
[60, 1, 'second'],
|
|
1151
|
+
[3600, 60, 'minute'],
|
|
1152
|
+
[86400, 3600, 'hour'],
|
|
1153
|
+
[604800, 86400, 'day'],
|
|
1154
|
+
[2592000, 604800, 'week'],
|
|
1155
|
+
[31536000, 2592000, 'month'],
|
|
1156
|
+
[Infinity, 31536000, 'year'],
|
|
1157
|
+
];
|
|
1158
|
+
cacheLocal = '';
|
|
1159
|
+
rtf;
|
|
1160
|
+
transform(value, local = 'en') {
|
|
1161
|
+
if (value === null || value === undefined || value === "") {
|
|
1162
|
+
return "";
|
|
530
1163
|
}
|
|
531
|
-
const
|
|
532
|
-
if (
|
|
533
|
-
return
|
|
1164
|
+
const date = new Date(value);
|
|
1165
|
+
if (isNaN(date.getTime())) {
|
|
1166
|
+
return "";
|
|
534
1167
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
1168
|
+
if (local !== this.cacheLocal) {
|
|
1169
|
+
this.rtf = new Intl.RelativeTimeFormat(local, { numeric: "auto" });
|
|
1170
|
+
this.cacheLocal = local;
|
|
1171
|
+
}
|
|
1172
|
+
const seconds = Math.floor((date.getTime() - Date.now()) / 1000);
|
|
1173
|
+
for (const [max, divisor, unit] of TimeAgoPipePipe.THRESHOLDS) {
|
|
1174
|
+
if (Math.abs(seconds) < max) {
|
|
1175
|
+
return this.rtf.format(Math.round(seconds / divisor), unit);
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
return "";
|
|
538
1179
|
}
|
|
539
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
540
|
-
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1180
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: TimeAgoPipePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1181
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: TimeAgoPipePipe, isStandalone: true, name: "timeAgo" });
|
|
541
1182
|
}
|
|
542
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1183
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: TimeAgoPipePipe, decorators: [{
|
|
543
1184
|
type: Pipe,
|
|
544
1185
|
args: [{
|
|
545
|
-
name: '
|
|
1186
|
+
name: 'timeAgo',
|
|
546
1187
|
standalone: true
|
|
547
1188
|
}]
|
|
548
1189
|
}] });
|
|
549
1190
|
|
|
550
1191
|
/**
|
|
551
|
-
*
|
|
1192
|
+
* DiffPipe: Returns elements present in the first array but not in the second.
|
|
552
1193
|
*
|
|
553
|
-
*
|
|
554
|
-
* @param {number} [size=80] - The avatar size in pixels.
|
|
1194
|
+
* Supports primitives and objects by property key with dot notation.
|
|
555
1195
|
*
|
|
556
|
-
* @
|
|
1196
|
+
* @param {unknown[]} value - The source array.
|
|
1197
|
+
* @param {unknown[]} compared - The array to compare against.
|
|
1198
|
+
* @param {string} [key] - Optional property path for object comparison (supports dot notation).
|
|
1199
|
+
*
|
|
1200
|
+
* @returns {unknown[]} - Elements in value that are not in compared.
|
|
557
1201
|
*
|
|
558
1202
|
* @example
|
|
559
|
-
*
|
|
1203
|
+
* {{ [1, 2, 3, 4, 5] | diff:[3, 4, 5, 6] }} // [1, 2]
|
|
1204
|
+
* {{ allUsers | diff:activeUsers:'id' }} // inactive users
|
|
1205
|
+
* {{ orders | diff:shipped:'meta.trackingId' }} // unshipped orders
|
|
1206
|
+
*/
|
|
1207
|
+
class DiffPipe {
|
|
1208
|
+
transform(value, compared, key) {
|
|
1209
|
+
if (!Array.isArray(value)) {
|
|
1210
|
+
return [];
|
|
1211
|
+
}
|
|
1212
|
+
if (!Array.isArray(compared) || compared.length === 0) {
|
|
1213
|
+
return [...value];
|
|
1214
|
+
}
|
|
1215
|
+
if (!key) {
|
|
1216
|
+
const comparedSet = new Set(compared);
|
|
1217
|
+
return value.filter(item => !comparedSet.has(item));
|
|
1218
|
+
}
|
|
1219
|
+
const comparedSet = new Set(compared.map(item => this.getNestedValue(item, key)));
|
|
1220
|
+
return value.filter(item => {
|
|
1221
|
+
const val = this.getNestedValue(item, key);
|
|
1222
|
+
return !comparedSet.has(val);
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
getNestedValue(obj, path) {
|
|
1226
|
+
return path.split('.').reduce((current, segment) => current?.[segment], obj);
|
|
1227
|
+
}
|
|
1228
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: DiffPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1229
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: DiffPipe, isStandalone: true, name: "diff" });
|
|
1230
|
+
}
|
|
1231
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: DiffPipe, decorators: [{
|
|
1232
|
+
type: Pipe,
|
|
1233
|
+
args: [{
|
|
1234
|
+
name: 'diff',
|
|
1235
|
+
standalone: true,
|
|
1236
|
+
}]
|
|
1237
|
+
}] });
|
|
1238
|
+
|
|
1239
|
+
/**
|
|
1240
|
+
* EveryPipe: Checks if all elements in an array satisfy a condition.
|
|
1241
|
+
*
|
|
1242
|
+
* Supports primitives (equality check) and objects by property key with dot notation.
|
|
1243
|
+
*
|
|
1244
|
+
* @param {unknown[]} value - The array to check.
|
|
1245
|
+
* @param {unknown} match - The value to match against.
|
|
1246
|
+
* @param {string} [key] - Optional property path to check (supports dot notation).
|
|
1247
|
+
*
|
|
1248
|
+
* @returns {boolean} - True if all elements match, false otherwise.
|
|
560
1249
|
*
|
|
561
|
-
* @
|
|
1250
|
+
* @example
|
|
1251
|
+
* {{ [true, true, true] | every:true }} // true
|
|
1252
|
+
* {{ users | every:'active':'status' }} // are all users active?
|
|
1253
|
+
* {{ orders | every:'shipped':'meta.state' }} // are all orders shipped?
|
|
562
1254
|
*/
|
|
563
|
-
class
|
|
564
|
-
transform(value,
|
|
565
|
-
if (!value)
|
|
566
|
-
return
|
|
567
|
-
|
|
568
|
-
|
|
1255
|
+
class EveryPipe {
|
|
1256
|
+
transform(value, match, key) {
|
|
1257
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
1258
|
+
return false;
|
|
1259
|
+
}
|
|
1260
|
+
if (!key) {
|
|
1261
|
+
return value.every(item => item === match);
|
|
1262
|
+
}
|
|
1263
|
+
return value.every(item => this.getNestedValue(item, key) === match);
|
|
1264
|
+
}
|
|
1265
|
+
getNestedValue(obj, path) {
|
|
1266
|
+
return path.split('.').reduce((current, segment) => current?.[segment], obj);
|
|
1267
|
+
}
|
|
1268
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EveryPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1269
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: EveryPipe, isStandalone: true, name: "every" });
|
|
1270
|
+
}
|
|
1271
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: EveryPipe, decorators: [{
|
|
1272
|
+
type: Pipe,
|
|
1273
|
+
args: [{
|
|
1274
|
+
name: 'every',
|
|
1275
|
+
standalone: true,
|
|
1276
|
+
}]
|
|
1277
|
+
}] });
|
|
1278
|
+
|
|
1279
|
+
/**
|
|
1280
|
+
* IntersectionPipe: Returns elements common to both arrays.
|
|
1281
|
+
*
|
|
1282
|
+
* Supports primitives and objects by property key with dot notation.
|
|
1283
|
+
*
|
|
1284
|
+
* @param {unknown[]} value - The first array.
|
|
1285
|
+
* @param {unknown[]} compared - The second array.
|
|
1286
|
+
* @param {string} [key] - Optional property path for object comparison (supports dot notation).
|
|
1287
|
+
*
|
|
1288
|
+
* @returns {unknown[]} - Elements present in both arrays.
|
|
1289
|
+
*
|
|
1290
|
+
* @example
|
|
1291
|
+
* {{ [1, 2, 3, 4] | intersection:[3, 4, 5, 6] }} // [3, 4]
|
|
1292
|
+
* {{ teamA | intersection:teamB:'id' }} // shared members
|
|
1293
|
+
* {{ required | intersection:granted:'meta.scope' }} // matched permissions
|
|
1294
|
+
*/
|
|
1295
|
+
class IntersectionPipe {
|
|
1296
|
+
transform(value, compared, key) {
|
|
1297
|
+
if (!Array.isArray(value)) {
|
|
1298
|
+
return [];
|
|
1299
|
+
}
|
|
1300
|
+
if (!Array.isArray(compared) || compared.length === 0) {
|
|
1301
|
+
return [];
|
|
1302
|
+
}
|
|
1303
|
+
if (!key) {
|
|
1304
|
+
const comparedSet = new Set(compared);
|
|
1305
|
+
return value.filter(item => comparedSet.has(item));
|
|
1306
|
+
}
|
|
1307
|
+
const comparedSet = new Set(compared.map(item => this.getNestedValue(item, key)));
|
|
1308
|
+
return value.filter(item => {
|
|
1309
|
+
const val = this.getNestedValue(item, key);
|
|
1310
|
+
return comparedSet.has(val);
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1313
|
+
getNestedValue(obj, path) {
|
|
1314
|
+
return path.split('.').reduce((current, segment) => current?.[segment], obj);
|
|
1315
|
+
}
|
|
1316
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: IntersectionPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1317
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: IntersectionPipe, isStandalone: true, name: "intersection" });
|
|
1318
|
+
}
|
|
1319
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: IntersectionPipe, decorators: [{
|
|
1320
|
+
type: Pipe,
|
|
1321
|
+
args: [{
|
|
1322
|
+
name: 'intersection',
|
|
1323
|
+
standalone: true,
|
|
1324
|
+
}]
|
|
1325
|
+
}] });
|
|
1326
|
+
|
|
1327
|
+
/**
|
|
1328
|
+
* ChunkPipe: Splits an array into smaller arrays of a specified size.
|
|
1329
|
+
*
|
|
1330
|
+
* @param {unknown[]} value - The array to split.
|
|
1331
|
+
* @param {number} [size=1] - The size of each chunk.
|
|
1332
|
+
*
|
|
1333
|
+
* @returns {unknown[][]} - An array of chunks.
|
|
1334
|
+
*
|
|
1335
|
+
* @example
|
|
1336
|
+
* {{ [1, 2, 3, 4, 5] | chunk:2 }} // [[1, 2], [3, 4], [5]]
|
|
1337
|
+
* {{ [1, 2, 3, 4, 5, 6] | chunk:3 }} // [[1, 2, 3], [4, 5, 6]]
|
|
1338
|
+
*/
|
|
1339
|
+
class ChunkPipe {
|
|
1340
|
+
transform(value, size = 1) {
|
|
1341
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
1342
|
+
return [];
|
|
1343
|
+
}
|
|
1344
|
+
if (size <= 0) {
|
|
1345
|
+
return [];
|
|
1346
|
+
}
|
|
1347
|
+
const result = [];
|
|
1348
|
+
for (let i = 0; i < value.length; i += size) {
|
|
1349
|
+
result.push(value.slice(i, i + size));
|
|
1350
|
+
}
|
|
1351
|
+
return result;
|
|
569
1352
|
}
|
|
570
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
571
|
-
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1353
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ChunkPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1354
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: ChunkPipe, isStandalone: true, name: "chunk" });
|
|
572
1355
|
}
|
|
573
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1356
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ChunkPipe, decorators: [{
|
|
574
1357
|
type: Pipe,
|
|
575
1358
|
args: [{
|
|
576
|
-
name: '
|
|
1359
|
+
name: 'chunk',
|
|
577
1360
|
standalone: true
|
|
578
1361
|
}]
|
|
579
1362
|
}] });
|
|
580
1363
|
|
|
581
1364
|
/**
|
|
582
|
-
*
|
|
1365
|
+
* FlattenPipe: Flattens nested arrays to a specified depth.
|
|
583
1366
|
*
|
|
584
|
-
*
|
|
585
|
-
*
|
|
586
|
-
* It uses the Angular `DomSanitizer` to bypass security and render the highlighted HTML.
|
|
1367
|
+
* @param {unknown[]} value - The nested array to flatten.
|
|
1368
|
+
* @param {number} [depth=Infinity] - How many levels of nesting to flatten.
|
|
587
1369
|
*
|
|
588
|
-
* @
|
|
589
|
-
* @param {string} searchTerm - The string to search for and highlight.
|
|
590
|
-
* @returns {SafeHtml} - The input string with the search term highlighted, or an empty string if input or searchTerm are falsy.
|
|
1370
|
+
* @returns {unknown[]} - A new flattened array.
|
|
591
1371
|
*
|
|
592
1372
|
* @example
|
|
593
|
-
* {{
|
|
594
|
-
* {{
|
|
595
|
-
* {{ '
|
|
596
|
-
* {{ null | highlight: 'test' }} // Returns ''
|
|
597
|
-
* {{ undefined | highlight: 'test' }} // Returns ''
|
|
598
|
-
*
|
|
599
|
-
* @author Mofiro Jean
|
|
1373
|
+
* {{ [[1, 2], [3, 4]] | flatten }} // [1, 2, 3, 4]
|
|
1374
|
+
* {{ [[1, [2, [3]]]] | flatten:1 }} // [1, 2, [3]]
|
|
1375
|
+
* {{ [['a', 'b'], ['c']] | flatten }} // ['a', 'b', 'c']
|
|
600
1376
|
*/
|
|
601
|
-
class
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
return this.sanitizer.bypassSecurityTrustHtml(value || '');
|
|
1377
|
+
class Flatten {
|
|
1378
|
+
transform(value, depth = Infinity) {
|
|
1379
|
+
if (!Array.isArray(value)) {
|
|
1380
|
+
return [];
|
|
606
1381
|
}
|
|
607
|
-
|
|
608
|
-
const regex = new RegExp(`(${escapedSearch})`, 'gi');
|
|
609
|
-
const highlighed = value.replace(regex, '<span class="highlight">$1</span>');
|
|
610
|
-
return this.sanitizer.bypassSecurityTrustHtml(highlighed);
|
|
1382
|
+
return value.flat(depth);
|
|
611
1383
|
}
|
|
612
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
613
|
-
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1384
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: Flatten, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1385
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: Flatten, isStandalone: true, name: "flatten" });
|
|
614
1386
|
}
|
|
615
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1387
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: Flatten, decorators: [{
|
|
616
1388
|
type: Pipe,
|
|
617
1389
|
args: [{
|
|
618
|
-
name: '
|
|
1390
|
+
name: 'flatten',
|
|
619
1391
|
standalone: true
|
|
620
1392
|
}]
|
|
621
1393
|
}] });
|
|
622
1394
|
|
|
623
1395
|
/**
|
|
624
|
-
*
|
|
625
|
-
* This prevents the browser from interpreting the input as HTML, rendering it as plain text.
|
|
1396
|
+
* GroupByPipe: Groups array elements by a property value.
|
|
626
1397
|
*
|
|
627
|
-
* @param {
|
|
628
|
-
* @
|
|
1398
|
+
* @param {unknown[]} value - The array to group.
|
|
1399
|
+
* @param {string} key - Property path to group by (supports dot notation).
|
|
1400
|
+
*
|
|
1401
|
+
* @returns {Record<string, unknown[]>} - An object where keys are group names and values are arrays.
|
|
629
1402
|
*
|
|
630
1403
|
* @example
|
|
631
|
-
*
|
|
632
|
-
* {{
|
|
633
|
-
* ```
|
|
1404
|
+
* {{ users | groupBy:'role' }} // { admin: [...], editor: [...] }
|
|
1405
|
+
* {{ orders | groupBy:'customer.city' }} // { 'New York': [...], 'London': [...] }
|
|
634
1406
|
*/
|
|
635
|
-
class
|
|
636
|
-
transform(value) {
|
|
637
|
-
if (!value ||
|
|
638
|
-
return
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
'
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
1407
|
+
class GroupByPipe {
|
|
1408
|
+
transform(value, key) {
|
|
1409
|
+
if (!Array.isArray(value) || !key) {
|
|
1410
|
+
return {};
|
|
1411
|
+
}
|
|
1412
|
+
return value.reduce((groups, item) => {
|
|
1413
|
+
const groupKey = String(this.getNestedValue(item, key) ?? 'undefined');
|
|
1414
|
+
if (!groups[groupKey]) {
|
|
1415
|
+
groups[groupKey] = [];
|
|
1416
|
+
}
|
|
1417
|
+
groups[groupKey].push(item);
|
|
1418
|
+
return groups;
|
|
1419
|
+
}, {});
|
|
647
1420
|
}
|
|
648
|
-
|
|
649
|
-
|
|
1421
|
+
getNestedValue(obj, path) {
|
|
1422
|
+
return path.split('.').reduce((current, segment) => current?.[segment], obj);
|
|
1423
|
+
}
|
|
1424
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: GroupByPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1425
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: GroupByPipe, isStandalone: true, name: "groupBy" });
|
|
650
1426
|
}
|
|
651
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1427
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: GroupByPipe, decorators: [{
|
|
652
1428
|
type: Pipe,
|
|
653
1429
|
args: [{
|
|
654
|
-
name: '
|
|
655
|
-
standalone: true
|
|
1430
|
+
name: 'groupBy',
|
|
1431
|
+
standalone: true,
|
|
656
1432
|
}]
|
|
657
1433
|
}] });
|
|
658
1434
|
|
|
659
1435
|
/**
|
|
660
|
-
*
|
|
661
|
-
* Uses Angular's DomSanitizer to mark the output as trusted for use in [innerHTML].
|
|
1436
|
+
* InitialPipe: Returns all elements except the last n.
|
|
662
1437
|
*
|
|
663
|
-
* @param {
|
|
664
|
-
* @
|
|
1438
|
+
* @param {unknown[]} value - The array to slice.
|
|
1439
|
+
* @param {number} [n=1] - Number of elements to exclude from the end.
|
|
665
1440
|
*
|
|
666
|
-
* @
|
|
667
|
-
* WARNING: Use with caution. Only apply to trusted input to avoid XSS risks.
|
|
668
|
-
* Ensure input is pre-validated or sourced from a secure origin (e.g., a controlled rich-text editor).
|
|
1441
|
+
* @returns {unknown[]} - A new array without the last n elements.
|
|
669
1442
|
*
|
|
670
1443
|
* @example
|
|
671
|
-
*
|
|
672
|
-
*
|
|
673
|
-
*
|
|
674
|
-
* ```
|
|
1444
|
+
* {{ [1, 2, 3, 4, 5] | initial }} // [1, 2, 3, 4]
|
|
1445
|
+
* {{ [1, 2, 3, 4, 5] | initial:2 }} // [1, 2, 3]
|
|
1446
|
+
* {{ ['a', 'b', 'c'] | initial }} // ['a', 'b']
|
|
675
1447
|
*/
|
|
676
|
-
class
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
1448
|
+
class InitialPipe {
|
|
1449
|
+
transform(value, n = 1) {
|
|
1450
|
+
if (!Array.isArray(value)) {
|
|
1451
|
+
return [];
|
|
1452
|
+
}
|
|
1453
|
+
if (n <= 0) {
|
|
1454
|
+
return [...value];
|
|
1455
|
+
}
|
|
1456
|
+
if (n >= value.length) {
|
|
1457
|
+
return [];
|
|
1458
|
+
}
|
|
1459
|
+
return value.slice(0, -n);
|
|
682
1460
|
}
|
|
683
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
684
|
-
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1461
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: InitialPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1462
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: InitialPipe, isStandalone: true, name: "initial" });
|
|
685
1463
|
}
|
|
686
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1464
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: InitialPipe, decorators: [{
|
|
687
1465
|
type: Pipe,
|
|
688
1466
|
args: [{
|
|
689
|
-
name: '
|
|
1467
|
+
name: 'initial',
|
|
690
1468
|
standalone: true
|
|
691
1469
|
}]
|
|
692
1470
|
}] });
|
|
693
1471
|
|
|
694
1472
|
/**
|
|
695
|
-
*
|
|
1473
|
+
* OrderByPipe: Sorts an array by a property value.
|
|
696
1474
|
*
|
|
697
|
-
* @param {
|
|
1475
|
+
* @param {unknown[]} value - The array to sort.
|
|
1476
|
+
* @param {string} key - Property path to sort by (supports dot notation).
|
|
1477
|
+
* @param {string} [direction='asc'] - Sort direction: 'asc' or 'desc'.
|
|
698
1478
|
*
|
|
699
|
-
* @returns {
|
|
1479
|
+
* @returns {unknown[]} - A new sorted array.
|
|
700
1480
|
*
|
|
701
1481
|
* @example
|
|
702
|
-
* {{
|
|
703
|
-
* {{
|
|
704
|
-
*
|
|
705
|
-
* @author Mofiro Jean
|
|
1482
|
+
* {{ users | orderBy:'name' }} // sorted A-Z
|
|
1483
|
+
* {{ users | orderBy:'name':'desc' }} // sorted Z-A
|
|
1484
|
+
* {{ users | orderBy:'age':'asc' }} // sorted by age
|
|
706
1485
|
*/
|
|
707
|
-
class
|
|
708
|
-
transform(value) {
|
|
709
|
-
if (!value)
|
|
710
|
-
return
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
.
|
|
1486
|
+
class OrderByPipe {
|
|
1487
|
+
transform(value, key, direction = 'asc') {
|
|
1488
|
+
if (!Array.isArray(value) || value.length <= 1 || !key) {
|
|
1489
|
+
return Array.isArray(value) ? [...value] : [];
|
|
1490
|
+
}
|
|
1491
|
+
const dir = direction === 'desc' ? -1 : 1;
|
|
1492
|
+
return [...value].sort((a, b) => {
|
|
1493
|
+
const valA = this.getNestedValue(a, key);
|
|
1494
|
+
const valB = this.getNestedValue(b, key);
|
|
1495
|
+
if (valA === valB)
|
|
1496
|
+
return 0;
|
|
1497
|
+
if (valA === null || valA === undefined)
|
|
1498
|
+
return 1;
|
|
1499
|
+
if (valB === null || valB === undefined)
|
|
1500
|
+
return -1;
|
|
1501
|
+
if (typeof valA === 'string' && typeof valB === 'string') {
|
|
1502
|
+
return valA.localeCompare(valB) * dir;
|
|
1503
|
+
}
|
|
1504
|
+
if (typeof valA === 'number' && typeof valB === 'number') {
|
|
1505
|
+
return (valA - valB) * dir;
|
|
1506
|
+
}
|
|
1507
|
+
return String(valA).localeCompare(String(valB)) * dir;
|
|
1508
|
+
});
|
|
716
1509
|
}
|
|
717
|
-
|
|
718
|
-
|
|
1510
|
+
getNestedValue(obj, path) {
|
|
1511
|
+
return path.split('.').reduce((current, segment) => current?.[segment], obj);
|
|
1512
|
+
}
|
|
1513
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: OrderByPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1514
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: OrderByPipe, isStandalone: true, name: "orderBy" });
|
|
719
1515
|
}
|
|
720
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1516
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: OrderByPipe, decorators: [{
|
|
721
1517
|
type: Pipe,
|
|
722
1518
|
args: [{
|
|
723
|
-
name: '
|
|
724
|
-
standalone: true
|
|
1519
|
+
name: 'orderBy',
|
|
1520
|
+
standalone: true,
|
|
725
1521
|
}]
|
|
726
1522
|
}] });
|
|
727
1523
|
|
|
728
1524
|
/**
|
|
729
|
-
*
|
|
1525
|
+
* PluckPipe: Extracts a property value from every object in an array.
|
|
730
1526
|
*
|
|
731
|
-
* @param {
|
|
732
|
-
* @param {
|
|
1527
|
+
* @param {unknown[]} value - The array of objects.
|
|
1528
|
+
* @param {string} key - Property path to extract (supports dot notation).
|
|
733
1529
|
*
|
|
734
|
-
* @returns {
|
|
1530
|
+
* @returns {unknown[]} - An array of the extracted values.
|
|
735
1531
|
*
|
|
736
1532
|
* @example
|
|
737
|
-
* {{
|
|
738
|
-
* {{ '
|
|
739
|
-
*
|
|
740
|
-
* @author Mofiro Jean
|
|
1533
|
+
* {{ users | pluck:'name' }} // ['Alice', 'Bob', 'Carol']
|
|
1534
|
+
* {{ orders | pluck:'customer.email' }} // ['a@test.com', 'b@test.com']
|
|
741
1535
|
*/
|
|
742
|
-
class
|
|
743
|
-
transform(value,
|
|
744
|
-
if (!value ||
|
|
745
|
-
return
|
|
1536
|
+
class PluckPipe {
|
|
1537
|
+
transform(value, key) {
|
|
1538
|
+
if (!Array.isArray(value) || !key) {
|
|
1539
|
+
return [];
|
|
746
1540
|
}
|
|
747
|
-
|
|
748
|
-
const parts = value.split('.');
|
|
749
|
-
return `${parts[0]}.${parts[1]}.*.*`;
|
|
750
|
-
}
|
|
751
|
-
return value;
|
|
1541
|
+
return value.map(item => this.getNestedValue(item, key));
|
|
752
1542
|
}
|
|
753
|
-
|
|
754
|
-
|
|
1543
|
+
getNestedValue(obj, path) {
|
|
1544
|
+
return path.split('.').reduce((current, segment) => current?.[segment], obj);
|
|
1545
|
+
}
|
|
1546
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: PluckPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1547
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: PluckPipe, isStandalone: true, name: "pluck" });
|
|
755
1548
|
}
|
|
756
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1549
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: PluckPipe, decorators: [{
|
|
757
1550
|
type: Pipe,
|
|
758
1551
|
args: [{
|
|
759
|
-
name: '
|
|
760
|
-
standalone: true
|
|
1552
|
+
name: 'pluck',
|
|
1553
|
+
standalone: true,
|
|
761
1554
|
}]
|
|
762
1555
|
}] });
|
|
763
1556
|
|
|
764
1557
|
/**
|
|
765
|
-
*
|
|
1558
|
+
* RangePipe: Generates a numeric sequence array.
|
|
766
1559
|
*
|
|
767
|
-
* @param {
|
|
768
|
-
* @param {number} [
|
|
1560
|
+
* @param {number} value - The number of items to generate (or the end value when start is provided).
|
|
1561
|
+
* @param {number} [start=0] - The starting number.
|
|
1562
|
+
* @param {number} [step=1] - The increment between each number.
|
|
769
1563
|
*
|
|
770
|
-
* @returns {
|
|
1564
|
+
* @returns {number[]} - An array of sequential numbers.
|
|
771
1565
|
*
|
|
772
1566
|
* @example
|
|
773
|
-
* {{
|
|
774
|
-
*
|
|
775
|
-
*
|
|
776
|
-
* @author Mofiro Jean
|
|
1567
|
+
* {{ 5 | range }} // [0, 1, 2, 3, 4]
|
|
1568
|
+
* {{ 5 | range:1 }} // [1, 2, 3, 4, 5]
|
|
1569
|
+
* {{ 10 | range:0:2 }} // [0, 2, 4, 6, 8]
|
|
777
1570
|
*/
|
|
778
|
-
class
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
try {
|
|
783
|
-
if (typeof value === 'object') {
|
|
784
|
-
jsonString = JSON.stringify(value, null, spaces);
|
|
785
|
-
}
|
|
786
|
-
else if (value && typeof value === 'string') {
|
|
787
|
-
jsonString = JSON.stringify(JSON.parse(value), null, spaces);
|
|
788
|
-
}
|
|
789
|
-
else {
|
|
790
|
-
throw new Error('Invalid or empty input');
|
|
791
|
-
}
|
|
1571
|
+
class RangePipe {
|
|
1572
|
+
transform(value, start = 0, step = 1) {
|
|
1573
|
+
if (typeof value !== 'number' || isNaN(value) || value <= 0) {
|
|
1574
|
+
return [];
|
|
792
1575
|
}
|
|
793
|
-
|
|
794
|
-
return
|
|
1576
|
+
if (step === 0) {
|
|
1577
|
+
return [];
|
|
795
1578
|
}
|
|
796
|
-
const
|
|
797
|
-
|
|
798
|
-
.
|
|
799
|
-
.replace(/>/g, '>');
|
|
800
|
-
let finalJson = this.highlightJson(escapedJson);
|
|
801
|
-
if (highlightProperty) {
|
|
802
|
-
const lines = finalJson.split('\n');
|
|
803
|
-
const highlightedLines = lines.map(line => {
|
|
804
|
-
const searchString = `<span class="json-key">"${highlightProperty}"</span>`;
|
|
805
|
-
if (line.includes(searchString)) {
|
|
806
|
-
return `<span class="highlight-line">${line}</span>`;
|
|
807
|
-
}
|
|
808
|
-
return line;
|
|
809
|
-
});
|
|
810
|
-
finalJson = highlightedLines.join('\n');
|
|
1579
|
+
const result = [];
|
|
1580
|
+
for (let i = 0; i < value; i++) {
|
|
1581
|
+
result.push(start + i * step);
|
|
811
1582
|
}
|
|
812
|
-
return this.sanitizer.bypassSecurityTrustHtml(`<pre class="json-pretty">${finalJson}</pre>`);
|
|
813
|
-
}
|
|
814
|
-
highlightJson(json) {
|
|
815
|
-
let result = json.replace(/"([^"\\]*(?:\\.[^"\\]*)*)"/g, (match, p1, offset) => {
|
|
816
|
-
const remainingString = json.substring(offset + match.length);
|
|
817
|
-
const isKey = /^\s*:/.test(remainingString);
|
|
818
|
-
return isKey
|
|
819
|
-
? `<span class="json-key">${match}</span>`
|
|
820
|
-
: `<span class="json-string">${match}</span>`;
|
|
821
|
-
});
|
|
822
|
-
// Highlight numbers
|
|
823
|
-
result = result.replace(/\b-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b/g, '<span class="json-number">$&</span>');
|
|
824
|
-
// Highlight booleans
|
|
825
|
-
result = result.replace(/\b(true|false)\b/g, '<span class="json-boolean">$&</span>');
|
|
826
|
-
// Highlight null
|
|
827
|
-
result = result.replace(/\bnull\b/g, '<span class="json-null">$&</span>');
|
|
828
|
-
// Highlight punctuation
|
|
829
|
-
result = result.replace(/[{}[\]]/g, '<span class="json-punctuation">$&</span>');
|
|
830
1583
|
return result;
|
|
831
1584
|
}
|
|
832
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
833
|
-
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1585
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: RangePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1586
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: RangePipe, isStandalone: true, name: "range" });
|
|
834
1587
|
}
|
|
835
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1588
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: RangePipe, decorators: [{
|
|
836
1589
|
type: Pipe,
|
|
837
1590
|
args: [{
|
|
838
|
-
name: '
|
|
839
|
-
standalone: true
|
|
1591
|
+
name: 'range',
|
|
1592
|
+
standalone: true,
|
|
840
1593
|
}]
|
|
841
1594
|
}] });
|
|
842
1595
|
|
|
843
1596
|
/**
|
|
844
|
-
*
|
|
1597
|
+
* ReversePipe: Reverses the characters in a string.
|
|
845
1598
|
*
|
|
846
|
-
* @param {string} value - The
|
|
847
|
-
* @returns {string} The string in kebab-case, or an empty string if input is invalid.
|
|
1599
|
+
* @param {string} value - The string to reverse.
|
|
848
1600
|
*
|
|
849
|
-
* @
|
|
850
|
-
* ```html
|
|
851
|
-
* {{ 'hello world' | kebabCase }} <!-- Outputs: hello-world -->
|
|
852
|
-
* ```
|
|
1601
|
+
* @returns {string} - The reversed string (e.g., 'hello' → 'olleh').
|
|
853
1602
|
*
|
|
854
|
-
* @
|
|
1603
|
+
* @example
|
|
1604
|
+
* {{ 'hello' | reverse }} // Outputs: 'olleh'
|
|
1605
|
+
* {{ '12345' | reverse }} // Outputs: '54321'
|
|
1606
|
+
* <p>{{ userInput | reverse }}</p>
|
|
855
1607
|
*/
|
|
856
|
-
class
|
|
1608
|
+
class ReversePipe {
|
|
857
1609
|
transform(value) {
|
|
858
|
-
if (
|
|
859
|
-
return
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
.
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
.replace(/^-|-$/g, ''); // Remove leading/trailing hyphens
|
|
1610
|
+
if (Array.isArray(value)) {
|
|
1611
|
+
return [...value].reverse();
|
|
1612
|
+
}
|
|
1613
|
+
if (typeof value === 'string') {
|
|
1614
|
+
return value.split('').reverse().join('');
|
|
1615
|
+
}
|
|
1616
|
+
return '';
|
|
866
1617
|
}
|
|
867
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
868
|
-
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1618
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ReversePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1619
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: ReversePipe, isStandalone: true, name: "reverse" });
|
|
869
1620
|
}
|
|
870
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1621
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ReversePipe, decorators: [{
|
|
871
1622
|
type: Pipe,
|
|
872
1623
|
args: [{
|
|
873
|
-
name: '
|
|
1624
|
+
name: 'reverse',
|
|
874
1625
|
standalone: true
|
|
875
1626
|
}]
|
|
876
1627
|
}] });
|
|
877
1628
|
|
|
878
1629
|
/**
|
|
879
|
-
*
|
|
1630
|
+
* SamplePipe: Randomly selects n items from an array.
|
|
880
1631
|
*
|
|
881
|
-
*
|
|
1632
|
+
* Uses Fisher-Yates partial shuffle for unbiased selection.
|
|
1633
|
+
* Returns a single item when n=1 (default), or an array when n>1.
|
|
882
1634
|
*
|
|
883
|
-
* @
|
|
1635
|
+
* @param {unknown[]} value - The array to sample from.
|
|
1636
|
+
* @param {number} [n=1] - Number of items to select.
|
|
1637
|
+
*
|
|
1638
|
+
* @returns {unknown | unknown[]} - A single random item (n=1) or array of random items (n>1).
|
|
884
1639
|
*
|
|
885
1640
|
* @example
|
|
886
|
-
* {{
|
|
887
|
-
* {{
|
|
888
|
-
*
|
|
1641
|
+
* {{ [1, 2, 3, 4, 5] | sample }} // 3 (random single)
|
|
1642
|
+
* {{ [1, 2, 3, 4, 5] | sample:3 }} // [5, 1, 3] (random 3)
|
|
1643
|
+
* {{ users | sample:5 }} // 5 random users
|
|
889
1644
|
*
|
|
890
|
-
* @
|
|
1645
|
+
* @note Impure pipe — returns different results on each change detection cycle.
|
|
1646
|
+
* Bind the result to a signal to control when it re-samples.
|
|
891
1647
|
*/
|
|
892
|
-
class
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
'M': '--', 'N': '-.', 'O': '---', 'P': '.--.', 'Q': '--.-', 'R': '.-.',
|
|
897
|
-
'S': '...', 'T': '-', 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-',
|
|
898
|
-
'Y': '-.--', 'Z': '--..', '0': '-----', '1': '.----', '2': '..---',
|
|
899
|
-
'3': '...--', '4': '....-', '5': '.....', '6': '-....', '7': '--...',
|
|
900
|
-
'8': '---..', '9': '----.'
|
|
901
|
-
};
|
|
902
|
-
transform(value) {
|
|
903
|
-
if (!value || typeof value !== 'string') {
|
|
904
|
-
return '';
|
|
1648
|
+
class SamplePipe {
|
|
1649
|
+
transform(value, n = 1) {
|
|
1650
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
1651
|
+
return n === 1 ? undefined : [];
|
|
905
1652
|
}
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
1653
|
+
if (n <= 0) {
|
|
1654
|
+
return [];
|
|
1655
|
+
}
|
|
1656
|
+
// Clamp n to array length
|
|
1657
|
+
const count = Math.min(n, value.length);
|
|
1658
|
+
// Fisher-Yates partial shuffle — only shuffle `count` positions
|
|
1659
|
+
const arr = [...value];
|
|
1660
|
+
for (let i = arr.length - 1; i > arr.length - 1 - count; i--) {
|
|
1661
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
1662
|
+
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
1663
|
+
}
|
|
1664
|
+
const result = arr.slice(arr.length - count);
|
|
1665
|
+
// Return single item for n=1, array otherwise
|
|
1666
|
+
return n === 1 ? result[0] : result;
|
|
912
1667
|
}
|
|
913
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
914
|
-
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1668
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: SamplePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1669
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: SamplePipe, isStandalone: true, name: "sample", pure: false });
|
|
915
1670
|
}
|
|
916
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1671
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: SamplePipe, decorators: [{
|
|
917
1672
|
type: Pipe,
|
|
918
1673
|
args: [{
|
|
919
|
-
name: '
|
|
920
|
-
standalone: true
|
|
1674
|
+
name: 'sample',
|
|
1675
|
+
standalone: true,
|
|
1676
|
+
pure: false,
|
|
921
1677
|
}]
|
|
922
1678
|
}] });
|
|
923
1679
|
|
|
924
1680
|
/**
|
|
925
|
-
*
|
|
1681
|
+
* ShufflePipe: Randomly reorders elements in an array using the Fisher-Yates
|
|
1682
|
+
algorithm.
|
|
926
1683
|
*
|
|
927
|
-
*
|
|
928
|
-
*
|
|
1684
|
+
* Uses the Fisher-Yates (Knuth) shuffle for unbiased randomization,
|
|
1685
|
+
* guaranteeing every permutation has equal probability.
|
|
929
1686
|
*
|
|
930
|
-
* @
|
|
1687
|
+
* @param {unknown[]} value - The array to shuffle.
|
|
1688
|
+
*
|
|
1689
|
+
* @returns {unknown[]} - A new array with elements in random order.
|
|
931
1690
|
*
|
|
932
1691
|
* @example
|
|
933
|
-
*
|
|
1692
|
+
* {{ [1, 2, 3, 4, 5] | shuffle }} // [3, 1, 5, 2, 4]
|
|
1693
|
+
* {{ ['a', 'b', 'c'] | shuffle }} // ['c', 'a', 'b']
|
|
934
1694
|
*
|
|
935
|
-
* @
|
|
1695
|
+
* @note Impure pipe — runs on every change detection cycle.
|
|
1696
|
+
* Avoid using in performance-critical templates or bind the result
|
|
1697
|
+
* to a signal/variable to control when it re-shuffles.
|
|
936
1698
|
*/
|
|
937
|
-
class
|
|
938
|
-
transform(value
|
|
939
|
-
if (!value) {
|
|
940
|
-
return
|
|
1699
|
+
class ShufflePipe {
|
|
1700
|
+
transform(value) {
|
|
1701
|
+
if (!Array.isArray(value)) {
|
|
1702
|
+
return [];
|
|
941
1703
|
}
|
|
942
|
-
|
|
1704
|
+
const arr = [...value];
|
|
1705
|
+
for (let i = arr.length - 1; i >= 0; i--) {
|
|
1706
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
1707
|
+
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
1708
|
+
}
|
|
1709
|
+
return arr;
|
|
943
1710
|
}
|
|
944
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
945
|
-
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1711
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ShufflePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1712
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: ShufflePipe, isStandalone: true, name: "shuffle", pure: false });
|
|
946
1713
|
}
|
|
947
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1714
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ShufflePipe, decorators: [{
|
|
948
1715
|
type: Pipe,
|
|
949
1716
|
args: [{
|
|
950
|
-
name: '
|
|
1717
|
+
name: 'shuffle',
|
|
1718
|
+
pure: false,
|
|
951
1719
|
standalone: true
|
|
952
1720
|
}]
|
|
953
1721
|
}] });
|
|
954
1722
|
|
|
955
1723
|
/**
|
|
956
|
-
*
|
|
1724
|
+
* TailPipe: Returns all elements except the first n.
|
|
957
1725
|
*
|
|
958
|
-
*
|
|
959
|
-
*
|
|
960
|
-
*
|
|
961
|
-
* @param {string} value - The input string to transform.
|
|
962
|
-
* @param {string | RegExp} pattern - The pattern to match (string or RegExp). If an empty string, the value is returned as-is.
|
|
963
|
-
* @param {string} replacement - The string to replace matches with.
|
|
964
|
-
* @param {string} [highlightClass] - Optional CSS class for highlighting matched or replaced text (e.g., 'highlight').
|
|
965
|
-
* @param {boolean} [isReplace=true] - Whether to perform replacement (true) or only highlight matches (false).
|
|
1726
|
+
* @param {unknown[]} value - The array to slice.
|
|
1727
|
+
* @param {number} [n=1] - Number of elements to exclude from the start.
|
|
966
1728
|
*
|
|
967
|
-
* @returns {
|
|
1729
|
+
* @returns {unknown[]} - A new array without the first n elements.
|
|
968
1730
|
*
|
|
969
1731
|
* @example
|
|
970
|
-
* {{
|
|
971
|
-
*
|
|
972
|
-
*
|
|
973
|
-
|
|
974
|
-
|
|
1732
|
+
* {{ [1, 2, 3, 4, 5] | tail }} // [2, 3, 4, 5]
|
|
1733
|
+
* {{ [1, 2, 3, 4, 5] | tail:2 }} // [3, 4, 5]
|
|
1734
|
+
* {{ ['a', 'b', 'c'] | tail }} // ['b', 'c']
|
|
1735
|
+
*/
|
|
1736
|
+
class TailPipe {
|
|
1737
|
+
transform(value, n = 1) {
|
|
1738
|
+
if (!Array.isArray(value)) {
|
|
1739
|
+
return [];
|
|
1740
|
+
}
|
|
1741
|
+
// n = 0 means keep everything
|
|
1742
|
+
if (n <= 0)
|
|
1743
|
+
return [...value];
|
|
1744
|
+
// n >= length means remove everything
|
|
1745
|
+
if (n >= value.length)
|
|
1746
|
+
return [];
|
|
1747
|
+
return value.slice(n);
|
|
1748
|
+
}
|
|
1749
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: TailPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1750
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: TailPipe, isStandalone: true, name: "tail" });
|
|
1751
|
+
}
|
|
1752
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: TailPipe, decorators: [{
|
|
1753
|
+
type: Pipe,
|
|
1754
|
+
args: [{
|
|
1755
|
+
name: 'tail',
|
|
1756
|
+
}]
|
|
1757
|
+
}] });
|
|
1758
|
+
|
|
1759
|
+
/**
|
|
1760
|
+
* TruthifyPipe: Removes all falsy values from an array.
|
|
975
1761
|
*
|
|
976
|
-
*
|
|
977
|
-
* // Output: Angular is <span class="highlight">awesome</span>
|
|
1762
|
+
* Falsy values: false, 0, -0, '', null, undefined, NaN
|
|
978
1763
|
*
|
|
979
|
-
* {
|
|
980
|
-
* // Output: Angular is <span class="highlight">great</span>
|
|
1764
|
+
* @param {unknown[]} value - The array to filter.
|
|
981
1765
|
*
|
|
982
|
-
*
|
|
983
|
-
* // Renders: Angular is <span class="highlight">great</span>
|
|
1766
|
+
* @returns {unknown[]} - A new array with only truthy values.
|
|
984
1767
|
*
|
|
985
|
-
* @
|
|
1768
|
+
* @example
|
|
1769
|
+
* {{ [0, 1, '', 'hello', null, true] | truthify }} // [1, 'hello', true]
|
|
1770
|
+
* {{ ['', 'a', '', 'b'] | truthify }} // ['a', 'b']
|
|
986
1771
|
*/
|
|
987
|
-
class
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
return '';
|
|
992
|
-
// handles empty string pattern
|
|
993
|
-
if (!pattern || (typeof pattern === 'string' && pattern.trim() === '')) {
|
|
994
|
-
return value;
|
|
995
|
-
}
|
|
996
|
-
const finalPattern = typeof pattern === 'string' ? new RegExp(pattern, 'gi') : pattern;
|
|
997
|
-
if (!highlightClass) {
|
|
998
|
-
return isReplace ? value.replace(finalPattern, replacement) : value;
|
|
999
|
-
}
|
|
1000
|
-
// Sanitize the replacement to prevent XSS
|
|
1001
|
-
const sanitizedReplacement = replacement.replace(/</g, '<').replace(/>/g, '>');
|
|
1002
|
-
if (isReplace) {
|
|
1003
|
-
const highlightedReplacement = `<span class="${highlightClass}">${sanitizedReplacement}</span>`;
|
|
1004
|
-
const replaced = value.replace(finalPattern, highlightedReplacement);
|
|
1005
|
-
return this.sanitizer.bypassSecurityTrustHtml(replaced);
|
|
1772
|
+
class TruthifyPipe {
|
|
1773
|
+
transform(value) {
|
|
1774
|
+
if (!Array.isArray(value)) {
|
|
1775
|
+
return [];
|
|
1006
1776
|
}
|
|
1007
|
-
|
|
1008
|
-
const result = value.replace(finalPattern, highlightedMatch);
|
|
1009
|
-
return this.sanitizer.bypassSecurityTrustHtml(result);
|
|
1777
|
+
return value.filter(Boolean);
|
|
1010
1778
|
}
|
|
1011
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1012
|
-
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1779
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: TruthifyPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1780
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: TruthifyPipe, isStandalone: true, name: "truthify" });
|
|
1013
1781
|
}
|
|
1014
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1782
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: TruthifyPipe, decorators: [{
|
|
1015
1783
|
type: Pipe,
|
|
1016
1784
|
args: [{
|
|
1017
|
-
name: '
|
|
1018
|
-
standalone: true
|
|
1785
|
+
name: 'truthify',
|
|
1786
|
+
standalone: true,
|
|
1019
1787
|
}]
|
|
1020
1788
|
}] });
|
|
1021
1789
|
|
|
1022
1790
|
/**
|
|
1023
|
-
*
|
|
1791
|
+
* UniquePipe: Removes duplicate values from an array.
|
|
1024
1792
|
*
|
|
1025
|
-
*
|
|
1793
|
+
* Supports primitives, objects by property key, and deep nested keys via dot notation.
|
|
1026
1794
|
*
|
|
1027
|
-
* @
|
|
1795
|
+
* @param {unknown[]} value - The array to deduplicate.
|
|
1796
|
+
* @param {string} [key] - Optional property path to compare objects by (e.g., 'id', 'user.email').
|
|
1028
1797
|
*
|
|
1029
|
-
* @
|
|
1030
|
-
* {{ 'hello' | reverse }} // Outputs: 'olleh'
|
|
1031
|
-
* {{ '12345' | reverse }} // Outputs: '54321'
|
|
1032
|
-
* <p>{{ userInput | reverse }}</p>
|
|
1798
|
+
* @returns {unknown[]} - A new array with duplicates removed, preserving first occurrence.
|
|
1033
1799
|
*
|
|
1034
|
-
* @
|
|
1800
|
+
* @example
|
|
1801
|
+
* {{ [1, 2, 2, 3] | unique }} // [1, 2, 3]
|
|
1802
|
+
* {{ users | unique:'email' }} // unique by email
|
|
1803
|
+
* {{ orders | unique:'customer.email' }} // unique by nested property
|
|
1035
1804
|
*/
|
|
1036
|
-
class
|
|
1037
|
-
transform(value) {
|
|
1038
|
-
if (!value
|
|
1039
|
-
return
|
|
1805
|
+
class UniquePipe {
|
|
1806
|
+
transform(value, key) {
|
|
1807
|
+
if (!Array.isArray(value)) {
|
|
1808
|
+
return [];
|
|
1040
1809
|
}
|
|
1041
|
-
|
|
1810
|
+
if (!key) {
|
|
1811
|
+
return [...new Set(value)];
|
|
1812
|
+
}
|
|
1813
|
+
const seen = new Set();
|
|
1814
|
+
return value.filter(item => {
|
|
1815
|
+
const val = this.getNestedValue(item, key);
|
|
1816
|
+
if (seen.has(val))
|
|
1817
|
+
return false;
|
|
1818
|
+
seen.add(val);
|
|
1819
|
+
return true;
|
|
1820
|
+
});
|
|
1042
1821
|
}
|
|
1043
|
-
|
|
1044
|
-
|
|
1822
|
+
getNestedValue(obj, path) {
|
|
1823
|
+
return path.split('.').reduce((current, segment) => current?.[segment], obj);
|
|
1824
|
+
}
|
|
1825
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UniquePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1826
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: UniquePipe, isStandalone: true, name: "unique" });
|
|
1045
1827
|
}
|
|
1046
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1828
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UniquePipe, decorators: [{
|
|
1047
1829
|
type: Pipe,
|
|
1048
1830
|
args: [{
|
|
1049
|
-
name: '
|
|
1831
|
+
name: 'unique',
|
|
1050
1832
|
standalone: true
|
|
1051
1833
|
}]
|
|
1052
1834
|
}] });
|
|
1053
1835
|
|
|
1054
1836
|
/**
|
|
1055
|
-
*
|
|
1837
|
+
* WithoutPipe: Excludes specified elements from an array.
|
|
1056
1838
|
*
|
|
1057
|
-
*
|
|
1058
|
-
* @returns {string} The string in snake_case, or an empty string if input is invalid.
|
|
1839
|
+
* Supports primitives and objects by property key with dot notation.
|
|
1059
1840
|
*
|
|
1060
|
-
* @
|
|
1061
|
-
*
|
|
1062
|
-
* {
|
|
1063
|
-
* ```
|
|
1841
|
+
* @param {unknown[]} value - The array to filter.
|
|
1842
|
+
* @param {unknown[]} excludes - Values to exclude.
|
|
1843
|
+
* @param {string} [key] - Optional property path for object comparison (supports dot notation).
|
|
1064
1844
|
*
|
|
1065
|
-
* @
|
|
1845
|
+
* @returns {unknown[]} - A new array without the excluded elements.
|
|
1846
|
+
*
|
|
1847
|
+
* @example
|
|
1848
|
+
* {{ [1, 2, 3, 4, 5] | without:[2, 4] }} // [1, 3, 5]
|
|
1849
|
+
* {{ users | without:['banned']:'status' }} // active users
|
|
1850
|
+
* {{ orders | without:['cancelled']:'meta.status' }} // non-cancelled orders
|
|
1066
1851
|
*/
|
|
1067
|
-
class
|
|
1068
|
-
transform(value) {
|
|
1069
|
-
if (!value
|
|
1070
|
-
return
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
.
|
|
1078
|
-
|
|
1852
|
+
class WithoutPipe {
|
|
1853
|
+
transform(value, excludes, key) {
|
|
1854
|
+
if (!Array.isArray(value)) {
|
|
1855
|
+
return [];
|
|
1856
|
+
}
|
|
1857
|
+
if (!Array.isArray(excludes) || excludes.length === 0) {
|
|
1858
|
+
return [...value];
|
|
1859
|
+
}
|
|
1860
|
+
const excludeSet = new Set(excludes);
|
|
1861
|
+
if (!key) {
|
|
1862
|
+
return value.filter(item => !excludeSet.has(item));
|
|
1863
|
+
}
|
|
1864
|
+
return value.filter(item => {
|
|
1865
|
+
const val = this.getNestedValue(item, key);
|
|
1866
|
+
return !excludeSet.has(val);
|
|
1867
|
+
});
|
|
1079
1868
|
}
|
|
1080
|
-
|
|
1081
|
-
|
|
1869
|
+
getNestedValue(obj, path) {
|
|
1870
|
+
return path.split('.').reduce((current, segment) => current?.[segment], obj);
|
|
1871
|
+
}
|
|
1872
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: WithoutPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1873
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: WithoutPipe, isStandalone: true, name: "without" });
|
|
1082
1874
|
}
|
|
1083
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1875
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: WithoutPipe, decorators: [{
|
|
1084
1876
|
type: Pipe,
|
|
1085
1877
|
args: [{
|
|
1086
|
-
name: '
|
|
1087
|
-
standalone: true
|
|
1878
|
+
name: 'without',
|
|
1879
|
+
standalone: true,
|
|
1088
1880
|
}]
|
|
1089
1881
|
}] });
|
|
1090
1882
|
|
|
1091
1883
|
/**
|
|
1092
|
-
*
|
|
1884
|
+
* SomePipe: Checks if at least one element in an array satisfies a condition.
|
|
1093
1885
|
*
|
|
1094
|
-
*
|
|
1095
|
-
* @param {string} [lang='en-US'] - The language (local) for speech synthesis.
|
|
1886
|
+
* Supports primitives (equality check) and objects by property key with dot notation.
|
|
1096
1887
|
*
|
|
1097
|
-
* @
|
|
1888
|
+
* @param {unknown[]} value - The array to check.
|
|
1889
|
+
* @param {unknown} match - The value to match against.
|
|
1890
|
+
* @param {string} [key] - Optional property path to check (supports dot notation).
|
|
1098
1891
|
*
|
|
1099
|
-
* @
|
|
1100
|
-
* <div>{{ Hello World' | textToSpeech }}</div>
|
|
1101
|
-
* <div>{{ 'Bonjour' | textToSpeech:'fr-FR' }}h</div>
|
|
1892
|
+
* @returns {boolean} - True if at least one element matches, false otherwise.
|
|
1102
1893
|
*
|
|
1103
|
-
* @
|
|
1894
|
+
* @example
|
|
1895
|
+
* {{ [false, false, true] | some:true }} // true
|
|
1896
|
+
* {{ users | some:'admin':'role' }} // any admins?
|
|
1897
|
+
* {{ orders | some:'failed':'meta.status' }} // any failures?
|
|
1104
1898
|
*/
|
|
1105
|
-
class
|
|
1106
|
-
transform(value,
|
|
1107
|
-
if (!value ||
|
|
1108
|
-
return;
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1899
|
+
class SomePipe {
|
|
1900
|
+
transform(value, match, key) {
|
|
1901
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
1902
|
+
return false;
|
|
1903
|
+
}
|
|
1904
|
+
if (!key) {
|
|
1905
|
+
return value.some(item => item === match);
|
|
1906
|
+
}
|
|
1907
|
+
return value.some(item => this.getNestedValue(item, key) === match);
|
|
1112
1908
|
}
|
|
1113
|
-
|
|
1114
|
-
|
|
1909
|
+
getNestedValue(obj, path) {
|
|
1910
|
+
return path.split('.').reduce((current, segment) => current?.[segment], obj);
|
|
1911
|
+
}
|
|
1912
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: SomePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1913
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: SomePipe, isStandalone: true, name: "some" });
|
|
1115
1914
|
}
|
|
1116
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1915
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: SomePipe, decorators: [{
|
|
1117
1916
|
type: Pipe,
|
|
1118
1917
|
args: [{
|
|
1119
|
-
name: '
|
|
1120
|
-
standalone: true
|
|
1918
|
+
name: 'some',
|
|
1919
|
+
standalone: true,
|
|
1121
1920
|
}]
|
|
1122
1921
|
}] });
|
|
1123
1922
|
|
|
1124
1923
|
/**
|
|
1125
|
-
*
|
|
1924
|
+
* UnionPipe: Combines two arrays, keeping only unique elements.
|
|
1126
1925
|
*
|
|
1127
|
-
*
|
|
1128
|
-
*
|
|
1926
|
+
* Supports primitives and objects by property key with dot notation.
|
|
1927
|
+
*
|
|
1928
|
+
* @param {unknown[]} value - The first array.
|
|
1929
|
+
* @param {unknown[]} other - The second array.
|
|
1930
|
+
* @param {string} [key] - Optional property path for uniqueness check (supports dot notation).
|
|
1931
|
+
*
|
|
1932
|
+
* @returns {unknown[]} - A merged array with duplicates removed.
|
|
1129
1933
|
*
|
|
1130
1934
|
* @example
|
|
1131
|
-
*
|
|
1132
|
-
* {{
|
|
1133
|
-
*
|
|
1935
|
+
* {{ [1, 2, 3] | union:[3, 4, 5] }} // [1, 2, 3, 4, 5]
|
|
1936
|
+
* {{ admins | union:editors:'id' }} // all unique users
|
|
1937
|
+
* {{ local | union:remote:'meta.uuid' }} // merged records
|
|
1134
1938
|
*/
|
|
1135
|
-
class
|
|
1136
|
-
transform(value) {
|
|
1137
|
-
if (!value
|
|
1138
|
-
return
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1939
|
+
class UnionPipe {
|
|
1940
|
+
transform(value, other, key) {
|
|
1941
|
+
if (!Array.isArray(value) && !Array.isArray(other)) {
|
|
1942
|
+
return [];
|
|
1943
|
+
}
|
|
1944
|
+
const first = Array.isArray(value) ? value : [];
|
|
1945
|
+
const second = Array.isArray(other) ? other : [];
|
|
1946
|
+
if (!key) {
|
|
1947
|
+
const seen = new Set();
|
|
1948
|
+
const result = [];
|
|
1949
|
+
for (const item of [...first, ...second]) {
|
|
1950
|
+
if (!seen.has(item)) {
|
|
1951
|
+
seen.add(item);
|
|
1952
|
+
result.push(item);
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
return result;
|
|
1956
|
+
}
|
|
1957
|
+
const seen = new Set();
|
|
1958
|
+
const result = [];
|
|
1959
|
+
for (const item of [...first, ...second]) {
|
|
1960
|
+
const val = this.getNestedValue(item, key);
|
|
1961
|
+
if (!seen.has(val)) {
|
|
1962
|
+
seen.add(val);
|
|
1963
|
+
result.push(item);
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
return result;
|
|
1144
1967
|
}
|
|
1145
|
-
|
|
1146
|
-
|
|
1968
|
+
getNestedValue(obj, path) {
|
|
1969
|
+
return path.split('.').reduce((current, segment) => current?.[segment], obj);
|
|
1970
|
+
}
|
|
1971
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UnionPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
1972
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: UnionPipe, isStandalone: true, name: "union" });
|
|
1147
1973
|
}
|
|
1148
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
1974
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: UnionPipe, decorators: [{
|
|
1149
1975
|
type: Pipe,
|
|
1150
1976
|
args: [{
|
|
1151
|
-
name: '
|
|
1152
|
-
standalone: true
|
|
1977
|
+
name: 'union',
|
|
1978
|
+
standalone: true,
|
|
1153
1979
|
}]
|
|
1154
1980
|
}] });
|
|
1155
1981
|
|
|
1156
1982
|
/**
|
|
1157
|
-
*
|
|
1983
|
+
* FilterByPipe: Filters an array by matching a search term against object
|
|
1984
|
+
properties.
|
|
1158
1985
|
*
|
|
1159
|
-
*
|
|
1160
|
-
*
|
|
1986
|
+
* @param {unknown[]} value - The array to filter.
|
|
1987
|
+
* @param {string} search - The search term.
|
|
1988
|
+
* @param {string} [key] - Property to search in. If omitted, searches all string
|
|
1989
|
+
properties.
|
|
1161
1990
|
*
|
|
1162
|
-
* @
|
|
1163
|
-
* @param {number} [maxLength=10] - The maximum length of the truncated string. Defaults to 10.
|
|
1164
|
-
* @param {string} [ellipsis='...'] - The string to append to the truncated portion. Defaults to '...'.
|
|
1165
|
-
* @param {boolean} [preserveWords=false] - If true, truncates at the last space before `maxLength` to avoid cutting words. Defaults to false.
|
|
1166
|
-
* @returns {string} - The truncated string. Returns an empty string if the input is null, undefined, or not a string.
|
|
1991
|
+
* @returns {unknown[]} - Filtered array with matching items.
|
|
1167
1992
|
*
|
|
1168
1993
|
* @example
|
|
1169
|
-
* {{
|
|
1170
|
-
* {{
|
|
1171
|
-
* {{
|
|
1172
|
-
* {{ 'This is a long sentence' | truncate: 15: '...' : true }} // Returns 'This is a...'
|
|
1173
|
-
* {{ 'This is a long sentence' | truncate: 20: '...' : true }} // Returns 'This is a long...'
|
|
1174
|
-
* {{ null | truncate }} // Returns ''
|
|
1175
|
-
* {{ undefined | truncate }} // Returns ''
|
|
1176
|
-
*
|
|
1177
|
-
* @author Mofiro Jean
|
|
1994
|
+
* {{ users | filterBy:'alice':'name' }} // users with 'alice' in name
|
|
1995
|
+
* {{ users | filterBy:'admin':'role' }} // users with role 'admin'
|
|
1996
|
+
* {{ users | filterBy:'bob' }} // search all properties for 'bob'
|
|
1178
1997
|
*/
|
|
1179
|
-
class
|
|
1180
|
-
transform(value,
|
|
1181
|
-
if (!value ||
|
|
1182
|
-
return
|
|
1998
|
+
class FilterByPipe {
|
|
1999
|
+
transform(value, search, key) {
|
|
2000
|
+
if (!Array.isArray(value) || !search) {
|
|
2001
|
+
return Array.isArray(value) ? [...value] : [];
|
|
1183
2002
|
}
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
2003
|
+
const term = String(search).toLowerCase();
|
|
2004
|
+
if (key) {
|
|
2005
|
+
return value.filter(item => {
|
|
2006
|
+
const val = this.getNestedValue(item, key);
|
|
2007
|
+
return val !== undefined && val !== null
|
|
2008
|
+
&& String(val).toLowerCase().includes(term);
|
|
2009
|
+
});
|
|
1191
2010
|
}
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
// If a space is found and it's not the very beginning of the string
|
|
1196
|
-
if (lastSpaceIndex !== -1 && lastSpaceIndex !== 0) {
|
|
1197
|
-
truncated = truncated.substring(0, lastSpaceIndex);
|
|
2011
|
+
return value.filter(item => {
|
|
2012
|
+
if (typeof item === 'object' && item !== null) {
|
|
2013
|
+
return this.searchObject(item, term);
|
|
1198
2014
|
}
|
|
1199
|
-
|
|
1200
|
-
|
|
2015
|
+
return String(item).toLowerCase().includes(term);
|
|
2016
|
+
});
|
|
1201
2017
|
}
|
|
1202
|
-
|
|
1203
|
-
|
|
2018
|
+
searchObject(obj, term) {
|
|
2019
|
+
return Object.values(obj).some(val => {
|
|
2020
|
+
if (typeof val === 'string') {
|
|
2021
|
+
return val.toLowerCase().includes(term);
|
|
2022
|
+
}
|
|
2023
|
+
if (typeof val === 'number' || typeof val === 'boolean') {
|
|
2024
|
+
return String(val).toLowerCase().includes(term);
|
|
2025
|
+
}
|
|
2026
|
+
if (typeof val === 'object' && val !== null) {
|
|
2027
|
+
return this.searchObject(val, term);
|
|
2028
|
+
}
|
|
2029
|
+
return false;
|
|
2030
|
+
});
|
|
2031
|
+
}
|
|
2032
|
+
getNestedValue(obj, path) {
|
|
2033
|
+
return path.split('.').reduce((current, segment) => current?.[segment], obj);
|
|
2034
|
+
}
|
|
2035
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: FilterByPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
2036
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: FilterByPipe, isStandalone: true, name: "filterBy" });
|
|
1204
2037
|
}
|
|
1205
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type:
|
|
2038
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: FilterByPipe, decorators: [{
|
|
1206
2039
|
type: Pipe,
|
|
1207
2040
|
args: [{
|
|
1208
|
-
name: '
|
|
1209
|
-
standalone: true
|
|
2041
|
+
name: 'filterBy',
|
|
2042
|
+
standalone: true,
|
|
1210
2043
|
}]
|
|
1211
2044
|
}] });
|
|
1212
2045
|
|
|
2046
|
+
// Text
|
|
1213
2047
|
const ALL_PIPES = [
|
|
2048
|
+
// Text
|
|
1214
2049
|
AsciiArtPipe,
|
|
1215
|
-
BarcodePipe,
|
|
1216
2050
|
CamelCasePipe,
|
|
1217
|
-
ColorConvertPipe,
|
|
1218
|
-
CreditCardMaskPipe,
|
|
1219
|
-
DeviceTypePipe,
|
|
1220
|
-
EmailMaskPipe,
|
|
1221
|
-
GravatarPipe,
|
|
1222
2051
|
HighlightPipe,
|
|
1223
|
-
HtmlEscapePipe,
|
|
1224
|
-
HtmlSanitizePipe,
|
|
1225
2052
|
InitialsPipe,
|
|
1226
|
-
IpAddressMaskPipe,
|
|
1227
|
-
JsonPrettyPipe,
|
|
1228
2053
|
KebabCasePipe,
|
|
1229
2054
|
MorseCodePipe,
|
|
1230
|
-
QrCodePipe,
|
|
1231
2055
|
ReplacePipe,
|
|
1232
|
-
ReversePipe,
|
|
1233
2056
|
SnakeCasePipe,
|
|
1234
|
-
TextToSpeechPipe,
|
|
1235
2057
|
TitleCasePipe,
|
|
1236
2058
|
TruncatePipe,
|
|
1237
|
-
|
|
2059
|
+
// Security & Privacy
|
|
2060
|
+
CreditCardMaskPipe,
|
|
2061
|
+
EmailMaskPipe,
|
|
2062
|
+
HtmlEscapePipe,
|
|
2063
|
+
HtmlSanitizePipe,
|
|
2064
|
+
IpAddressMaskPipe,
|
|
2065
|
+
// Media & Visual
|
|
2066
|
+
BarcodePipe,
|
|
2067
|
+
ColorConvertPipe,
|
|
2068
|
+
GravatarPipe,
|
|
2069
|
+
QrCodePipe,
|
|
2070
|
+
// Data & Utility
|
|
2071
|
+
CountPipe,
|
|
2072
|
+
DeviceTypePipe,
|
|
2073
|
+
JsonPrettyPipe,
|
|
2074
|
+
TextToSpeechPipe,
|
|
2075
|
+
TimeAgoPipePipe,
|
|
2076
|
+
// Array
|
|
2077
|
+
ChunkPipe,
|
|
2078
|
+
DiffPipe,
|
|
2079
|
+
EveryPipe,
|
|
2080
|
+
IntersectionPipe,
|
|
2081
|
+
Flatten,
|
|
2082
|
+
GroupByPipe,
|
|
2083
|
+
InitialPipe,
|
|
2084
|
+
OrderByPipe,
|
|
2085
|
+
PluckPipe,
|
|
2086
|
+
RangePipe,
|
|
2087
|
+
ReversePipe,
|
|
2088
|
+
SamplePipe,
|
|
2089
|
+
ShufflePipe,
|
|
2090
|
+
TailPipe,
|
|
2091
|
+
TruthifyPipe,
|
|
2092
|
+
UniquePipe,
|
|
2093
|
+
WithoutPipe,
|
|
2094
|
+
SomePipe,
|
|
2095
|
+
UnionPipe,
|
|
2096
|
+
FilterByPipe
|
|
1238
2097
|
];
|
|
1239
2098
|
|
|
2099
|
+
// Text
|
|
2100
|
+
|
|
1240
2101
|
/**
|
|
1241
2102
|
* Generated bundle index. Do not edit.
|
|
1242
2103
|
*/
|
|
1243
2104
|
|
|
1244
|
-
export { ALL_PIPES, AsciiArtPipe, BarcodePipe, CamelCasePipe, ColorConvertPipe, CountPipe, CreditCardMaskPipe, DeviceTypePipe, EmailMaskPipe, GravatarPipe, HighlightPipe, HtmlEscapePipe, HtmlSanitizePipe, InitialsPipe, IpAddressMaskPipe, JsonPrettyPipe, KebabCasePipe, MorseCodePipe, QrCodePipe, ReplacePipe, ReversePipe, SnakeCasePipe, TextToSpeechPipe, TitleCasePipe, TruncatePipe };
|
|
2105
|
+
export { ALL_PIPES, AsciiArtPipe, BarcodePipe, CamelCasePipe, ChunkPipe, ColorConvertPipe, CountPipe, CreditCardMaskPipe, DeviceTypePipe, DiffPipe, EmailMaskPipe, EveryPipe, FilterByPipe, Flatten, GravatarPipe, GroupByPipe, HighlightPipe, HtmlEscapePipe, HtmlSanitizePipe, InitialPipe, InitialsPipe, IntersectionPipe, IpAddressMaskPipe, JsonPrettyPipe, KebabCasePipe, MorseCodePipe, OrderByPipe, PluckPipe, QrCodePipe, RangePipe, ReplacePipe, ReversePipe, SamplePipe, ShufflePipe, SnakeCasePipe, SomePipe, TailPipe, TextToSpeechPipe, TimeAgoPipePipe, TitleCasePipe, TruncatePipe, TruthifyPipe, UnionPipe, UniquePipe, WithoutPipe };
|
|
1245
2106
|
//# sourceMappingURL=ngx-transforms.mjs.map
|