Initial commit of the common code for the Modello UI
[profile/ivi/Modello_Common.git] / js / services / themeengine.js
1 /*global loadScript, Configuration */
2
3 /**
4  * @module Services
5  */
6
7  /**
8  * This class provides unified way to access available themes, detection of theme changes and method of updating selected theme. This component is usually initialized by
9  * {{#crossLink "Bootstrap"}}{{/crossLink}} class and can be later accessed using {{#crossLink "Bootstrap/themeEngine:property"}}{{/crossLink}} object. Component uses
10  * {{#crossLink "Configuration"}}{{/crossLink}} class to persist selected theme in key specified by {{#crossLink "ThemeEngine/selectedThemeKey:property"}}{{/crossLink}}.
11  *
12  * List of available themes is stored in {{#crossLink "ThemeEngine/_themes:property"}}{{/crossLink}} property; new theme can be set using
13  * {{#crossLink "ThemeEngine/setUserTheme:method"}}{{/crossLink}} method.
14  *
15  * To attach to signal indicating update of currencly selected theme use {{#crossLink "ThemeEngine/addStatusListener:method"}}{{/crossLink}} method, e.g.:
16  *
17  *     var listenerId = bootstrap.themeEngine.addStatusListener(function(themeId) {
18  *        // Process theme update
19  *     });
20  *
21  * @class ThemeEngine
22  * @constructor
23  */
24
25 var ThemeEngine = (function() {
26     "use strict";
27     function ThemeEngine() {
28         console.info("Starting up service ThemeEngine");
29     }
30
31     /**
32      * Defines configuration property storing currently selected theme.
33      * @property selectedThemeKey
34      * @type String
35      */
36     ThemeEngine.prototype.selectedThemeKey = "selectedTheme";
37
38     /**
39      * Contains array of attached callbacks.
40      * @property _reloadCallbacks
41      * @private
42      * @type Array
43      */
44     ThemeEngine.prototype._reloadCallbacks = [];
45
46     /**
47      * Contains array of available themes.
48      * @property _themes
49      * @private
50      * @type Array
51      */
52     ThemeEngine.prototype._themes = [
53     {
54         "id": "http://com.intel.tizen/blue",
55         "name": "Blue theme",
56         "type": "user",
57         "version": "0.5.1354227499444",
58         "selected": true,
59         "icon": "icon.png",
60         "iconUrl": "./css/user/blue/icon.png",
61         "_dir": "blue"
62     }, {
63         "id": "http://com.intel.tizen/green",
64         "name": "Green theme",
65         "type": "user",
66         "version": "0.5.0",
67         "icon": "icon.png",
68         "iconUrl": "./css/user/green/icon.png",
69         "selected": false,
70         "_dir": "green"
71     }];
72
73     /**
74      * This method initialize theme engine from configuration object and loads default theme.
75      * @method init
76      * @param callback {function(error)} Callback function called after method is finished. Parameter `error` will contain any error that was intercepted.
77      */
78     ThemeEngine.prototype.init = function(aCallback) {
79         var self = this;
80
81         loadScript('./css/car/components/configuration/configuration.js', function (path, status) {
82             if (status === "ok") {
83                 var storedTheme = Configuration.get("selectedTheme");
84                 self._injectHeaders(storedTheme, function() {
85                     self._updateSelectedTheme();
86
87                     Configuration.addUpdateListener(function() {
88                         var id = Configuration.get("selectedTheme");
89                         var selectedTheme = self.getSelectedTheme();
90                         if (!selectedTheme || selectedTheme.id !== id) {
91                             self._injectHeaders(id, function() {
92                                 self._updateSelectedTheme();
93
94                                 $(self._reloadCallbacks).each(function() {
95                                     this(id);
96                                 });
97                             });
98                         }
99                     });
100                     aCallback();
101                 });
102             }
103             else {
104                 aCallback(status);
105             }
106         });
107     };
108
109     /**
110      * Method adds update listener which is fired after theme is changed.
111      * @method addStatusListener
112      * @param callback {function()} Callback to be invoked after theme is changed.
113      * @return {Integer} ID that can be used for removal of status listener.
114      */
115     ThemeEngine.prototype.addStatusListener = function(callback) {
116         this._reloadCallbacks.push(callback);
117     };
118
119     ThemeEngine.prototype._updateSelectedTheme = function () {
120         var selectedTheme = Configuration.get(this.selectedThemeKey);
121
122         for(var i = 0; i < this._themes.length; i++) {
123             this._themes[i].selected = this._themes[i].id === Configuration.get(this.selectedThemeKey);
124         }
125     };
126
127     /**
128      * Method executes callback method with array of available themes as parameter.
129      * @method getUserThemes
130      * @param callback {function(themes)} Callback with array of available themes.
131      */
132     ThemeEngine.prototype.getUserThemes = function(callback) {
133         var self = this;
134         window.setTimeout(function() {
135             callback(self._themes);
136         }, 200);
137     };
138
139      /**
140      * Method sets new user theme identified by theme ID in case that this theme isn't currently selected.
141      * @method setUserTheme
142      * @param id {String} ID of theme that should be set.
143      */
144     ThemeEngine.prototype.setUserTheme = function(id) {
145         var prevTheme = Configuration.get("selectedTheme");
146         id = id || prevTheme;
147         id = id ||  "http://com.intel.tizen/blue";
148
149         if(prevTheme !== id) {
150             Configuration.set(this.selectedThemeKey, id);
151         }
152     };
153
154     /**
155      * Method returns information about one user theme identified by theme ID.
156      * @method getSelectedTheme
157      * @param id {String} ID of theme that should be set.
158      */
159     ThemeEngine.prototype.getSelectedTheme = function() {
160         for(var i = 0; i < this._themes.length; ++i) {
161             if (this._themes[i].selected) {
162                 return this._themes[i];
163             }
164         }
165         return null;
166     };
167
168     ThemeEngine.prototype._injectHeaders = function(id, callback) {
169         callback = callback || function() {};
170         var self = this;
171
172         $(this._themes).each(function() {
173             var theme = this;
174             //remove all previous theme .js
175             $('script[src="./css/user/' + theme._dir + '/user.js"]').remove();
176
177             if (theme.id === id) {
178                 $("head > *").each(function() {
179                     if ($(this).data("theme") === "user") {
180                         $(this).remove();
181                     }
182                 });
183
184                 $('<link data-theme="user" rel="stylesheet" href="./css/user/' + theme._dir + '/user.css" />').appendTo("head");
185
186                 loadScript('./css/user/' + theme._dir + '/user.js', function(aPath, aStatus) {
187                     if (aStatus === "ok") {
188                        callback(id);
189                     }
190                 },true);
191             }
192         });
193     };
194
195     window.__themeengine = undefined === window.__themeengine ? new ThemeEngine() : window.__themeengine;
196     return window.__themeengine;
197 })();