opt-in presence record
[redakcja.git] / src / redakcja / static / js / wiki / 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 = "/editor";
19
20                 if (vname == "ajax_document_text") {
21                         var path = "/text/" + arguments[1] + '/';
22
23                 if (arguments[2] !== undefined)
24                                 path += arguments[2] + '/';
25
26                         return base_path + path;
27                 }
28
29         if (vname == "ajax_document_revert") {
30             return base_path + "/revert/" + arguments[1] + '/';
31         }
32
33
34                 if (vname == "ajax_document_history") {
35
36                         return base_path + "/history/" + arguments[1] + '/';
37                 }
38
39                 if (vname == "ajax_document_gallery") {
40
41                         return base_path + "/gallery/" + arguments[1] + '/';
42                 }
43
44                 if (vname == "ajax_document_diff")
45                         return base_path + "/diff/" + arguments[1] + '/';
46
47         if (vname == "ajax_document_rev")
48             return base_path + "/rev/" + arguments[1] + '/';
49
50                 if (vname == "ajax_document_pubmark")
51                         return base_path + "/pubmark/" + arguments[1] + '/';
52
53                 if (vname == "ajax_cover_preview")
54                         return "/cover/preview/";
55
56                 console.log("Couldn't reverse match:", vname);
57                 return "/404.html";
58         };
59
60         /*
61          * Document Abstraction
62          */
63         function WikiDocument(element_id) {
64                 var meta = $('#' + element_id);
65                 this.id = meta.attr('data-chunk-id');
66
67                 this.revision = $("*[data-key='revision']", meta).text();
68                 this.readonly = !!$("*[data-key='readonly']", meta).text();
69
70                 this.galleryLink = $("*[data-key='gallery']", meta).text();
71         this.galleryStart = parseInt($("*[data-key='gallery-start']", meta).text());
72             this.fullUri = $("*[data-key='full-uri']", meta).text();
73
74         var diff = $("*[data-key='diff']", meta).text();
75         if (diff) {
76             diff = diff.split(',');
77             if (diff.length == 2 && diff[0] < diff[1])
78                 this.diff = diff;
79             else if (diff.length == 1) {
80                 diff = parseInt(diff);
81                 if (diff != NaN)
82                     this.diff = [diff - 1, diff];
83             }
84         }
85
86                 this.galleryImages = [];
87                 this.text = null;
88                 this.has_local_changes = false;
89                 this.active = true;
90                 this._lock = -1;
91                 this._context_lock = -1;
92                 this._lock_count = 0;
93         };
94
95         WikiDocument.prototype.triggerDocumentChanged = function() {
96                 $(document).trigger('wlapi_document_changed', this);
97         };
98         /*
99          * Fetch text of this document.
100          */
101         WikiDocument.prototype.fetch = function(params) {
102                 params = $.extend({}, noops, params);
103                 var self = this;
104                 $.ajax({
105                         method: "GET",
106                         url: reverse("ajax_document_text", self.id),
107                         data: {"revision": self.revision},
108                         dataType: 'json',
109                         success: function(data) {
110                                 var changed = false;
111
112                                 if (self.text === null || self.revision !== data.revision) {
113                                         self.text = data.text;
114                                         self.revision = data.revision;
115                                         self.gallery = data.gallery;
116                                         changed = true;
117                                         self.triggerDocumentChanged();
118                                 };
119
120                                 self.has_local_changes = false;
121                                 params['success'](self, changed);
122                         },
123                         error: function() {
124                                 params['failure'](self, "Nie udało się wczytać treści dokumentu.");
125                         }
126                 });
127         };
128         /*
129          * Fetch history of this document.
130          *
131          * from - First revision to fetch (default = 0) upto - Last revision to
132          * fetch (default = tip)
133          *
134          */
135         WikiDocument.prototype.fetchHistory = function(params) {
136                 /* this doesn't modify anything, so no locks */
137                 params = $.extend({}, noops, params);
138                 var self = this;
139                 $.ajax({
140                         method: "GET",
141                         url: reverse("ajax_document_history", self.id),
142                         dataType: 'json',
143                         data: {
144                                 "from": params['from'],
145                                 "upto": params['upto']
146                         },
147                         success: function(data) {
148                                 params['success'](self, data);
149                         },
150                         error: function() {
151                                 params['failure'](self, "Nie udało się wczytać historii dokumentu.");
152                         }
153                 });
154         };
155         WikiDocument.prototype.fetchDiff = function(params) {
156                 /* this doesn't modify anything, so no locks */
157                 var self = this;
158                 params = $.extend({
159                         'from': self.revision,
160                         'to': self.revision
161                 }, noops, params);
162                 $.ajax({
163                         method: "GET",
164                         url: reverse("ajax_document_diff", self.id),
165                         dataType: 'html',
166                         data: {
167                                 "from": params['from'],
168                                 "to": params['to']
169                         },
170                         success: function(data) {
171                                 params['success'](self, data);
172                         },
173                         error: function() {
174                                 params['failure'](self, "Nie udało się wczytać porównania wersji.");
175                         }
176                 });
177         };
178
179     WikiDocument.prototype.checkRevision = function(params) {
180         /* this doesn't modify anything, so no locks */
181         var self = this;
182         let active = self.active;
183         self.active = false;
184         $.ajax({
185             method: "GET",
186             url: reverse("ajax_document_rev", self.id),
187             data: {
188                 'a': active,
189             },
190             dataType: 'text',
191             success: function(data) {
192                 if (data == '') {
193                     if (params.error)
194                         params.error();
195                 }
196                 else if (data != self.revision)
197                     params.outdated();
198             }
199         });
200     };
201
202         /*
203          * Fetch gallery
204          */
205         WikiDocument.prototype.refreshGallery = function(params) {
206                 params = $.extend({}, noops, params);
207                 var self = this;
208                 if (!self.galleryLink) {
209                         params['failure'](self, 'Brak galerii.');
210                         return;
211                 }
212                 $.ajax({
213                         method: "GET",
214                         url: reverse("ajax_document_gallery", self.galleryLink),
215                         dataType: 'json',
216                         // data: {},
217                         success: function(data) {
218                                 self.galleryImages = data;
219                                 params['success'](self, data);
220                         },
221                         error: function(xhr) {
222                 switch (xhr.status) {
223                     case 403:
224                         var msg = 'Galerie dostępne tylko dla zalogowanych użytkowników.';
225                         break;
226                     case 404:
227                         var msg = "Nie znaleziono galerii o nazwie: '" + self.galleryLink + "'.";
228                     default:
229                         var msg = "Nie udało się wczytać galerii o nazwie: '" + self.galleryLink + "'.";
230                 }
231                                 self.galleryImages = [];
232                                 params['failure'](self, msg);
233                         }
234                 });
235         };
236
237     /*
238      * Set document's text
239      */
240     WikiDocument.prototype.setText = function(text, setter) {
241         if (text == this.text) return;
242         
243         this.text = text;
244         this.has_local_changes = true;
245
246     };
247
248     
249         /*
250          * Save text back to the server
251          */
252         WikiDocument.prototype.save = function(params) {
253                 params = $.extend({}, noops, params);
254                 var self = this;
255
256                 if (!self.has_local_changes) {
257                         console.log("Abort: no changes.");
258                         return params['success'](self, false, "Nie ma zmian do zapisania.");
259                 };
260
261                 // Serialize form to dictionary
262                 var data = {};
263                 $.each(params['form'].serializeArray(), function() {
264                         data[this.name] = this.value;
265                 });
266
267                 data['textsave-text'] = self.text;
268
269                 $.ajax({
270                         url: reverse("ajax_document_text", self.id),
271                         type: "POST",
272                         dataType: "json",
273                         data: data,
274                         success: function(data) {
275                                 var changed = false;
276
277                 $('#header').removeClass('saving');
278
279                                 if (data.text) {
280                                         self.text = data.text;
281                                         self.revision = data.revision;
282                                         self.gallery = data.gallery;
283                                         changed = true;
284                                         self.triggerDocumentChanged();
285                                 };
286
287                                 params['success'](self, changed, ((changed && "Udało się zapisać :)") || "Twoja wersja i serwera jest identyczna"));
288                         },
289                         error: function(xhr) {
290                 if ($('#header').hasClass('saving')) {
291                     $('#header').removeClass('saving');
292                     $.blockUI({
293                         message: "<p>Nie udało się zapisać zmian. <br/><button onclick='$.unblockUI()'>OK</button></p>"
294                     })
295                 }
296                 else {
297                     try {
298                         params['failure'](self, $.parseJSON(xhr.responseText));
299                     }
300                     catch (e) {
301                         params['failure'](self, {
302                             "__message": "<p>Nie udało się zapisać - błąd serwera.</p>"
303                         });
304                     };
305                 }
306
307                         }
308                 });
309
310         $('#save-hide').click(function(){
311             $('#header').addClass('saving');
312             $.unblockUI();
313             $.wiki.blocking.unblock();
314         });
315         }; /* end of save() */
316
317     WikiDocument.prototype.revertToVersion = function(params) {
318         var self = this;
319         params = $.extend({}, noops, params);
320
321         if (params.revision >= this.revision) {
322             params.failure(self, 'Proszę wybrać rewizję starszą niż aktualna.');
323             return;
324         }
325
326         // Serialize form to dictionary
327         var data = {};
328         $.each(params['form'].serializeArray(), function() {
329             data[this.name] = this.value;
330         });
331
332         $.ajax({
333             url: reverse("ajax_document_revert", self.id),
334             type: "POST",
335             dataType: "json",
336             data: data,
337             success: function(data) {
338                 if (data.text) {
339                     self.text = data.text;
340                     self.revision = data.revision;
341                     self.gallery = data.gallery;
342                     self.triggerDocumentChanged();
343
344                     params.success(self, "Udało się przywrócić wersję :)");
345                 }
346                 else {
347                     params.failure(self, "Przywracana wersja identyczna z aktualną. Anulowano przywracanie.");
348                 }
349             },
350             error: function(xhr) {
351                 params.failure(self, "Nie udało się przywrócić wersji - błąd serwera.");
352             }
353         });
354     };
355
356         WikiDocument.prototype.pubmark = function(params) {
357                 params = $.extend({}, noops, params);
358                 var self = this;
359                 var data = {
360                         "pubmark-id": self.id,
361                 };
362
363                 /* unpack form */
364                 $.each(params.form.serializeArray(), function() {
365                         data[this.name] = this.value;
366                 });
367
368                 $.ajax({
369                         url: reverse("ajax_document_pubmark", self.id),
370                         type: "POST",
371                         dataType: "json",
372                         data: data,
373                         success: function(data) {
374                                 params.success(self, data.message);
375                         },
376                         error: function(xhr) {
377                                 if (xhr.status == 403 || xhr.status == 401) {
378                                         params.failure(self, {
379                                                 "__all__": ["Nie masz uprawnień lub nie jesteś zalogowany."]
380                                         });
381                                 }
382                                 else {
383                                         try {
384                                                 params.failure(self, $.parseJSON(xhr.responseText));
385                                         }
386                                         catch (e) {
387                                                 params.failure(self, {
388                                                         "__all__": ["Nie udało się - błąd serwera."]
389                                                 });
390                                         };
391                                 };
392                         }
393                 });
394         };
395
396         WikiDocument.prototype.refreshCover = function(params) {
397         var self = this;
398                 var data = {
399                         xml: self.text // TODO: send just DC
400                 };
401         $.ajax({
402             url: reverse("ajax_cover_preview"),
403             type: "POST",
404             data: data,
405             success: function(data) {
406                 params.success(data);
407             },
408             error: function(xhr) {
409                 // params.failure("Nie udało się odświeżyć okładki - błąd serwera.");
410             }
411         });
412         };
413
414
415     WikiDocument.prototype.getLength = function(params) {
416         params = $.extend({}, noops, params);
417         var xml = this.text.replace(/\/(\s+)/g, '<br />$1');
418         var parser = new DOMParser();
419         var doc = parser.parseFromString(xml, 'text/xml');
420         var error = $('parsererror', doc);
421
422         if (error.length > 0) {
423             throw "Not an XML document.";
424         }
425         $.xmlns["rdf"] = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; 
426         $('rdf|RDF', doc).remove();
427         if (params.noFootnotes) {
428             $('pa, pe, pr, pt', doc).remove();
429         }
430         if (params.noThemes) {
431             $('motyw', doc).remove();
432         }
433         var text = $(doc).text();
434         text = $.trim(text.replace(/\s{2,}/g, ' '));
435         return text.length;
436     }
437
438     /* Temporary workaround for relative images. */
439     WikiDocument.prototype.getBase = function() {
440         return '/media/dynamic/images/' + this.galleryLink + '/';
441     };
442
443         $.wikiapi.WikiDocument = WikiDocument;
444 })(jQuery);