retold-remote 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/css/retold-remote.css +83 -0
  3. package/html/codejar.js +511 -0
  4. package/html/index.html +23 -0
  5. package/package.json +68 -0
  6. package/server.js +43 -0
  7. package/source/Pict-Application-RetoldRemote-Configuration.json +7 -0
  8. package/source/Pict-Application-RetoldRemote.js +622 -0
  9. package/source/Pict-RetoldRemote-Bundle.js +14 -0
  10. package/source/cli/RetoldRemote-CLI-Program.js +15 -0
  11. package/source/cli/RetoldRemote-CLI-Run.js +3 -0
  12. package/source/cli/RetoldRemote-Server-Setup.js +257 -0
  13. package/source/cli/commands/RetoldRemote-Command-Serve.js +87 -0
  14. package/source/providers/Pict-Provider-GalleryFilterSort.js +597 -0
  15. package/source/providers/Pict-Provider-GalleryNavigation.js +819 -0
  16. package/source/providers/Pict-Provider-RetoldRemote.js +273 -0
  17. package/source/providers/Pict-Provider-RetoldRemoteIcons.js +640 -0
  18. package/source/providers/Pict-Provider-RetoldRemoteTheme.js +879 -0
  19. package/source/server/RetoldRemote-MediaService.js +536 -0
  20. package/source/server/RetoldRemote-PathRegistry.js +121 -0
  21. package/source/server/RetoldRemote-ThumbnailCache.js +89 -0
  22. package/source/server/RetoldRemote-ToolDetector.js +78 -0
  23. package/source/views/PictView-Remote-Gallery.js +1437 -0
  24. package/source/views/PictView-Remote-ImageViewer.js +363 -0
  25. package/source/views/PictView-Remote-Layout.js +420 -0
  26. package/source/views/PictView-Remote-MediaViewer.js +530 -0
  27. package/source/views/PictView-Remote-SettingsPanel.js +318 -0
  28. package/source/views/PictView-Remote-TopBar.js +206 -0
  29. package/web-application/codejar.js +511 -0
  30. package/web-application/css/retold-remote.css +83 -0
  31. package/web-application/index.html +23 -0
  32. package/web-application/js/pict.min.js +12 -0
  33. package/web-application/js/pict.min.js.map +1 -0
  34. package/web-application/retold-remote.compatible.js +5764 -0
  35. package/web-application/retold-remote.compatible.js.map +1 -0
  36. package/web-application/retold-remote.compatible.min.js +120 -0
  37. package/web-application/retold-remote.compatible.min.js.map +1 -0
  38. package/web-application/retold-remote.js +5763 -0
  39. package/web-application/retold-remote.js.map +1 -0
  40. package/web-application/retold-remote.min.js +120 -0
  41. package/web-application/retold-remote.min.js.map +1 -0
@@ -0,0 +1,597 @@
1
+ const libPictProvider = require('pict-provider');
2
+
3
+ const _ImageExtensions = { 'png': true, 'jpg': true, 'jpeg': true, 'gif': true, 'webp': true, 'svg': true, 'bmp': true, 'ico': true, 'avif': true, 'tiff': true, 'tif': true };
4
+ const _VideoExtensions = { 'mp4': true, 'webm': true, 'mov': true, 'mkv': true, 'avi': true, 'wmv': true, 'flv': true, 'm4v': true };
5
+ const _AudioExtensions = { 'mp3': true, 'wav': true, 'ogg': true, 'flac': true, 'aac': true, 'm4a': true, 'wma': true };
6
+ const _DocumentExtensions = { 'pdf': true, 'epub': true, 'mobi': true };
7
+
8
+ const _DefaultProviderConfiguration =
9
+ {
10
+ ProviderIdentifier: 'RetoldRemote-GalleryFilterSort',
11
+ AutoInitialize: true,
12
+ AutoInitializeOrdinal: 0,
13
+ AutoSolveWithApp: false
14
+ };
15
+
16
+ class GalleryFilterSortProvider extends libPictProvider
17
+ {
18
+ constructor(pFable, pOptions, pServiceHash)
19
+ {
20
+ super(pFable, pOptions, pServiceHash);
21
+ }
22
+
23
+ // ──────────────────────────────────────────────
24
+ // Pipeline
25
+ // ──────────────────────────────────────────────
26
+
27
+ /**
28
+ * Run the full filter+sort pipeline.
29
+ * Reads from RawFileList, applies all active filters and sort,
30
+ * writes result into GalleryItems, resets cursor, and re-renders.
31
+ */
32
+ applyFilterSort()
33
+ {
34
+ let tmpRemote = this.pict.AppData.RetoldRemote;
35
+ if (!tmpRemote)
36
+ {
37
+ return;
38
+ }
39
+
40
+ let tmpItems = (tmpRemote.RawFileList || []).slice();
41
+
42
+ // 1. Text search
43
+ tmpItems = this._applySearch(tmpItems, tmpRemote.SearchQuery);
44
+
45
+ // 2. Media type filter
46
+ let tmpFilterState = tmpRemote.FilterState || {};
47
+ tmpItems = this._applyMediaTypeFilter(tmpItems, tmpFilterState.MediaType || 'all');
48
+
49
+ // 3. Extension filter
50
+ tmpItems = this._applyExtensionFilter(tmpItems, tmpFilterState.Extensions || []);
51
+
52
+ // 4. Size range filter
53
+ tmpItems = this._applySizeFilter(tmpItems, tmpFilterState.SizeMin, tmpFilterState.SizeMax);
54
+
55
+ // 5. Date range filter
56
+ tmpItems = this._applyDateFilter(tmpItems, tmpFilterState);
57
+
58
+ // 6. Sort
59
+ tmpItems = this._sortItems(tmpItems, tmpRemote.SortField || 'folder-first', tmpRemote.SortDirection || 'asc');
60
+
61
+ // Write result
62
+ tmpRemote.GalleryItems = tmpItems;
63
+ tmpRemote.GalleryCursorIndex = 0;
64
+
65
+ // Re-render gallery
66
+ let tmpGalleryView = this.pict.views['RetoldRemote-Gallery'];
67
+ if (tmpGalleryView)
68
+ {
69
+ tmpGalleryView.renderGallery();
70
+ }
71
+ }
72
+
73
+ // ──────────────────────────────────────────────
74
+ // Filter stages
75
+ // ──────────────────────────────────────────────
76
+
77
+ /**
78
+ * Search filter: substring match on item Name.
79
+ */
80
+ _applySearch(pItems, pQuery)
81
+ {
82
+ if (!pQuery)
83
+ {
84
+ return pItems;
85
+ }
86
+
87
+ let tmpQuery = pQuery.toLowerCase();
88
+ return pItems.filter((pItem) =>
89
+ {
90
+ return pItem.Name.toLowerCase().includes(tmpQuery);
91
+ });
92
+ }
93
+
94
+ /**
95
+ * Media type filter: by category. Folders always pass.
96
+ */
97
+ _applyMediaTypeFilter(pItems, pMediaType)
98
+ {
99
+ if (pMediaType === 'all')
100
+ {
101
+ return pItems;
102
+ }
103
+
104
+ return pItems.filter((pItem) =>
105
+ {
106
+ if (pItem.Type === 'folder')
107
+ {
108
+ return true;
109
+ }
110
+
111
+ let tmpCategory = this.getCategory((pItem.Extension || '').toLowerCase());
112
+
113
+ if (pMediaType === 'images') return tmpCategory === 'image';
114
+ if (pMediaType === 'video') return tmpCategory === 'video';
115
+ if (pMediaType === 'audio') return tmpCategory === 'audio';
116
+ if (pMediaType === 'documents') return tmpCategory === 'document';
117
+ return true;
118
+ });
119
+ }
120
+
121
+ /**
122
+ * Extension filter: only matching extensions pass. Folders always pass.
123
+ * An empty array means "all extensions".
124
+ */
125
+ _applyExtensionFilter(pItems, pExtensions)
126
+ {
127
+ if (!pExtensions || pExtensions.length === 0)
128
+ {
129
+ return pItems;
130
+ }
131
+
132
+ // Build a fast lookup set
133
+ let tmpExtSet = {};
134
+ for (let i = 0; i < pExtensions.length; i++)
135
+ {
136
+ tmpExtSet[pExtensions[i].toLowerCase()] = true;
137
+ }
138
+
139
+ return pItems.filter((pItem) =>
140
+ {
141
+ if (pItem.Type === 'folder')
142
+ {
143
+ return true;
144
+ }
145
+ let tmpExt = (pItem.Extension || '').replace(/^\./, '').toLowerCase();
146
+ return tmpExtSet[tmpExt] === true;
147
+ });
148
+ }
149
+
150
+ /**
151
+ * File size range filter. Folders always pass.
152
+ */
153
+ _applySizeFilter(pItems, pMin, pMax)
154
+ {
155
+ if (pMin === null && pMax === null)
156
+ {
157
+ return pItems;
158
+ }
159
+
160
+ return pItems.filter((pItem) =>
161
+ {
162
+ if (pItem.Type === 'folder')
163
+ {
164
+ return true;
165
+ }
166
+ let tmpSize = pItem.Size || 0;
167
+ if (pMin !== null && tmpSize < pMin)
168
+ {
169
+ return false;
170
+ }
171
+ if (pMax !== null && tmpSize > pMax)
172
+ {
173
+ return false;
174
+ }
175
+ return true;
176
+ });
177
+ }
178
+
179
+ /**
180
+ * Date range filter on Modified and/or Created fields. Folders always pass.
181
+ */
182
+ _applyDateFilter(pItems, pDateFilters)
183
+ {
184
+ let tmpModAfter = pDateFilters.DateModifiedAfter ? new Date(pDateFilters.DateModifiedAfter).getTime() : null;
185
+ let tmpModBefore = pDateFilters.DateModifiedBefore ? new Date(pDateFilters.DateModifiedBefore + 'T23:59:59').getTime() : null;
186
+ let tmpCreatedAfter = pDateFilters.DateCreatedAfter ? new Date(pDateFilters.DateCreatedAfter).getTime() : null;
187
+ let tmpCreatedBefore = pDateFilters.DateCreatedBefore ? new Date(pDateFilters.DateCreatedBefore + 'T23:59:59').getTime() : null;
188
+
189
+ if (tmpModAfter === null && tmpModBefore === null && tmpCreatedAfter === null && tmpCreatedBefore === null)
190
+ {
191
+ return pItems;
192
+ }
193
+
194
+ return pItems.filter((pItem) =>
195
+ {
196
+ if (pItem.Type === 'folder')
197
+ {
198
+ return true;
199
+ }
200
+
201
+ if (tmpModAfter !== null || tmpModBefore !== null)
202
+ {
203
+ let tmpMod = pItem.Modified ? new Date(pItem.Modified).getTime() : 0;
204
+ if (tmpModAfter !== null && tmpMod < tmpModAfter) return false;
205
+ if (tmpModBefore !== null && tmpMod > tmpModBefore) return false;
206
+ }
207
+
208
+ if (tmpCreatedAfter !== null || tmpCreatedBefore !== null)
209
+ {
210
+ let tmpCreated = pItem.Created ? new Date(pItem.Created).getTime() : 0;
211
+ if (tmpCreatedAfter !== null && tmpCreated < tmpCreatedAfter) return false;
212
+ if (tmpCreatedBefore !== null && tmpCreated > tmpCreatedBefore) return false;
213
+ }
214
+
215
+ return true;
216
+ });
217
+ }
218
+
219
+ // ──────────────────────────────────────────────
220
+ // Sort
221
+ // ──────────────────────────────────────────────
222
+
223
+ /**
224
+ * Sort items by the specified field and direction.
225
+ */
226
+ _sortItems(pItems, pSortField, pSortDirection)
227
+ {
228
+ let tmpDirection = (pSortDirection === 'desc') ? -1 : 1;
229
+
230
+ return pItems.slice().sort((pA, pB) =>
231
+ {
232
+ // 'folder-first' mode: folders always sort before files
233
+ if (pSortField === 'folder-first')
234
+ {
235
+ if (pA.Type === 'folder' && pB.Type !== 'folder') return -1;
236
+ if (pA.Type !== 'folder' && pB.Type === 'folder') return 1;
237
+ // Both same type: sort by name ascending
238
+ let tmpNameA = (pA.Name || '').toLowerCase();
239
+ let tmpNameB = (pB.Name || '').toLowerCase();
240
+ if (tmpNameA < tmpNameB) return -1 * tmpDirection;
241
+ if (tmpNameA > tmpNameB) return 1 * tmpDirection;
242
+ return 0;
243
+ }
244
+
245
+ if (pSortField === 'name')
246
+ {
247
+ let tmpNameA = (pA.Name || '').toLowerCase();
248
+ let tmpNameB = (pB.Name || '').toLowerCase();
249
+ if (tmpNameA < tmpNameB) return -1 * tmpDirection;
250
+ if (tmpNameA > tmpNameB) return 1 * tmpDirection;
251
+ return 0;
252
+ }
253
+
254
+ if (pSortField === 'modified')
255
+ {
256
+ let tmpDateA = pA.Modified ? new Date(pA.Modified).getTime() : 0;
257
+ let tmpDateB = pB.Modified ? new Date(pB.Modified).getTime() : 0;
258
+ if (tmpDateA !== tmpDateB) return (tmpDateA - tmpDateB) * tmpDirection;
259
+ // Tiebreaker: name ascending
260
+ let tmpNameA = (pA.Name || '').toLowerCase();
261
+ let tmpNameB = (pB.Name || '').toLowerCase();
262
+ return tmpNameA < tmpNameB ? -1 : (tmpNameA > tmpNameB ? 1 : 0);
263
+ }
264
+
265
+ if (pSortField === 'created')
266
+ {
267
+ let tmpDateA = pA.Created ? new Date(pA.Created).getTime() : 0;
268
+ let tmpDateB = pB.Created ? new Date(pB.Created).getTime() : 0;
269
+ if (tmpDateA !== tmpDateB) return (tmpDateA - tmpDateB) * tmpDirection;
270
+ // Tiebreaker: name ascending
271
+ let tmpNameA = (pA.Name || '').toLowerCase();
272
+ let tmpNameB = (pB.Name || '').toLowerCase();
273
+ return tmpNameA < tmpNameB ? -1 : (tmpNameA > tmpNameB ? 1 : 0);
274
+ }
275
+
276
+ return 0;
277
+ });
278
+ }
279
+
280
+ // ──────────────────────────────────────────────
281
+ // Category helper
282
+ // ──────────────────────────────────────────────
283
+
284
+ /**
285
+ * Get the media category for an extension string (with or without leading dot).
286
+ *
287
+ * @param {string} pExtension - e.g. '.png' or 'png'
288
+ * @returns {string} 'image', 'video', 'audio', 'document', or 'other'
289
+ */
290
+ getCategory(pExtension)
291
+ {
292
+ let tmpExt = (pExtension || '').replace(/^\./, '').toLowerCase();
293
+ if (_ImageExtensions[tmpExt]) return 'image';
294
+ if (_VideoExtensions[tmpExt]) return 'video';
295
+ if (_AudioExtensions[tmpExt]) return 'audio';
296
+ if (_DocumentExtensions[tmpExt]) return 'document';
297
+ return 'other';
298
+ }
299
+
300
+ // ──────────────────────────────────────────────
301
+ // Extension helpers for the filter panel
302
+ // ──────────────────────────────────────────────
303
+
304
+ /**
305
+ * Get the unique set of file extensions present in RawFileList.
306
+ * Returns an array of { ext, category, count } grouped by category.
307
+ *
308
+ * @returns {Array}
309
+ */
310
+ getAvailableExtensions()
311
+ {
312
+ let tmpRemote = this.pict.AppData.RetoldRemote;
313
+ let tmpRaw = tmpRemote ? tmpRemote.RawFileList : [];
314
+ let tmpExtMap = {};
315
+
316
+ for (let i = 0; i < tmpRaw.length; i++)
317
+ {
318
+ let tmpItem = tmpRaw[i];
319
+ if (tmpItem.Type === 'folder')
320
+ {
321
+ continue;
322
+ }
323
+ let tmpExt = (tmpItem.Extension || '').replace(/^\./, '').toLowerCase();
324
+ if (!tmpExt)
325
+ {
326
+ continue;
327
+ }
328
+ if (!tmpExtMap[tmpExt])
329
+ {
330
+ tmpExtMap[tmpExt] =
331
+ {
332
+ ext: tmpExt,
333
+ category: this.getCategory(tmpExt),
334
+ count: 0
335
+ };
336
+ }
337
+ tmpExtMap[tmpExt].count++;
338
+ }
339
+
340
+ // Convert to array and sort by category then extension
341
+ let tmpCategoryOrder = { 'image': 0, 'video': 1, 'audio': 2, 'document': 3, 'other': 4 };
342
+ let tmpResult = Object.values(tmpExtMap);
343
+ tmpResult.sort((pA, pB) =>
344
+ {
345
+ let tmpCatA = tmpCategoryOrder[pA.category] || 99;
346
+ let tmpCatB = tmpCategoryOrder[pB.category] || 99;
347
+ if (tmpCatA !== tmpCatB) return tmpCatA - tmpCatB;
348
+ return pA.ext < pB.ext ? -1 : (pA.ext > pB.ext ? 1 : 0);
349
+ });
350
+
351
+ return tmpResult;
352
+ }
353
+
354
+ // ──────────────────────────────────────────────
355
+ // Filter chips
356
+ // ──────────────────────────────────────────────
357
+
358
+ /**
359
+ * Return an array of { key, label } for each non-default filter currently active.
360
+ */
361
+ getActiveFilterChips()
362
+ {
363
+ let tmpRemote = this.pict.AppData.RetoldRemote;
364
+ if (!tmpRemote)
365
+ {
366
+ return [];
367
+ }
368
+
369
+ let tmpChips = [];
370
+ let tmpFilterState = tmpRemote.FilterState || {};
371
+
372
+ // Media type
373
+ if (tmpFilterState.MediaType && tmpFilterState.MediaType !== 'all')
374
+ {
375
+ let tmpLabels = { 'images': 'Images', 'video': 'Video', 'audio': 'Audio', 'documents': 'Docs' };
376
+ tmpChips.push({ key: 'mediaType', label: tmpLabels[tmpFilterState.MediaType] || tmpFilterState.MediaType });
377
+ }
378
+
379
+ // Extensions
380
+ let tmpExtensions = tmpFilterState.Extensions || [];
381
+ if (tmpExtensions.length > 0)
382
+ {
383
+ for (let i = 0; i < tmpExtensions.length; i++)
384
+ {
385
+ tmpChips.push({ key: 'ext:' + tmpExtensions[i], label: '.' + tmpExtensions[i] });
386
+ }
387
+ }
388
+
389
+ // Size
390
+ if (tmpFilterState.SizeMin !== null && tmpFilterState.SizeMin !== undefined)
391
+ {
392
+ tmpChips.push({ key: 'sizeMin', label: '\u2265 ' + this._formatSizeKB(tmpFilterState.SizeMin) });
393
+ }
394
+ if (tmpFilterState.SizeMax !== null && tmpFilterState.SizeMax !== undefined)
395
+ {
396
+ tmpChips.push({ key: 'sizeMax', label: '\u2264 ' + this._formatSizeKB(tmpFilterState.SizeMax) });
397
+ }
398
+
399
+ // Dates
400
+ if (tmpFilterState.DateModifiedAfter)
401
+ {
402
+ tmpChips.push({ key: 'dateModifiedAfter', label: 'Modified after ' + tmpFilterState.DateModifiedAfter });
403
+ }
404
+ if (tmpFilterState.DateModifiedBefore)
405
+ {
406
+ tmpChips.push({ key: 'dateModifiedBefore', label: 'Modified before ' + tmpFilterState.DateModifiedBefore });
407
+ }
408
+ if (tmpFilterState.DateCreatedAfter)
409
+ {
410
+ tmpChips.push({ key: 'dateCreatedAfter', label: 'Created after ' + tmpFilterState.DateCreatedAfter });
411
+ }
412
+ if (tmpFilterState.DateCreatedBefore)
413
+ {
414
+ tmpChips.push({ key: 'dateCreatedBefore', label: 'Created before ' + tmpFilterState.DateCreatedBefore });
415
+ }
416
+
417
+ // Search query
418
+ if (tmpRemote.SearchQuery)
419
+ {
420
+ tmpChips.push({ key: 'search', label: 'Search: "' + tmpRemote.SearchQuery + '"' });
421
+ }
422
+
423
+ return tmpChips;
424
+ }
425
+
426
+ /**
427
+ * Format bytes into a human-readable KB/MB string for chip labels.
428
+ */
429
+ _formatSizeKB(pBytes)
430
+ {
431
+ if (pBytes >= 1048576)
432
+ {
433
+ return (pBytes / 1048576).toFixed(1) + ' MB';
434
+ }
435
+ return Math.round(pBytes / 1024) + ' KB';
436
+ }
437
+
438
+ /**
439
+ * Remove a specific filter by key.
440
+ *
441
+ * @param {string} pKey - e.g. 'mediaType', 'ext:png', 'sizeMin', 'dateModifiedAfter', 'search'
442
+ */
443
+ removeFilter(pKey)
444
+ {
445
+ let tmpRemote = this.pict.AppData.RetoldRemote;
446
+ if (!tmpRemote)
447
+ {
448
+ return;
449
+ }
450
+
451
+ let tmpFilterState = tmpRemote.FilterState;
452
+
453
+ if (pKey === 'mediaType')
454
+ {
455
+ tmpFilterState.MediaType = 'all';
456
+ tmpRemote.GalleryFilter = 'all';
457
+ }
458
+ else if (pKey.startsWith('ext:'))
459
+ {
460
+ let tmpExt = pKey.substring(4);
461
+ tmpFilterState.Extensions = (tmpFilterState.Extensions || []).filter((e) => e !== tmpExt);
462
+ }
463
+ else if (pKey === 'sizeMin')
464
+ {
465
+ tmpFilterState.SizeMin = null;
466
+ }
467
+ else if (pKey === 'sizeMax')
468
+ {
469
+ tmpFilterState.SizeMax = null;
470
+ }
471
+ else if (pKey === 'dateModifiedAfter')
472
+ {
473
+ tmpFilterState.DateModifiedAfter = null;
474
+ }
475
+ else if (pKey === 'dateModifiedBefore')
476
+ {
477
+ tmpFilterState.DateModifiedBefore = null;
478
+ }
479
+ else if (pKey === 'dateCreatedAfter')
480
+ {
481
+ tmpFilterState.DateCreatedAfter = null;
482
+ }
483
+ else if (pKey === 'dateCreatedBefore')
484
+ {
485
+ tmpFilterState.DateCreatedBefore = null;
486
+ }
487
+ else if (pKey === 'search')
488
+ {
489
+ tmpRemote.SearchQuery = '';
490
+ }
491
+ }
492
+
493
+ /**
494
+ * Reset all filters to defaults.
495
+ */
496
+ clearAllFilters()
497
+ {
498
+ let tmpRemote = this.pict.AppData.RetoldRemote;
499
+ if (!tmpRemote)
500
+ {
501
+ return;
502
+ }
503
+
504
+ tmpRemote.SearchQuery = '';
505
+ tmpRemote.GalleryFilter = 'all';
506
+ tmpRemote.FilterState =
507
+ {
508
+ MediaType: 'all',
509
+ Extensions: [],
510
+ SizeMin: null,
511
+ SizeMax: null,
512
+ DateModifiedAfter: null,
513
+ DateModifiedBefore: null,
514
+ DateCreatedAfter: null,
515
+ DateCreatedBefore: null
516
+ };
517
+ }
518
+
519
+ // ──────────────────────────────────────────────
520
+ // Presets
521
+ // ──────────────────────────────────────────────
522
+
523
+ /**
524
+ * Save current filter+sort config as a named preset.
525
+ *
526
+ * @param {string} pName
527
+ */
528
+ savePreset(pName)
529
+ {
530
+ if (!pName)
531
+ {
532
+ return;
533
+ }
534
+
535
+ let tmpRemote = this.pict.AppData.RetoldRemote;
536
+ if (!tmpRemote)
537
+ {
538
+ return;
539
+ }
540
+
541
+ let tmpPreset =
542
+ {
543
+ Name: pName,
544
+ FilterState: JSON.parse(JSON.stringify(tmpRemote.FilterState)),
545
+ SortField: tmpRemote.SortField,
546
+ SortDirection: tmpRemote.SortDirection
547
+ };
548
+
549
+ tmpRemote.FilterPresets = tmpRemote.FilterPresets || [];
550
+ tmpRemote.FilterPresets.push(tmpPreset);
551
+ }
552
+
553
+ /**
554
+ * Load a saved preset and apply its filter+sort config.
555
+ *
556
+ * @param {number} pIndex - index into FilterPresets array
557
+ */
558
+ loadPreset(pIndex)
559
+ {
560
+ let tmpRemote = this.pict.AppData.RetoldRemote;
561
+ if (!tmpRemote || !tmpRemote.FilterPresets)
562
+ {
563
+ return;
564
+ }
565
+
566
+ let tmpPreset = tmpRemote.FilterPresets[pIndex];
567
+ if (!tmpPreset)
568
+ {
569
+ return;
570
+ }
571
+
572
+ tmpRemote.FilterState = JSON.parse(JSON.stringify(tmpPreset.FilterState));
573
+ tmpRemote.GalleryFilter = tmpRemote.FilterState.MediaType || 'all';
574
+ tmpRemote.SortField = tmpPreset.SortField || 'folder-first';
575
+ tmpRemote.SortDirection = tmpPreset.SortDirection || 'asc';
576
+ }
577
+
578
+ /**
579
+ * Delete a saved preset.
580
+ *
581
+ * @param {number} pIndex - index into FilterPresets array
582
+ */
583
+ deletePreset(pIndex)
584
+ {
585
+ let tmpRemote = this.pict.AppData.RetoldRemote;
586
+ if (!tmpRemote || !tmpRemote.FilterPresets)
587
+ {
588
+ return;
589
+ }
590
+
591
+ tmpRemote.FilterPresets.splice(pIndex, 1);
592
+ }
593
+ }
594
+
595
+ GalleryFilterSortProvider.default_configuration = _DefaultProviderConfiguration;
596
+
597
+ module.exports = GalleryFilterSortProvider;