editor: fix - block removing root node via insert/delete
[fnpeditor.git] / src / editor / modules / rng / rng.js
1 define([
2 'libs/underscore',
3 'fnpjs/layout',
4 'fnpjs/vbox',
5 'views/tabs/tabs',
6 'libs/text!./mainLayout.html',
7 'libs/text!./editingLayout.html',
8 'libs/text!./diffLayout.html',
9 ], function(_, layout, vbox, tabs, mainLayoutTemplate, visualEditingLayoutTemplate, diffLayoutTemplate) {
10
11 'use strict';
12
13 return function(sandbox) {
14
15     /* globals gettext */
16     
17     function addMainTab(title, slug, view) {
18         views.mainTabs.addTab(title, slug, view);
19     }
20      
21     var commands = {
22         highlightDocumentElement: function(element, origin) {
23             ///'nodeBreadCrumbs', 'nodeFamilyTree'
24             ['documentCanvas', 'nodeFamilyTree'].forEach(function(moduleName) {
25                 if(!origin || moduleName !== origin) {
26                     sandbox.getModule(moduleName).highlightElement(element);
27                 }
28             });
29         },
30         dimDocumentElement: function(element, origin) {
31             //'nodeBreadCrumbs', 'nodeFamilyTree'
32             ['documentCanvas', 'nodeFamilyTree'].forEach(function(moduleName) {
33                 if(!origin || moduleName !== origin) {
34                     sandbox.getModule(moduleName).dimElement(element);
35                 }
36             });
37         },
38         jumpToDocumentElement: function(element) {
39             sandbox.getModule('documentCanvas').jumpToElement(element);
40         },
41         updateCurrentNodeElement: function(nodeElement) {
42             sandbox.getModule('nodePane').setNodeElement(nodeElement);
43             sandbox.getModule('nodeFamilyTree').setElement(nodeElement);
44             sandbox.getModule('nodeBreadCrumbs').setNodeElement(nodeElement);
45             sandbox.getModule('documentToolbar').setNodeElement(nodeElement);
46             sandbox.getModule('metadataEditor').setNodeElement(nodeElement);
47         },
48         updateCurrentTextElement: function(textElement) {
49             sandbox.getModule('nodeFamilyTree').setElement(textElement);
50         }
51     };
52     
53
54     var views = {
55         mainLayout: new layout.Layout(mainLayoutTemplate),
56         mainTabs: (new tabs.View()).render(),
57         visualEditing: new layout.Layout(visualEditingLayoutTemplate),
58         visualEditingSidebar: (new tabs.View({stacked: true})).render(),
59         currentNodePaneLayout: new vbox.VBox(),
60         diffLayout: new layout.Layout(diffLayoutTemplate)
61     };
62     
63     views.visualEditing.setView('rightColumn', views.visualEditingSidebar.getAsView());
64     addMainTab(gettext('Editor'), 'editor', views.visualEditing.getAsView());
65     addMainTab(gettext('Source'), 'sourceEditor',  '');
66     addMainTab(gettext('History'), 'history', views.diffLayout.getAsView());
67     
68     sandbox.getDOM().append(views.mainLayout.getAsView());
69     
70     views.visualEditingSidebar.addTab({icon: 'pencil'}, 'edit', views.currentNodePaneLayout.getAsView());
71
72     var wlxmlDocument, documentIsDirty;
73     
74     /* Events handling */
75     
76     var eventHandlers = {};
77      
78     eventHandlers.sourceEditor = {
79         ready: function() {
80             addMainTab(gettext('Source'), 'sourceEditor',  sandbox.getModule('sourceEditor').getView());
81             sandbox.getModule('sourceEditor').setDocument(sandbox.getModule('data').getDocument());
82         }
83     };
84     
85     eventHandlers.data = {
86         ready: function() {
87             views.mainLayout.setView('mainView', views.mainTabs.getAsView());
88             
89             _.each(['sourceEditor', 'documentCanvas', 'documentToolbar', 'nodePane', 'metadataEditor', 'nodeFamilyTree', 'nodeBreadCrumbs', 'mainBar', 'indicator', 'documentHistory', 'diffViewer'], function(moduleName) {
90                 sandbox.getModule(moduleName).start();
91             });
92             
93             wlxmlDocument = sandbox.getModule('data').getDocument();
94             documentIsDirty = false;
95             wlxmlDocument.on('change', function() {
96                 documentIsDirty = true;
97             });
98             wlxmlDocument.on('contentSet', function() {
99                 documentIsDirty = true;
100             });
101         },
102         savingStarted: function() {
103             sandbox.getModule('mainBar').setCommandEnabled('save', false);
104             sandbox.getModule('indicator').showMessage(gettext('Saving...'));
105         },
106         savingEnded: function(status, current_version) {
107             void(status);
108             documentIsDirty = false;
109             sandbox.getModule('mainBar').setCommandEnabled('save', true);
110             sandbox.getModule('indicator').clearMessage({message:'Dokument zapisany'});
111             sandbox.getModule('mainBar').setVersion(current_version);
112         },
113         restoringStarted: function(event) {
114             sandbox.getModule('mainBar').setCommandEnabled('save', false);
115             sandbox.getModule('indicator').showMessage(gettext('Restoring version ') + event.version + '...');
116         },
117         historyItemAdded: function(item) {
118             sandbox.getModule('documentHistory').addHistory([item], {animate: true});
119         },
120         diffFetched: function(diff) {
121             sandbox.getModule('diffViewer').setDiff(diff);
122         },
123         documentReverted: function(version) {
124             documentIsDirty = false;
125             sandbox.getModule('mainBar').setCommandEnabled('save', true);
126             sandbox.getModule('indicator').clearMessage({message:'Wersja ' + version + ' przywrócona'});
127             sandbox.getModule('mainBar').setVersion(version);
128         }
129     };
130     
131     eventHandlers.mainBar = {
132         ready: function() {
133             sandbox.getModule('mainBar').setVersion(sandbox.getModule('data').getDocumentVersion());
134             views.mainLayout.setView('topPanel', sandbox.getModule('mainBar').getView());
135         },
136         'cmd.save': function() {
137             sandbox.getModule('data').saveDocument();
138         }
139     };
140     
141     eventHandlers.indicator = {
142         ready: function() {
143             views.mainLayout.setView('messages', sandbox.getModule('indicator').getView());
144         }
145     };
146     
147
148     
149     eventHandlers.documentCanvas = {
150         ready: function() {
151             sandbox.getModule('documentCanvas').setDocument(sandbox.getModule('data').getDocument());
152             views.visualEditing.setView('leftColumn', sandbox.getModule('documentCanvas').getView());
153         },
154         
155         currentTextElementSet: function(textElement) {
156             commands.updateCurrentTextElement(textElement);
157         },
158
159         currentNodeElementSet: function(nodeElement) {
160             commands.updateCurrentNodeElement(nodeElement);
161         },
162         
163         currentNodeElementChanged: function(nodeElement) {
164             commands.updateCurrentNodeElement(nodeElement);
165         },
166
167         nodeHovered: function(canvasNode) {
168             commands.highlightDocumentNode(canvasNode);
169         },
170         
171         nodeBlured: function(canvasNode) {
172             commands.dimDocumentNode(canvasNode);
173         }
174     };
175
176     eventHandlers.nodePane = {
177         ready: function() {
178             views.currentNodePaneLayout.appendView(sandbox.getModule('nodePane').getView());
179         },
180         
181         nodeElementChange: function(attr, value) {
182             sandbox.getModule('documentCanvas').modifyCurrentNodeElement(attr, value);
183         }
184     };
185     
186     eventHandlers.metadataEditor = {
187         ready: function() {
188             sandbox.getModule('metadataEditor').setDocument(sandbox.getModule('data').getDocument());
189             views.visualEditingSidebar.addTab({icon: 'info-sign'}, 'metadataEditor', sandbox.getModule('metadataEditor').getView());
190         }
191     };
192     
193     eventHandlers.nodeFamilyTree = {
194         ready: function() {
195             views.currentNodePaneLayout.appendView(sandbox.getModule('nodeFamilyTree').getView());
196         },
197         nodeEntered: function(node) {
198             commands.highlightDocumentElement(node, 'nodeFamilyTree');
199         },
200         nodeLeft: function(node) {
201             commands.dimDocumentElement(node, 'nodeFamilyTree');
202         },
203         nodeClicked: function(node) {
204             commands.jumpToDocumentElement(node);
205         }
206     };
207     
208     eventHandlers.documentToolbar = {
209         ready: function() {
210             views.visualEditing.setView('toolbar', sandbox.getModule('documentToolbar').getView());
211         },
212         command: function(cmd, params) {
213             sandbox.getModule('documentCanvas').command(cmd, params);
214         }
215     };
216     
217     eventHandlers.nodeBreadCrumbs = {
218         ready: function() {
219             views.visualEditing.setView('statusBar', sandbox.getModule('nodeBreadCrumbs').getView());
220         },
221         elementEntered: function(element) {
222             commands.highlightDocumentElement(element, 'nodeBreadCrumbs');
223         },
224         elementLeft: function(element) {
225             commands.dimDocumentElement(element, 'nodeBreadCrumbs');
226         },
227         elementClicked: function(element) {
228             commands.jumpToDocumentElement(element);
229         }
230     };
231     
232     eventHandlers.documentHistory = {
233         ready: function() {
234             sandbox.getModule('documentHistory').addHistory(sandbox.getModule('data').getHistory());
235             views.diffLayout.setView('left', sandbox.getModule('documentHistory').getView());
236         },
237         compare: function(ver1, ver2) {
238             sandbox.getModule('data').fetchDiff(ver1, ver2);
239         },
240         restoreVersion: function(version) {
241             sandbox.getModule('data').restoreVersion(version);
242         },
243         displayVersion: function(event) {
244             /* globals window */
245             window.open('/' + gettext('editor') + '/' + sandbox.getModule('data').getDocumentId() + '?version=' + event.version, _.uniqueId());
246         }
247     };
248     
249     eventHandlers.diffViewer = {
250         ready: function() {
251             views.diffLayout.setView('right', sandbox.getModule('diffViewer').getView());
252         }
253     };
254
255     window.addEventListener('beforeunload', function(event) {
256         var txt = gettext('Do you really want to exit?');
257         if(documentIsDirty) {
258             txt += ' ' + gettext('Document contains unsaved changes!');
259         }
260         event.returnValue = txt; // FF
261         return txt; // Chrome
262     });
263     
264     /* api */
265     
266     return {
267         start: function() {
268             sandbox.getModule('data').start();
269         },
270         handleEvent: function(moduleName, eventName, args) {
271             if(eventHandlers[moduleName] && eventHandlers[moduleName][eventName]) {
272                 eventHandlers[moduleName][eventName].apply(eventHandlers, args);
273             }
274         }
275     };
276 };
277
278 });