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