Automatically search for the next match after single replace, fixes #3384
[redakcja.git] / redakcja / static / js / wiki_img / wikiapi.js
1 (function($) {
2         $.wikiapi = {};
3         var noop = function() {
4         };
5         var noops = {
6                 success: noop,
7                 failure: noop
8         };
9         /*
10          * Return absolute reverse path of given named view. (at least he have it
11          * hard-coded in one place)
12          *
13          * TODO: think of a way, not to hard-code it here ;)
14          *
15          */
16         function reverse() {
17                 var vname = arguments[0];
18                 var base_path = "/images";
19
20                 if (vname == "ajax_document_text") {
21                         return base_path + "/text/" + arguments[1] + "/";
22                 }
23
24         if (vname == "ajax_document_revert") {
25             return base_path + "/revert/" + arguments[1] + '/';
26         }
27
28                 if (vname == "ajax_document_history") {
29                         return base_path + "/history/" + arguments[1] + '/';
30                 }
31
32                 if (vname == "ajax_document_diff")
33                         return base_path + "/diff/" + arguments[1] + '/';
34
35                 if (vname == "ajax_document_pubmark")
36                         return base_path + "/pubmark/" + arguments[1] + '/';
37
38                 console.log("Couldn't reverse match:", vname);
39                 return "/404.html";
40         };
41
42         /*
43          * Document Abstraction
44          */
45         function WikiDocument(element_id) {
46                 var meta = $('#' + element_id);
47                 this.id = meta.attr('data-object-id');
48
49                 this.revision = $("*[data-key='revision']", meta).text();
50                 this.readonly = !!$("*[data-key='readonly']", meta).text();
51
52         var diff = $("*[data-key='diff']", meta).text();
53         if (diff) {
54             diff = diff.split(',');
55             if (diff.length == 2 && diff[0] < diff[1])
56                 this.diff = diff;
57             else if (diff.length == 1) {
58                 diff = parseInt(diff);
59                 if (diff != NaN)
60                     this.diff = [diff - 1, diff];
61             }
62         }
63
64                 this.text = null;
65                 this.has_local_changes = false;
66                 this._lock = -1;
67                 this._context_lock = -1;
68                 this._lock_count = 0;
69         };
70
71         WikiDocument.prototype.triggerDocumentChanged = function() {
72                 $(document).trigger('wlapi_document_changed', this);
73         };
74         /*
75          * Fetch text of this document.
76          */
77         WikiDocument.prototype.fetch = function(params) {
78                 params = $.extend({}, noops, params);
79                 var self = this;
80                 $.ajax({
81                         method: "GET",
82                         url: reverse("ajax_document_text", self.id),
83                         data: {"commit": self.commit},
84                         dataType: 'json',
85                         success: function(data) {
86                                 var changed = false;
87
88                                 if (self.text === null || self.commit !== data.commit) {
89                                         self.text = data.text;
90                                         if (self.text === '') {
91                                             self.text = '<picture></picture>';
92                                         }
93                                         self.revision = data.revision;
94                     self.commit = data.commit;
95                                         changed = true;
96                                         self.triggerDocumentChanged();
97                                 };
98
99                                 self.has_local_changes = false;
100                                 params['success'](self, changed);
101                         },
102                         error: function() {
103                                 params['failure'](self, "Nie udało się wczytać treści dokumentu.");
104                         }
105                 });
106         };
107         /*
108          * Fetch history of this document.
109          *
110          * from - First revision to fetch (default = 0) upto - Last revision to
111          * fetch (default = tip)
112          *
113          */
114         WikiDocument.prototype.fetchHistory = function(params) {
115                 /* this doesn't modify anything, so no locks */
116                 params = $.extend({}, noops, params);
117                 var self = this;
118                 $.ajax({
119                         method: "GET",
120                         url: reverse("ajax_document_history", self.id),
121                         dataType: 'json',
122                         data: {
123                                 "from": params['from'],
124                                 "upto": params['upto']
125                         },
126                         success: function(data) {
127                                 params['success'](self, data);
128                         },
129                         error: function() {
130                                 params['failure'](self, "Nie udało się wczytać historii dokumentu.");
131                         }
132                 });
133         };
134         WikiDocument.prototype.fetchDiff = function(params) {
135                 /* this doesn't modify anything, so no locks */
136                 var self = this;
137                 params = $.extend({
138                         'from': self.revision,
139                         'to': self.revision
140                 }, noops, params);
141                 $.ajax({
142                         method: "GET",
143                         url: reverse("ajax_document_diff", self.id),
144                         dataType: 'html',
145                         data: {
146                                 "from": params['from'],
147                                 "to": params['to']
148                         },
149                         success: function(data) {
150                                 params['success'](self, data);
151                         },
152                         error: function() {
153                                 params['failure'](self, "Nie udało się wczytać porównania wersji.");
154                         }
155                 });
156         };
157
158         /*
159          * Set document's text
160          */
161         WikiDocument.prototype.setText = function(text) {
162                 this.text = text;
163                 this.has_local_changes = true;
164         };
165
166         /*
167          * Save text back to the server
168          */
169         WikiDocument.prototype.save = function(params) {
170                 params = $.extend({}, noops, params);
171                 var self = this;
172
173                 if (!self.has_local_changes) {
174                         console.log("Abort: no changes.");
175                         return params['success'](self, false, "Nie ma zmian do zapisania.");
176                 };
177
178                 // Serialize form to dictionary
179                 var data = {};
180                 $.each(params['form'].serializeArray(), function() {
181                         data[this.name] = this.value;
182                 });
183
184                 data['textsave-text'] = self.text;
185
186                 $.ajax({
187                         url: reverse("ajax_document_text", self.id),
188                         type: "POST",
189                         dataType: "json",
190                         data: data,
191                         success: function(data) {
192                                 var changed = false;
193
194                 $('#header').removeClass('saving');
195
196                                 if (data.text) {
197                                         self.text = data.text;
198                                         self.revision = data.revision;
199                     self.commit = data.commit;
200                                         changed = true;
201                                         self.triggerDocumentChanged();
202                                 };
203
204                                 params['success'](self, changed, ((changed && "Udało się zapisać :)") || "Twoja wersja i serwera jest identyczna"));
205                         },
206                         error: function(xhr) {
207                 if ($('#header').hasClass('saving')) {
208                     $('#header').removeClass('saving');
209                     $.blockUI({
210                         message: "<p>Nie udało się zapisać zmian. <br/><button onclick='$.unblockUI()'>OK</button></p>"
211                     })
212                 }
213                 else {
214                     try {
215                         params['failure'](self, $.parseJSON(xhr.responseText));
216                     }
217                     catch (e) {
218                         params['failure'](self, {
219                             "__message": "<p>Nie udało się zapisać - błąd serwera.</p>"
220                         });
221                     };
222                 }
223
224                         }
225                 });
226
227         $('#save-hide').click(function(){
228             $('#header').addClass('saving');
229             $.unblockUI();
230             $.wiki.blocking.unblock();
231         });
232         }; /* end of save() */
233
234     WikiDocument.prototype.revertToVersion = function(params) {
235         var self = this;
236         params = $.extend({}, noops, params);
237
238         if (params.revision >= this.revision) {
239             params.failure(self, 'Proszę wybrać rewizję starszą niż aktualna.');
240             return;
241         }
242
243         // Serialize form to dictionary
244         var data = {};
245         $.each(params['form'].serializeArray(), function() {
246             data[this.name] = this.value;
247         });
248
249         $.ajax({
250             url: reverse("ajax_document_revert", self.id),
251             type: "POST",
252             dataType: "json",
253             data: data,
254             success: function(data) {
255                 if (data.text) {
256                     self.text = data.text;
257                     self.revision = data.revision;
258                     self.gallery = data.gallery;
259                     self.triggerDocumentChanged();
260
261                     params.success(self, "Udało się przywrócić wersję :)");
262                 }
263                 else {
264                     params.failure(self, "Przywracana wersja identyczna z aktualną. Anulowano przywracanie.");
265                 }
266             },
267             error: function(xhr) {
268                 params.failure(self, "Nie udało się przywrócić wersji - błąd serwera.");
269             }
270         });
271     };
272
273         WikiDocument.prototype.pubmark = function(params) {
274                 params = $.extend({}, noops, params);
275                 var self = this;
276                 var data = {
277                         "pubmark-id": self.id,
278                 };
279
280                 /* unpack form */
281                 $.each(params.form.serializeArray(), function() {
282                         data[this.name] = this.value;
283                 });
284
285                 $.ajax({
286                         url: reverse("ajax_document_pubmark", self.id),
287                         type: "POST",
288                         dataType: "json",
289                         data: data,
290                         success: function(data) {
291                                 params.success(self, data.message);
292                         },
293                         error: function(xhr) {
294                                 if (xhr.status == 403 || xhr.status == 401) {
295                                         params.failure(self, {
296                                                 "__all__": ["Nie masz uprawnień lub nie jesteś zalogowany."]
297                                         });
298                                 }
299                                 else {
300                                         try {
301                                                 params.failure(self, $.parseJSON(xhr.responseText));
302                                         }
303                                         catch (e) {
304                                                 params.failure(self, {
305                                                         "__all__": ["Nie udało się - błąd serwera."]
306                                                 });
307                                         };
308                                 };
309                         }
310                 });
311         };
312
313
314
315     WikiDocument.prototype.getImageItems = function(tag) {
316         var self = this;
317
318         var parser = new DOMParser();
319         var doc = parser.parseFromString(self.text, 'text/xml');
320         var error = $('parsererror', doc);
321
322         if (error.length != 0) {
323             return null;
324         }
325
326         var a = [];
327         $('sem[type="'+tag+'"]', doc).each(function(i, e) {
328             var $e = $(e);
329             var $div = $e.children().first()
330             var value = $e.attr(tag);
331             $e.find('div').each(function(i, div) {
332                 var $div = $(div);
333                 switch ($div.attr('type')) {
334                     case 'rect':
335                         a.push([
336                             value,
337                             $div.attr('x1'),
338                             $div.attr('y1'),
339                             $div.attr('x2'),
340                             $div.attr('y2')
341                         ]);
342                         break;
343                     case 'whole':
344                         a.push([
345                             value,
346                             null, null, null, null
347                         ]);
348                         break
349                 }
350             });
351         });
352
353         return a;
354     }
355
356     WikiDocument.prototype.setImageItems = function(tag, items) {
357         var self = this;
358
359         var parser = new DOMParser();
360         var doc = parser.parseFromString(self.text, 'text/xml');
361         var serializer = new XMLSerializer();
362         var error = $('parsererror', doc);
363
364         if (error.length != 0) {
365             return null;
366         }
367
368         $('sem[type="'+tag+'"]', doc).remove();
369         $root = $(doc.firstChild);
370         $.each(items, function(i, e) {
371             var $sem = $(doc.createElement("sem"));
372             $sem.attr('type', tag);
373             $sem.attr(tag, e[0]);
374             $div = $(doc.createElement("div"));
375             if (e[1]) {
376                 $div.attr('type', 'rect');
377                 $div.attr('x1', e[1]);
378                 $div.attr('y1', e[2]);
379                 $div.attr('x2', e[3]);
380                 $div.attr('y2', e[4]);
381             }
382             else {
383                 $div.attr('type', 'whole');
384             }
385             $sem.append($div);
386             $root.append($sem);
387         });
388         self.setText(serializer.serializeToString(doc));
389     }
390
391
392         $.wikiapi.WikiDocument = WikiDocument;
393 })(jQuery);
394
395
396
397 // Wykonuje block z załadowanymi kanonicznymi motywami
398 function withThemes(code_block, onError)
399 {
400     if (typeof withThemes.canon == 'undefined') {
401         $.ajax({
402             url: '/editor/themes',
403             dataType: 'text',
404             success: function(data) {
405                 withThemes.canon = data.split('\n');
406                 code_block(withThemes.canon);
407             },
408             error: function() {
409                 withThemes.canon = null;
410                 code_block(withThemes.canon);
411             }
412         })
413     }
414     else {
415         code_block(withThemes.canon);
416     }
417 }
418