editor: refactoring the way document properties are kept
[fnpeditor.git] / src / editor / modules / data / data.js
1 define([
2     'libs/jquery',
3     './dialog',
4     'wlxml/wlxml',
5     'wlxml/extensions/list/list',
6     'fnpjs/logging/logging',
7 ], function($, Dialog, wlxml, listExtension, logging) {
8
9 'use strict';
10 /* global gettext, alert, window */
11
12 var logger = logging.getLogger('editor.modules.data'),
13     stubDocument = '<section><div>' + gettext('This is an empty document.') + '</div></section>';
14
15
16 return function(sandbox) {
17
18     var document_id = sandbox.getBootstrappedData().document_id;
19     var history = sandbox.getBootstrappedData().history;
20     var documentDirty = false;
21     var draftDirty = false;
22
23     var documentProperties = {};
24     var data = sandbox.getBootstrappedData();
25     Object.keys(data)
26         .filter(function(key) {
27             return key !== 'history' && key !== 'document';
28         })
29         .forEach(function(key) {
30             documentProperties[key] = data[key];
31         });
32
33     var wlxmlDocument, text;
34
35     var loadDocument = function(text) {
36         logger.debug('loading document');
37         try {
38             wlxmlDocument = wlxml.WLXMLDocumentFromXML(text);
39         } catch(e) {
40             logger.exception(e);
41             alert(gettext('This document contains errors and can\'t be loaded. :(')); // TODO
42             wlxmlDocument = wlxml.WLXMLDocumentFromXML(stubDocument);
43         }
44
45         wlxmlDocument.registerExtension(listExtension);
46         sandbox.getPlugins().forEach(function(plugin) {
47             if(plugin.documentExtension) {
48                 wlxmlDocument.registerExtension(plugin.documentExtension);
49             }
50         });
51         
52         var modificationFlag = true;
53         var handleChange = function() {
54             documentDirty = true;
55             draftDirty = true;
56             modificationFlag = true;
57         };
58         wlxmlDocument.on('change', handleChange);
59         wlxmlDocument.on('contentSet', handleChange);
60
61         if(window.localStorage) {
62             window.setInterval(function() {
63                 if(modificationFlag) {
64                     modificationFlag = false;
65                     return;
66                 }
67                 if(wlxmlDocument && documentDirty && draftDirty) {
68                     logger.debug('Saving draft to local storage.');
69                     sandbox.publish('savingStarted', 'local');
70                     window.localStorage.setItem(getLocalStorageKey(), wlxmlDocument.toXML());
71                     sandbox.publish('savingEnded', 'success', 'local');
72                     draftDirty = false;
73                 }
74             }, sandbox.getConfig().autoSaveInterval || 2500);
75         }
76         sandbox.publish('ready');
77     };
78     
79     function readCookie(name) {
80         /* global escape, unescape, document */
81         var nameEQ = escape(name) + '=';
82         var ca = document.cookie.split(';');
83         for (var i = 0; i < ca.length; i++) {
84             var c = ca[i];
85             while (c.charAt(0) === ' ') {
86                 c = c.substring(1, c.length);
87             }
88             if (c.indexOf(nameEQ) === 0) {
89                 return unescape(c.substring(nameEQ.length, c.length));
90             }
91         }
92         return null;
93     }
94     
95     $.ajaxSetup({
96         crossDomain: false,
97         beforeSend: function(xhr, settings) {
98             if (!(/^(GET|HEAD|OPTIONS|TRACE)$/.test(settings.type))) {
99                 xhr.setRequestHeader('X-CSRFToken', readCookie('csrftoken'));
100             }
101         }
102     });
103     
104     var reloadHistory = function() {
105         $.ajax({
106             method: 'get',
107             url: sandbox.getConfig().documentHistoryUrl(document_id),
108             success: function(data) {
109                 history = data;
110                 sandbox.publish('historyItemAdded', data.slice(-1)[0]);
111             },
112         });
113     };
114
115     var getLocalStorageKey = function() {
116         return 'draft-id:' + document_id + '-ver:' + documentProperties.version;
117     };
118
119    
120     return {
121         start: function() {
122
123             if(window.localStorage) {
124                 text = window.localStorage.getItem(getLocalStorageKey());
125                 if(text) {
126                     logger.debug('Local draft exists');
127                     var dialog = Dialog.create({
128                         title: gettext('Local draft of a document exists'),
129                         text: gettext('Unsaved local draft of this version of the document exists in your browser. Do you want to load it instead?'),
130                         executeButtonText: gettext('Yes, restore local draft'),
131                         cancelButtonText: gettext('No, use version loaded from the server')
132                     });
133                     dialog.on('cancel', function() {
134                         logger.debug('Bootstrapped version chosen');
135                         text = sandbox.getBootstrappedData().document;
136                         
137                     });
138                     dialog.on('execute', function(event) {
139                         logger.debug('Local draft chosen');
140                         event.success();
141                     });
142                     dialog.show();
143                     dialog.on('close', function() {
144                         loadDocument(text);
145                     });
146                 } else {
147                     loadDocument(sandbox.getBootstrappedData().document);
148                 }
149             } else {
150                 loadDocument(sandbox.getBootstrappedData().document);
151             }
152         },
153         getDocument: function() {
154             return wlxmlDocument;
155         },
156         saveDocument: function() {
157             var documentSaveForm = $.extend({
158                         fields: [],
159                         content_field_name: 'text',
160                         version_field_name: 'version'
161                     },
162                     sandbox.getConfig().documentSaveForm
163                 ),
164                 dialog = Dialog.create({
165                     fields: documentSaveForm.fields,
166                     title: gettext('Save Document'),
167                     executeButtonText: gettext('Save')
168                 });
169             
170             dialog.on('execute', function(event) {
171                 sandbox.publish('savingStarted', 'remote');
172
173                 var formData = event.formData;
174                 formData[documentSaveForm.content_field_name] = wlxmlDocument.toXML();
175                 formData[documentSaveForm.version_field_name] = documentProperties.version;
176                 if(sandbox.getConfig().jsonifySentData) {
177                     formData = JSON.stringify(formData);
178                 }
179
180                 dialog.toggleButtons(false);
181                 $.ajax({
182                     method: 'post',
183                     url: sandbox.getConfig().documentSaveUrl(document_id),
184                     data: formData,
185                     success: function(data) {
186                         event.success();
187                         sandbox.publish('savingEnded', 'success', 'remote', data);
188
189                         Object.keys(data)
190                             .filter(function(key) {
191                                 return key !== 'text';
192                             })
193                             .forEach(function(key) {
194                                 documentProperties[key] = data[key];
195                             });
196
197                         reloadHistory();
198                     },
199                     error: function() {event.error(); sandbox.publish('savingEnded', 'error', 'remote');}
200                 });
201             });
202             dialog.on('cancel', function() {
203             });
204             dialog.show();
205             
206
207         },
208         getHistory: function() {
209             return history;
210         },
211         fetchDiff: function(ver1, ver2) {
212             $.ajax({
213                 method: 'get',
214                 url: sandbox.getConfig().documentDiffUrl(document_id),
215                 data: {from: ver1, to: ver2},
216                 success: function(data) {
217                     sandbox.publish('diffFetched', {table: data, ver1: ver1, ver2: ver2});
218                 },
219             });
220         },
221         restoreVersion: function(version) {
222             var documentRestoreForm = $.extend({
223                         fields: [],
224                         version_field_name: 'version'
225                     },
226                     sandbox.getConfig().documentRestoreForm
227                 ),
228                 dialog = Dialog.create({
229                     fields: documentRestoreForm.fields,
230                     title: gettext('Restore Version'),
231                     executeButtonText: gettext('Restore')
232                 });
233
234             dialog.on('execute', function(event) {
235                 var formData = event.formData;
236                 formData[documentRestoreForm.version_field_name] = version;
237                 sandbox.publish('restoringStarted', {version: version});
238                 if(sandbox.getConfig().jsonifySentData) {
239                     formData = JSON.stringify(formData);
240                 }
241                 $.ajax({
242                     method: 'post',
243                     dataType: 'json',
244                     url: sandbox.getConfig().documentRestoreUrl(document_id),
245                     data: formData,
246                     success: function(data) {
247                         Object.keys(data)
248                             .filter(function(key) {
249                                 return key !== 'document';
250                             })
251                             .forEach(function(key) {
252                                 documentProperties = data[key];
253                             });
254                         reloadHistory();
255                         wlxmlDocument.loadXML(data.document);
256                         documentDirty = false;
257                         sandbox.publish('documentReverted', data.version);
258                         event.success();
259                     },
260                 });
261             });
262             dialog.show();
263         },
264         dropDraft: function() {
265             logger.debug('Dropping a draft...');
266             wlxmlDocument.loadXML(sandbox.getBootstrappedData().document);
267             draftDirty = false;
268             logger.debug('Draft dropped');
269         },
270         getDocumentId: function() {
271             return document_id;
272         },
273         getDocumentProperties: function() {
274             return documentProperties;
275         }
276     };
277 };
278
279 });