[FEATURE] Store icons in localStorage
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Resources / Private / TypeScript / Icons.ts
1 /*
2  * This file is part of the TYPO3 CMS project.
3  *
4  * It is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU General Public License, either version 2
6  * of the License, or any later version.
7  *
8  * For the full copyright and license information, please read the
9  * LICENSE.txt file that was distributed with this source code.
10  *
11  * The TYPO3 project - inspiring people to share!
12  */
13
14 import * as $ from 'jquery';
15 import ClientStorage = require('./Storage/Client');
16
17 enum Sizes {
18   small = 'small',
19   default = 'default',
20   large = 'large',
21   overlay = 'overlay'
22 }
23
24 enum States {
25   default = 'default',
26   disabled = 'disabled'
27 }
28
29 enum MarkupIdentifiers {
30   default = 'default',
31   inline = 'inline'
32 }
33
34 interface PromiseCache {
35   [key: string]: JQueryPromise<any>;
36 }
37
38 /**
39  * Module: TYPO3/CMS/Backend/Icons
40  * Uses the icon API of the core to fetch icons via AJAX.
41  */
42 class Icons {
43   public readonly sizes: any = Sizes;
44   public readonly states: any = States;
45   public readonly markupIdentifiers: any = MarkupIdentifiers;
46   private readonly promiseCache: PromiseCache = {};
47
48   /**
49    * Get the icon by its identifier
50    *
51    * @param {string} identifier
52    * @param {Sizes} size
53    * @param {string} overlayIdentifier
54    * @param {string} state
55    * @param {MarkupIdentifiers} markupIdentifier
56    * @returns {JQueryPromise<any>}
57    */
58   public getIcon(identifier: string,
59                  size: Sizes,
60                  overlayIdentifier?: string,
61                  state?: string,
62                  markupIdentifier?: MarkupIdentifiers): JQueryPromise<any> {
63
64     /**
65      * Icon keys:
66      *
67      * 0: identifier
68      * 1: size
69      * 2: overlayIdentifier
70      * 3: state
71      * 4: markupIdentifier
72      */
73     size = size || Sizes.default;
74     state = state || States.default;
75     markupIdentifier = markupIdentifier || MarkupIdentifiers.default;
76
77     const describedIcon = [identifier, size, overlayIdentifier, state, markupIdentifier];
78     const cacheIdentifier = describedIcon.join('_');
79
80     return $.when(this.getIconRegistryCache()).pipe((registryCacheIdentifier: string): any => {
81       if (!ClientStorage.isset('icon_registry_cache_identifier')
82         || ClientStorage.get('icon_registry_cache_identifier') !== registryCacheIdentifier
83       ) {
84         ClientStorage.unsetByPrefix('icon_');
85         ClientStorage.set('icon_registry_cache_identifier', registryCacheIdentifier);
86       }
87
88       return this.fetchFromLocal(cacheIdentifier).then(null, (): any => {
89         return this.fetchFromRemote(describedIcon, cacheIdentifier);
90       });
91     });
92   }
93
94   private getIconRegistryCache(): JQueryPromise<any> {
95     const promiseCacheIdentifier = 'icon_registry_cache_identifier';
96
97     if (!this.isPromiseCached(promiseCacheIdentifier)) {
98       this.putInPromiseCache(promiseCacheIdentifier, $.ajax({
99         url: TYPO3.settings.ajaxUrls.icons_cache,
100         success: (response: string): string => {
101           return response;
102         }
103       }));
104     }
105
106     return this.getFromPromiseCache(promiseCacheIdentifier);
107   }
108
109   /**
110    * Performs the AJAX request to fetch the icon
111    *
112    * @param {Array<string>} icon
113    * @param {string} cacheIdentifier
114    * @returns {JQueryPromise<any>}
115    */
116   private fetchFromRemote(icon: Array<string>, cacheIdentifier: string): JQueryPromise<any> {
117     if (!this.isPromiseCached(cacheIdentifier)) {
118       this.putInPromiseCache(cacheIdentifier, $.ajax({
119         url: TYPO3.settings.ajaxUrls.icons,
120         dataType: 'html',
121         data: {
122           icon: JSON.stringify(icon)
123         },
124         success: (markup: string) => {
125           ClientStorage.set('icon_' + cacheIdentifier, markup);
126           return markup;
127         }
128       }));
129     }
130     return this.getFromPromiseCache(cacheIdentifier);
131   }
132
133   /**
134    * Gets the icon from localStorage
135    * @param {string} cacheIdentifier
136    * @returns {JQueryPromise<any>}
137    */
138   private fetchFromLocal(cacheIdentifier: string): JQueryPromise<any> {
139     const deferred = $.Deferred();
140     if (ClientStorage.isset('icon_' + cacheIdentifier)) {
141       deferred.resolve(ClientStorage.get('icon_' + cacheIdentifier));
142     } else {
143       deferred.reject();
144     }
145
146     return deferred.promise();
147   }
148
149   /**
150    * Check whether icon was fetched already
151    *
152    * @param {string} cacheIdentifier
153    * @returns {boolean}
154    */
155   private isPromiseCached(cacheIdentifier: string): boolean {
156     return typeof this.promiseCache[cacheIdentifier] !== 'undefined';
157   }
158
159   /**
160    * Get icon from cache
161    *
162    * @param {string} cacheIdentifier
163    * @returns {JQueryPromise<any>}
164    */
165   private getFromPromiseCache(cacheIdentifier: string): JQueryPromise<any> {
166     return this.promiseCache[cacheIdentifier];
167   }
168
169   /**
170    * Put icon into cache
171    *
172    * @param {string} cacheIdentifier
173    * @param {JQueryPromise<any>} markup
174    */
175   private putInPromiseCache(cacheIdentifier: string, markup: JQueryPromise<any>): void {
176     this.promiseCache[cacheIdentifier] = markup;
177   }
178 }
179
180 let iconsObject: Icons;
181 if (!iconsObject) {
182   iconsObject = new Icons();
183   TYPO3.Icons = iconsObject;
184 }
185
186 export = iconsObject;