3685fd3f43e53f054a4097bf0730d0ca2825fd79
[portal/sdk.git] /
1 /*
2  * Copyright (c) 2014 DataTorrent, Inc. ALL Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 'use strict';
18
19 angular.module('ui.dashboard')
20   .factory('LayoutStorage', function() {
21
22     var noopStorage = {
23       setItem: function() {
24
25       },
26       getItem: function() {
27
28       },
29       removeItem: function() {
30
31       }
32     };
33
34     
35
36     function LayoutStorage(options) {
37
38       var defaults = {
39         storage: noopStorage,
40         storageHash: '',
41         stringifyStorage: true
42       };
43
44       angular.extend(defaults, options);
45       angular.extend(options, defaults);
46
47       this.id = options.storageId;
48       this.storage = options.storage;
49       this.storageHash = options.storageHash;
50       this.stringifyStorage = options.stringifyStorage;
51       this.widgetDefinitions = options.widgetDefinitions;
52       this.defaultLayouts = options.defaultLayouts;
53       this.lockDefaultLayouts = options.lockDefaultLayouts;
54       this.widgetButtons = options.widgetButtons;
55       this.explicitSave = options.explicitSave;
56       this.defaultWidgets = options.defaultWidgets;
57       this.settingsModalOptions = options.settingsModalOptions;
58       this.onSettingsClose = options.onSettingsClose;
59       this.onSettingsDismiss = options.onSettingsDismiss;
60       this.options = options;
61       this.options.unsavedChangeCount = 0;
62
63       this.layouts = [];
64       this.states = {};
65       this.load();
66       this._ensureActiveLayout();
67     }
68
69     LayoutStorage.prototype = {
70
71       add: function(layouts) {
72         if (!angular.isArray(layouts)) {
73           layouts = [layouts];
74         }
75         var self = this;
76         angular.forEach(layouts, function(layout) {
77           layout.dashboard = layout.dashboard || {};
78           layout.dashboard.storage = self;
79           layout.dashboard.storageId = layout.id = self._getLayoutId.call(self,layout);
80           layout.dashboard.widgetDefinitions = layout.widgetDefinitions || self.widgetDefinitions;
81           layout.dashboard.stringifyStorage = false;
82           layout.dashboard.defaultWidgets = layout.defaultWidgets || self.defaultWidgets;
83           layout.dashboard.widgetButtons = self.widgetButtons;
84           layout.dashboard.explicitSave = self.explicitSave;
85           layout.dashboard.settingsModalOptions = self.settingsModalOptions;
86           layout.dashboard.onSettingsClose = self.onSettingsClose;
87           layout.dashboard.onSettingsDismiss = self.onSettingsDismiss;
88           self.layouts.push(layout);
89         });
90       },
91
92       remove: function(layout) {
93         var index = this.layouts.indexOf(layout);
94         if (index >= 0) {
95           this.layouts.splice(index, 1);
96           delete this.states[layout.id];
97
98           // check for active
99           if (layout.active && this.layouts.length) {
100             var nextActive = index > 0 ? index - 1 : 0;
101             this.layouts[nextActive].active = true;
102           }
103         }
104       },
105
106       save: function() {
107
108         var state = {
109           layouts: this._serializeLayouts(),
110           states: this.states,
111           storageHash: this.storageHash
112         };
113
114         if (this.stringifyStorage) {
115           state = JSON.stringify(state);
116         }
117
118         this.storage.setItem(this.id, state);
119         this.options.unsavedChangeCount = 0;
120       },
121
122       load: function() {
123
124         var serialized = this.storage.getItem(this.id);
125
126         this.clear();
127
128         if (serialized) {
129           // check for promise
130           if (angular.isObject(serialized) && angular.isFunction(serialized.then)) {
131             this._handleAsyncLoad(serialized);
132           } else {
133             this._handleSyncLoad(serialized);
134           }
135         } else {
136           this._addDefaultLayouts();
137         }
138       },
139
140       clear: function() {
141         this.layouts = [];
142         this.states = {};
143       },
144
145       setItem: function(id, value) {
146         this.states[id] = value;
147         this.save();
148       },
149
150       getItem: function(id) {
151         return this.states[id];
152       },
153
154       removeItem: function(id) {
155         delete this.states[id];
156         this.save();
157       },
158
159       getActiveLayout: function() {
160         var len = this.layouts.length;
161         for (var i = 0; i < len; i++) {
162           var layout = this.layouts[i];
163           if (layout.active) {
164             return layout;
165           }
166         }
167         return false;
168       },
169
170       _addDefaultLayouts: function() {
171         var self = this;
172         var defaults = this.lockDefaultLayouts ? { locked: true } : {};
173         angular.forEach(this.defaultLayouts, function(layout) {
174           self.add(angular.extend(_.clone(defaults), layout));
175         });
176       },
177
178       _serializeLayouts: function() {
179         var result = [];
180         angular.forEach(this.layouts, function(l) {
181           result.push({
182             title: l.title,
183             id: l.id,
184             active: l.active,
185             locked: l.locked,
186             defaultWidgets: l.dashboard.defaultWidgets
187           });
188         });
189         return result;
190       },
191
192       _handleSyncLoad: function(serialized) {
193         
194         var deserialized;
195
196         if (this.stringifyStorage) {
197           try {
198
199             deserialized = JSON.parse(serialized);
200
201           } catch (e) {
202             this._addDefaultLayouts();
203             return;
204           }
205         } else {
206
207           deserialized = serialized;
208
209         }
210
211         if (this.storageHash !== deserialized.storageHash) {
212           this._addDefaultLayouts();
213           return;
214         }
215         this.states = deserialized.states;
216         this.add(deserialized.layouts);
217       },
218
219       _handleAsyncLoad: function(promise) {
220         var self = this;
221         promise.then(
222           angular.bind(self, this._handleSyncLoad),
223           angular.bind(self, this._addDefaultLayouts)
224         );
225       },
226
227       _ensureActiveLayout: function() {
228         for (var i = 0; i < this.layouts.length; i++) {
229           var layout = this.layouts[i];
230           if (layout.active) {
231             return;
232           }
233         }
234         if (this.layouts[0]) {
235           this.layouts[0].active = true;
236         }
237       },
238
239       _getLayoutId: function(layout) {
240         if (layout.id) {
241           return layout.id;
242         }
243         var max = 0;
244         for (var i = 0; i < this.layouts.length; i++) {
245           var id = this.layouts[i].id;
246           max = Math.max(max, id * 1);
247         }
248         return max + 1;
249       }
250
251     };
252     return LayoutStorage;
253   });