The actual commit.
[redakcja.git] / project / static / js / models.js
1 /*globals Editor fileId SplitView PanelContainerView EditorView*/
2 var documentsUrl = '/api/documents/';
3
4
5 Editor.Model = Editor.Object.extend({
6   synced: false,
7   data: null
8 });
9
10
11 Editor.ToolbarButtonsModel = Editor.Model.extend({
12   _className: 'Editor.ToolbarButtonsModel',
13   serverURL: '/api/toolbar/buttons',
14   buttons: {},
15   
16   init: function() {
17     this._super();
18   },
19   
20   load: function() {
21     if (!this.get('buttons').length) {
22       $.ajax({
23         url: this.serverURL,
24         dataType: 'json',
25         success: this.loadSucceeded.bind(this)
26       });
27     }
28   },
29   
30   loadSucceeded: function(data) {
31     this.set('buttons', data);
32   }
33 });
34
35
36 // Stany modelu:
37 //
38 // empty -> loading -> synced -> unsynced -> loading
39 //                           \
40 //                            -> dirty -> updating -> updated -> synced
41 //
42 Editor.XMLModel = Editor.Model.extend({
43   _className: 'Editor.XMLModel',
44   serverURL: null,
45   data: '',
46   state: 'empty',
47   
48   init: function(serverURL) {
49     this._super();
50     this.set('state', 'empty');
51     this.serverURL = serverURL;
52     this.toolbarButtonsModel = new Editor.ToolbarButtonsModel();
53     this.addObserver(this, 'data', this.dataChanged.bind(this));
54   },
55   
56   load: function() {
57     if (this.get('state') == 'empty') {
58       this.set('state', 'loading');
59       $.ajax({
60         url: this.serverURL,
61         dataType: 'text',
62         success: this.loadingSucceeded.bind(this)
63       });
64       return true;
65     }
66     return false;
67   },
68   
69   update: function(message) {
70     if (this.get('state') == 'dirty') {
71       this.set('state', 'updating');
72       
73       var payload = {
74         contents: this.get('data')
75       };
76       if (message) {
77         payload.message = message;
78       }
79       
80       $.ajax({
81         url: this.serverURL,
82         type: 'put',
83         dataType: 'json',
84         data: payload,
85         success: this.updatingSucceeded.bind(this),
86         error: this.updatingFailed.bind(this)
87       });
88       return true;
89     }
90     return false;
91   },
92   
93   updatingSucceeded: function() {
94     if (this.get('state') != 'updating') {
95       alert('erroneous state:', this.get('state'));
96     }
97     this.set('state', 'updated');
98   },
99   
100   updatingFailed: function() {
101     if (this.get('state') != 'updating') {
102       alert('erroneous state:', this.get('state'));
103     }
104     this.set('state', 'dirty');
105   },
106   
107   set: function(property, value) {
108     if (property == 'state') {
109       console.log(this.description(), ':', property, '=', value);
110     }
111     return this._super(property, value);
112   },
113   
114   dataChanged: function(property, value) {
115     if (this.get('state') == 'synced') {
116       this.set('state', 'dirty');
117     }
118   },
119   
120   loadingSucceeded: function(data) {
121     if (this.get('state') != 'loading') {
122       alert('erroneous state:', this.get('state'));
123     }
124     this.set('data', data);
125     this.set('state', 'synced');
126   },
127   
128   dispose: function() {
129     this.removeObserver(this);
130     this._super();
131   }
132 });
133
134
135 Editor.HTMLModel = Editor.Model.extend({
136   _className: 'Editor.HTMLModel',
137   serverURL: null,
138   data: '',
139   state: 'empty',
140   
141   init: function(serverURL) {
142     this._super();
143     this.set('state', 'empty');
144     this.serverURL = serverURL;
145   },
146   
147   load: function() {
148     if (this.get('state') == 'empty') {
149       this.set('state', 'loading');
150       $.ajax({
151         url: this.serverURL,
152         dataType: 'text',
153         success: this.loadingSucceeded.bind(this)
154       });
155     }
156   },
157   
158   loadingSucceeded: function(data) {
159     if (this.get('state') != 'loading') {
160       alert('erroneous state:', this.get('state'));
161     }
162     this.set('data', data);
163     this.set('state', 'synced');
164   },
165   
166   set: function(property, value) {
167     if (property == 'state') {
168       console.log(this.description(), ':', property, '=', value);
169     }
170     return this._super(property, value);
171   }
172 });
173
174
175 Editor.ImageGalleryModel = Editor.Model.extend({
176   _className: 'Editor.ImageGalleryModel',
177   serverURL: null,  
178   state: 'empty',
179
180   init: function(serverURL) {
181     this._super();
182     this.set('state', 'empty');
183     this.serverURL = serverURL;
184     // olewać data    
185     this.pages = []
186   },
187
188   load: function() {
189     if (this.get('state') == 'empty') {
190       this.set('state', 'loading');
191       $.ajax({
192         url: this.serverURL,
193         dataType: 'json',
194         success: this.loadingSucceeded.bind(this)
195       });
196     }
197   },  
198
199   loadingSucceeded: function(data) {
200     if (this.get('state') != 'loading') {
201       alert('erroneous state:', this.get('state'));
202     }
203
204     this.set('pages', data.pages)      
205     this.set('state', 'synced');
206   },
207
208   set: function(property, value) {
209     if (property == 'state') {
210       console.log(this.description(), ':', property, '=', value);
211     }
212     return this._super(property, value);
213   }
214 });
215
216
217 Editor.DocumentModel = Editor.Model.extend({
218   _className: 'Editor.DocumentModel',
219   data: null, // name, text_url, latest_rev, latest_shared_rev, parts_url, dc_url, size
220   contentModels: {},
221   state: 'empty',
222   
223   init: function() {
224     this._super();
225     this.set('state', 'empty');
226     this.load();
227   },
228   
229   load: function() {
230     if (this.get('state') == 'empty') {
231       this.set('state', 'loading');
232       $.ajax({
233         cache: false,
234         url: documentsUrl + fileId,
235         dataType: 'json',
236         success: this.successfulLoad.bind(this)
237       });
238     }
239   },
240   
241   successfulLoad: function(data) {
242     this.set('data', data);
243     this.set('state', 'synced');
244     this.contentModels = {
245       'xml': new Editor.XMLModel(data.text_url),
246       'html': new Editor.HTMLModel(data.html_url),
247       'gallery': new Editor.ImageGalleryModel(data.gallery_url)
248     };
249     for (var key in this.contentModels) {
250       this.contentModels[key].addObserver(this, 'state', this.contentModelStateChanged.bind(this));
251     }
252   },
253   
254   contentModelStateChanged: function(property, value, contentModel) {
255     if (value == 'dirty') {
256       for (var key in this.contentModels) {
257         if (this.contentModels[key].guid() != contentModel.guid()) {
258           // console.log(this.contentModels[key].description(), 'frozen');
259           this.contentModels[key].set('state', 'unsynced');
260         }
261       }
262     }
263   },
264   
265   quickSave: function(message) {
266     for (var key in this.contentModels) {
267       if (this.contentModels[key].get('state') == 'dirty') {
268         this.contentModels[key].update(message);
269         break;
270       }
271     }
272   }
273 });
274
275
276 var leftPanelView, rightPanelContainer, doc;
277
278 $(function() {
279   doc = new Editor.DocumentModel();
280   var editor = new EditorView('#body-wrap', doc);
281   editor.freeze();
282   var splitView = new SplitView('#splitview', doc);
283   leftPanelView = new PanelContainerView('#left-panel-container', doc);
284   rightPanelContainer = new PanelContainerView('#right-panel-container', doc);
285 });