Fixes #4189: theme box fails when entering second theme.
[redakcja.git] / src / redakcja / static / js / wiki_img / base.js
1 (function($)
2 {
3         var noop = function() { };
4
5         $.wiki = {
6                 perspectives: {},
7                 cls: {},
8                 state: {
9                         "version": 1,
10                         "perspectives": {
11                 "CodeMirrorPerspective": {}
12                         }
13                 }
14         };
15
16         $.wiki.loadConfig = function() {
17                 if(!window.localStorage)
18                         return;
19
20                 try {
21                         var value = window.localStorage.getItem(CurrentDocument.id) || "{}";
22                         var config = JSON.parse(value);
23
24                         if (config.version == $.wiki.state.version) {
25                                 $.wiki.state.perspectives = $.extend($.wiki.state.perspectives, config.perspectives);
26                         }
27                 } catch(e) {
28                         console.log("Failed to load config, using default.");
29                 }
30
31                 console.log("Loaded:", $.wiki.state, $.wiki.state.version);
32         };
33
34         $(window).bind('unload', function() {
35                 if(window.localStorage)
36                         window.localStorage.setItem(CurrentDocument.id, JSON.stringify($.wiki.state));
37         })
38
39
40         $.wiki.activePerspective = function() {
41             return this.perspectives[$("#tabs li a.active").parent().attr('id')];
42         };
43
44         $.wiki.exitContext = function() {
45                 var ap = this.activePerspective();
46                 if(ap) ap.onExit();
47                 return ap;
48         };
49
50         $.wiki.enterContext = function(ap) {
51                 if(ap) ap.onEnter();
52         };
53
54         $.wiki.isDirty = function() {
55                 var ap = this.activePerspective();
56                 return (!!CurrentDocument && CurrentDocument.has_local_changes) || ap.dirty();
57         };
58
59         $.wiki.newTab = function(doc, title, klass) {
60                 var base_id = 'id' + Math.floor(Math.random()* 5000000000);
61                 var id = (''+klass)+'_' + base_id;
62                 var $tab = $('<li id="'+id+'" data-ui-related="'+base_id+'" data-ui-jsclass="'+klass+'" >'
63                              + title + '<img src="'+STATIC_URL+'icons/close.png" class="tabclose"></li>');
64                 var $tab = $('<li class="nav-item" id="'+id+'" data-ui-related="'+base_id+'" data-ui-jsclass="'+klass+'" ><a href="#" class="nav-link">'
65                          + title + ' <span class="badge badge-danger tabclose">x</span></a></li>');
66
67                 var $view = $('<div class="editor '+klass+'" id="'+base_id+'"> </div>');
68
69                 this.perspectives[id] = new $.wiki[klass]({
70                         doc: doc,
71                         id: id,
72                         base_id: base_id,
73                 });
74
75                 $('#tabs').append($tab);
76                 $view.hide().appendTo('#editor');
77                 return {
78                         tab: $tab[0],
79                         view: $view[0],
80                 };
81         };
82
83         $.wiki.initTab = function(options) {
84                 var klass = $(options.tab).attr('data-ui-jsclass');
85
86                 return new $.wiki[klass]({
87                         doc: options.doc,
88                         id: $(options.tab).attr('id'),
89                         callback: function() {
90                                 $.wiki.perspectives[this.perspective_id] = this;
91                                 if(options.callback)
92                                         options.callback.call(this);
93                         }
94                 });
95         };
96
97         $.wiki.perspectiveForTab = function(tab) { // element or id
98                 return this.perspectives[ $(tab).attr('id')];
99         }
100
101         $.wiki.switchToTab = function(tab){
102             var self = this;
103             var $tab = $(tab);
104
105             if($tab.length != 1)
106                 $tab = $(DEFAULT_PERSPECTIVE);
107
108             var $old_a = $tab.closest('.tabs').find('.active');
109
110             $old_a.each(function(){
111                 var tab = $(this).parent();
112                 $(this).removeClass('active');
113                 self.perspectives[tab.attr('id')].onExit();
114                 $('#' + tab.attr('data-ui-related')).hide();
115             });
116
117             /* show new */
118             $('a', tab).addClass('active');
119             $('#' + $tab.attr('data-ui-related')).show();
120
121             console.log($tab);
122             console.log($.wiki.perspectives);
123
124             $.wiki.perspectives[$tab.attr('id')].onEnter();
125         };
126
127         /*
128          * Basic perspective.
129          */
130         $.wiki.Perspective = function(options) {
131                 if(!options) return;
132
133                 this.doc = options.doc;
134                 if (options.id) {
135                         this.perspective_id = options.id;
136                 }
137                 else {
138                         this.perspective_id = '';
139                 }
140
141                 if(options.callback)
142                         options.callback.call(this);
143         };
144
145         $.wiki.Perspective.prototype.config = function() {
146                 return $.wiki.state.perspectives[this.perspective_id];
147         }
148
149         $.wiki.Perspective.prototype.toString = function() {
150                 return this.perspective_id;
151         };
152
153         $.wiki.Perspective.prototype.dirty = function() {
154                 return true;
155         };
156
157         $.wiki.Perspective.prototype.onEnter = function () {
158                 // called when perspective in initialized
159                 if (!this.noupdate_hash_onenter) {
160                         document.location.hash = '#' + this.perspective_id;
161                 }
162         };
163
164         $.wiki.Perspective.prototype.onExit = function () {
165                 // called when user switches to another perspective
166                 if (!this.noupdate_hash_onenter) {
167                         document.location.hash = '';
168                 }
169         };
170
171         $.wiki.Perspective.prototype.destroy = function() {
172                 // pass
173         };
174
175         $.wiki.Perspective.prototype.freezeState = function () {
176                 // free UI state (don't store data here)
177         };
178
179         $.wiki.Perspective.prototype.unfreezeState = function (frozenState) {
180                 // restore UI state
181         };
182
183         /*
184          * Stub rendering (used in generating history)
185          */
186         $.wiki.renderStub = function(params)
187         {
188                 params = $.extend({ 'filters': {} }, params);
189                 var $elem = params.stub.clone();
190                 $elem.removeClass('row-stub');
191                 params.container.append($elem);
192
193                 $('*[data-stub-value]', $elem).each(function() {
194                         var $this = $(this);
195                         var field = $this.attr('data-stub-value');
196
197                         var value = params.data[field];
198
199                         if(params.filters[field])
200                                 value = params.filters[field](value);
201
202                         if(value === null || value === undefined) return;
203
204                         if(!$this.attr('data-stub-target')) {
205                                 $this.text(value);
206                         }
207                         else {
208                                 $this.attr($this.attr('data-stub-target'), value);
209                                 $this.removeAttr('data-stub-target');
210                                 $this.removeAttr('data-stub-value');
211                         }
212                 });
213
214                 $elem.show();
215                 return $elem;
216         };
217
218         /*
219          * Dialogs
220          */
221         function GenericDialog(element) {
222                 if(!element) return;
223
224                 var self = this;
225
226                 self.$elem = $(element);
227
228                 if(!self.$elem.attr('data-ui-initialized')) {
229                         console.log("Initializing dialog", this);
230                         self.initialize();
231                         self.$elem.attr('data-ui-initialized', true);
232                 }
233
234                 self.show();
235         };
236
237         GenericDialog.prototype = {
238
239                 /*
240                 * Steps to follow when the dialog in first loaded on page.
241                 */
242                 initialize: function(){
243                         var self = this;
244
245                         /* bind buttons */
246                         $('button[data-ui-action]', self.$elem).click(function(event) {
247                                 event.preventDefault();
248
249                                 var action = $(this).attr('data-ui-action');
250                                 console.log("Button pressed, action: ", action);
251
252                                 try {
253                                         self[action + "Action"].call(self);
254                                 } catch(e) {
255                                         console.log("Action failed:", e);
256                                         // always hide on cancel
257                                         if(action == 'cancel')
258                                                 self.hide();
259                                 }
260                         });
261                 },
262
263                 /*
264                  * Prepare dialog for user. Clear any unnessary data.
265                 */
266                 show: function() {
267                         $.blockUI({
268                                 message: this.$elem,
269                                 css: {
270                                         'top': '25%',
271                                         'left': '25%',
272                                         'width': '50%'
273                                 }
274                         });
275                 },
276
277                 hide: function(){
278                         $.unblockUI();
279                 },
280
281                 cancelAction: function() {
282                         this.hide();
283                 },
284
285                 doneAction: function() {
286                         this.hide();
287                 },
288
289                 clearForm: function() {
290                         $("*[data-ui-error-for]", this.$elem).text('');
291                 },
292
293                 reportErrors: function(errors) {
294                         var global = $("*[data-ui-error-for='__all__']", this.$elem);
295                         var unassigned = [];
296
297                         for (var field_name in errors)
298                         {
299                                 var span = $("*[data-ui-error-for='"+field_name+"']", this.$elem);
300
301                                 if(!span.length) {
302                                         unassigned.push(field_name);
303                                         continue;
304                                 }
305
306                                 span.text(errors[field_name].join(' '));
307                         }
308
309                         if(unassigned.length > 0)
310                                 global.text( global.text() + 'W formularzu wystąpiły błędy');
311                 }
312         };
313
314         $.wiki.cls.GenericDialog = GenericDialog;
315
316         $.wiki.showDialog = function(selector, options) {
317                 var elem = $(selector);
318
319                 if(elem.length != 1) {
320                         console.log("Failed to show dialog:", selector, elem);
321                         return false;
322                 }
323
324                 try {
325                     var klass = elem.attr('data-ui-jsclass');
326                         return new $.wiki.cls[klass](elem, options);
327                 } catch(e) {
328                         console.log("Failed to show dialog", selector, klass, e);
329                         return false;
330                 }
331         };
332
333 })(jQuery);