smartxml: allow for removing node data for a specified key
[fnpeditor.git] / src / editor / modules / rng / rng.js
1 define([
2 './documentSummary',
3 'libs/underscore',
4 'fnpjs/layout',
5 'fnpjs/vbox',
6 'fnpjs/logging/logging',
7 'views/tabs/tabs',
8 'libs/text!./mainLayout.html',
9 'libs/text!./editingLayout.html',
10 'libs/text!./diffLayout.html',
11 ], function(documentSummary, _, layout, vbox, logging, tabs, mainLayoutTemplate, visualEditingLayoutTemplate, diffLayoutTemplate) {
12
13 'use strict';
14
15 return function(sandbox) {
16
17     /* globals gettext */
18
19     var logger = logging.getLogger('editor.modules.rng');
20     
21     function addMainTab(title, slug, view) {
22         views.mainTabs.addTab(title, slug, view);
23     }
24      
25     var commands = {
26         highlightDocumentElement: function(element, origin) {
27             ///'nodeBreadCrumbs', 'nodeFamilyTree'
28             ['documentCanvas', 'nodeFamilyTree'].forEach(function(moduleName) {
29                 if(!origin || moduleName !== origin) {
30                     sandbox.getModule(moduleName).highlightElement(element);
31                 }
32             });
33         },
34         dimDocumentElement: function(element, origin) {
35             //'nodeBreadCrumbs', 'nodeFamilyTree'
36             ['documentCanvas', 'nodeFamilyTree'].forEach(function(moduleName) {
37                 if(!origin || moduleName !== origin) {
38                     sandbox.getModule(moduleName).dimElement(element);
39                 }
40             });
41         },
42         jumpToDocumentElement: function(element) {
43             sandbox.getModule('documentCanvas').jumpToElement(element);
44         },
45         refreshCanvasSelection: function(selection) {
46             var fragment = selection.toDocumentFragment(),
47                 elementParent;
48             
49             sandbox.getModule('documentToolbar').setDocumentFragment(fragment);
50             
51             if(fragment && fragment.node) {
52                 elementParent = fragment.node.getNearestElementNode();
53                 sandbox.getModule('nodePane').setNodeElement(elementParent);
54                 sandbox.getModule('nodeFamilyTree').setElement(fragment.node);
55                 sandbox.getModule('nodeBreadCrumbs').setNodeElement(elementParent);
56                 sandbox.getModule('metadataEditor').setNodeElement(elementParent);
57             } else {
58                 sandbox.getModule('nodePane').setNodeElement(null);
59                 sandbox.getModule('nodeFamilyTree').setElement(null);
60                 sandbox.getModule('nodeBreadCrumbs').setNodeElement(null);
61                 sandbox.getModule('metadataEditor').setNodeElement(null);
62             }
63         },
64     };
65     
66
67     var views = {
68         mainLayout: new layout.Layout(mainLayoutTemplate),
69         mainTabs: (new tabs.View()).render(),
70         visualEditing: new layout.Layout(visualEditingLayoutTemplate),
71         visualEditingSidebar: (new tabs.View({stacked: true})).render(),
72         currentNodePaneLayout: new vbox.VBox(),
73         diffLayout: new layout.Layout(diffLayoutTemplate)
74     };
75     
76     views.visualEditing.setView('rightColumn', views.visualEditingSidebar.getAsView());
77     addMainTab(gettext('Editor'), 'editor', views.visualEditing.getAsView());
78     addMainTab(gettext('Source'), 'sourceEditor',  '');
79     addMainTab(gettext('History'), 'history', views.diffLayout.getAsView());
80     
81     sandbox.getDOM().append(views.mainLayout.getAsView());
82     
83     views.visualEditingSidebar.addTab({icon: 'pencil'}, 'edit', views.currentNodePaneLayout.getAsView());
84
85     var wlxmlDocument, documentIsDirty;
86     
87     /* Events handling */
88     
89     var eventHandlers = {};
90      
91     eventHandlers.sourceEditor = {
92         ready: function() {
93             addMainTab(gettext('Source'), 'sourceEditor',  sandbox.getModule('sourceEditor').getView());
94             sandbox.getModule('sourceEditor').setDocument(sandbox.getModule('data').getDocument());
95         }
96     };
97     
98     eventHandlers.data = {
99         ready: function(usingDraft, draftTimestamp) {
100             wlxmlDocument = sandbox.getModule('data').getDocument();
101
102             views.mainLayout.setView('mainView', views.mainTabs.getAsView());
103             
104             documentSummary.init(sandbox.getConfig().documentSummaryView, wlxmlDocument);
105             documentSummary.render();
106             documentSummary.setDraftField(usingDraft ? (draftTimestamp || '???') : '-');
107             views.currentNodePaneLayout.appendView(documentSummary.dom);
108
109             sandbox.getModule('mainBar').setCommandEnabled('drop-draft', usingDraft);
110             sandbox.getModule('mainBar').setCommandEnabled('save', usingDraft);
111
112             _.each(['sourceEditor', 'documentCanvas', 'documentToolbar', 'metadataEditor', 'nodeBreadCrumbs', 'mainBar', 'indicator', 'documentHistory', 'diffViewer', 'statusBar'], function(moduleName) {
113                 sandbox.getModule(moduleName).start();
114             });
115             
116             documentIsDirty = false;
117             wlxmlDocument.on('change', function() {
118                 documentIsDirty = true;
119                 sandbox.getModule('mainBar').setCommandEnabled('save', true);
120             });
121             wlxmlDocument.on('contentSet', function() {
122                 documentIsDirty = true;
123             });
124         },
125         draftDropped: function() {
126             documentSummary.setDraftField('-');
127             sandbox.getModule('mainBar').setCommandEnabled('drop-draft', false);
128             sandbox.getModule('mainBar').setCommandEnabled('save', false);
129         },
130         savingStarted: function(what) {
131             var msg = {
132                 remote: gettext('Saving document'),
133                 local: gettext('Saving local copy')
134             };
135             sandbox.getModule('mainBar').setCommandEnabled('save', false);
136             sandbox.getModule('indicator').showMessage(msg[what] + '...');
137         },
138         savingEnded: function(status, what, data) {
139             void(status);
140             var msg = {
141                 remote: gettext('Document saved'),
142                 local: gettext('Local copy saved')
143             };
144             documentIsDirty = false;
145             
146             sandbox.getModule('indicator').clearMessage({message: msg[what]});
147             if(status === 'success' && what === 'remote') {
148                 documentSummary.setDraftField('-');
149                 sandbox.getModule('mainBar').setCommandEnabled('drop-draft', false);
150                 sandbox.getModule('mainBar').setCommandEnabled('save', false);
151             }
152             if(what === 'local') {
153                 documentSummary.setDraftField(data.timestamp);
154                 sandbox.getModule('mainBar').setCommandEnabled('drop-draft', true);
155                 sandbox.getModule('mainBar').setCommandEnabled('save', true);
156             }
157         },
158         restoringStarted: function(event) {
159             sandbox.getModule('mainBar').setCommandEnabled('save', false);
160             sandbox.getModule('indicator').showMessage(gettext('Restoring version ') + event.version + '...');
161         },
162         historyItemAdded: function(item) {
163             sandbox.getModule('documentHistory').addHistory([item], {animate: true});
164         },
165         diffFetched: function(diff) {
166             sandbox.getModule('diffViewer').setDiff(diff);
167         },
168         documentReverted: function(version) {
169             documentIsDirty = false;
170             sandbox.getModule('indicator').clearMessage({message:'Wersja ' + version + ' przywrócona'});
171         }
172     };
173     
174     eventHandlers.mainBar = {
175         ready: function() {
176             views.mainLayout.setView('topPanel', sandbox.getModule('mainBar').getView());
177         },
178         'cmd.save': function() {
179             var sourceEditor = sandbox.getModule('sourceEditor');
180             if(!sourceEditor.changesCommited()) {
181                 logger.debug('Source editor has uncommited changes, commiting...');
182                 sourceEditor.commitChanges();
183             }
184             sandbox.getModule('data').saveDocument();
185         },
186         'cmd.drop-draft': function() {
187             sandbox.getModule('data').dropDraft();
188         }
189     };
190     
191     eventHandlers.indicator = {
192         ready: function() {
193             views.mainLayout.setView('messages', sandbox.getModule('indicator').getView());
194         }
195     };
196     
197
198     
199     eventHandlers.documentCanvas = {
200         ready: function() {
201             sandbox.getModule('documentCanvas').setDocument(sandbox.getModule('data').getDocument());
202             views.visualEditing.setView('leftColumn', sandbox.getModule('documentCanvas').getView());
203         },
204         
205         nodeHovered: function(canvasNode) {
206             commands.highlightDocumentNode(canvasNode);
207         },
208         
209         nodeBlured: function(canvasNode) {
210             commands.dimDocumentNode(canvasNode);
211         },
212
213         selectionChanged: function(selection) {
214             commands.refreshCanvasSelection(selection);
215         }
216     };
217
218     eventHandlers.nodePane = {
219         ready: function() {
220             views.currentNodePaneLayout.appendView(sandbox.getModule('nodePane').getView());
221         }
222     };
223     
224     eventHandlers.metadataEditor = {
225         ready: function() {
226             sandbox.getModule('metadataEditor').setDocument(sandbox.getModule('data').getDocument());
227             views.visualEditingSidebar.addTab({icon: 'info-sign'}, 'metadataEditor', sandbox.getModule('metadataEditor').getView());
228         }
229     };
230     
231     eventHandlers.nodeFamilyTree = {
232         ready: function() {
233             views.currentNodePaneLayout.appendView(sandbox.getModule('nodeFamilyTree').getView());
234         },
235         nodeEntered: function(node) {
236             commands.highlightDocumentElement(node, 'nodeFamilyTree');
237         },
238         nodeLeft: function(node) {
239             commands.dimDocumentElement(node, 'nodeFamilyTree');
240         },
241         nodeClicked: function(node) {
242             commands.jumpToDocumentElement(node);
243         }
244     };
245     
246     eventHandlers.documentToolbar = {
247         ready: function() {
248             views.visualEditing.setView('toolbar', sandbox.getModule('documentToolbar').getView());
249             sandbox.getModule('documentToolbar').setCanvas(sandbox.getModule('documentCanvas').getCanvas());
250         },
251         actionExecuted: function(action, ret) {
252             sandbox.getModule('documentCanvas').onAfterActionExecuted(action, ret);
253         }
254     };
255     
256     eventHandlers.nodeBreadCrumbs = {
257         ready: function() {
258             views.visualEditing.setView('statusBar', sandbox.getModule('nodeBreadCrumbs').getView());
259         },
260         elementEntered: function(element) {
261             commands.highlightDocumentElement(element, 'nodeBreadCrumbs');
262         },
263         elementLeft: function(element) {
264             commands.dimDocumentElement(element, 'nodeBreadCrumbs');
265         },
266         elementClicked: function(element) {
267             commands.jumpToDocumentElement(element);
268         }
269     };
270     
271     eventHandlers.documentHistory = {
272         ready: function() {
273             sandbox.getModule('documentHistory').addHistory(sandbox.getModule('data').getHistory());
274             views.diffLayout.setView('left', sandbox.getModule('documentHistory').getView());
275         },
276         compare: function(ver1, ver2) {
277             sandbox.getModule('data').fetchDiff(ver1, ver2);
278         },
279         restoreVersion: function(version) {
280             sandbox.getModule('data').restoreVersion(version);
281         },
282         displayVersion: function(event) {
283             /* globals window */
284             window.open('/' + gettext('editor') + '/' + sandbox.getModule('data').getDocumentId() + '?version=' + event.version, _.uniqueId());
285         }
286     };
287     
288     eventHandlers.diffViewer = {
289         ready: function() {
290             views.diffLayout.setView('right', sandbox.getModule('diffViewer').getView());
291         }
292     };
293
294     eventHandlers.statusBar = {
295         ready: function() {
296             views.mainLayout.setView('bottomPanel', sandbox.getModule('statusBar').getView());
297         }
298     };
299
300     eventHandlers.__all__ = {
301         actionHovered: function(action) {
302             sandbox.getModule('statusBar').showAction(action);
303         },
304         actionOff: function() {
305             sandbox.getModule('statusBar').clearAction();
306         }
307     };
308
309     window.addEventListener('beforeunload', function(event) {
310         var txt = gettext('Do you really want to exit?');
311         if(documentIsDirty) {
312             txt += ' ' + gettext('Document contains unsaved changes!');
313         }
314         event.returnValue = txt; // FF
315         return txt; // Chrome
316     });
317     
318     /* api */
319     
320     return {
321         start: function() {
322             sandbox.registerActionsAppObject({
323                 getUser: function() {
324                     return sandbox.getConfig().user;
325                 }
326             });
327             sandbox.getModule('data').start();
328         },
329         handleEvent: function(moduleName, eventName, args) {
330             var eventRepr = moduleName + '.' + eventName;
331             if(eventHandlers[moduleName] && eventHandlers[moduleName][eventName]) {
332                 logger.debug('Handling event ' + eventRepr);
333                 eventHandlers[moduleName][eventName].apply(eventHandlers, args);
334                 return;
335             }
336
337             if(eventHandlers.__all__[eventName]) {
338                 logger.debug('Handling event ' + eventRepr);
339                 eventHandlers.__all__[eventName].apply(eventHandlers.__all__, args);
340                 return;
341             }
342
343             logger.warning('No event handler for ' + eventRepr);
344         }
345     };
346 };
347
348 });