1 /*globals Editor fileId SplitView PanelContainerView EditorView FlashView messageCenter*/
2 Editor.Model = Editor.Object.extend({
8 Editor.ToolbarButtonsModel = Editor.Model.extend({
9 className: 'Editor.ToolbarButtonsModel',
17 if (!this.get('buttons').length) {
21 success: this.loadSucceeded.bind(this)
26 loadSucceeded: function(data) {
27 this.set('buttons', data);
34 // -> error -> loading
36 // empty -> loading -> synced -> unsynced -> loading
38 // -> dirty -> updating -> updated -> synced
40 Editor.XMLModel = Editor.Model.extend({
41 _className: 'Editor.XMLModel',
46 init: function(serverURL, revision) {
48 this.set('state', 'empty');
49 this.set('revision', revision);
50 this.serverURL = serverURL;
51 this.toolbarButtonsModel = new Editor.ToolbarButtonsModel();
52 this.addObserver(this, 'data', this.dataChanged.bind(this));
55 load: function(force) {
56 if (force || this.get('state') == 'empty') {
57 this.set('state', 'loading');
61 data: {revision: this.get('revision')},
62 success: this.loadingSucceeded.bind(this),
63 error: this.loadingFailed.bind(this)
70 loadingSucceeded: function(data) {
71 if (this.get('state') != 'loading') {
72 alert('erroneous state:', this.get('state'));
74 this.set('data', data);
75 this.set('state', 'synced');
78 loadingFailed: function() {
79 if (this.get('state') != 'loading') {
80 alert('erroneous state:', this.get('state'));
82 this.set('error', 'Nie udało się załadować panelu');
83 this.set('state', 'error');
86 update: function(message) {
87 if (this.get('state') == 'dirty') {
88 this.set('state', 'updating');
91 contents: this.get('data'),
92 revision: this.get('revision')
95 payload.message = message;
103 success: this.updatingSucceeded.bind(this),
104 error: this.updatingFailed.bind(this)
111 updatingSucceeded: function(data) {
112 if (this.get('state') != 'updating') {
113 alert('erroneous state:', this.get('state'));
115 this.set('revision', data.revision);
116 this.set('state', 'updated');
119 updatingFailed: function() {
120 if (this.get('state') != 'updating') {
121 alert('erroneous state:', this.get('state'));
123 messageCenter.addMessage('error', 'Uaktualnienie nie powiodło się', 'Uaktualnienie nie powiodło się');
124 this.set('state', 'dirty');
128 set: function(property, value) {
129 if (property == 'state') {
130 console.log(this.description(), ':', property, '=', value);
132 return this._super(property, value);
135 dataChanged: function(property, value) {
136 if (this.get('state') == 'synced') {
137 this.set('state', 'dirty');
141 dispose: function() {
142 this.removeObserver(this);
148 Editor.HTMLModel = Editor.Model.extend({
149 _className: 'Editor.HTMLModel',
157 init: function(htmlURL, revision, dataURL) {
159 this.set('state', 'empty');
160 this.set('revision', revision);
161 this.htmlURL = htmlURL;
162 this.dataURL = dataURL;
163 this.renderURL = "http://localhost:8000/api/render";
167 load: function(force) {
168 if (force || this.get('state') == 'empty') {
169 this.set('state', 'loading');
171 // load the transformed data
175 data: {revision: this.get('revision')},
176 success: this.loadingSucceeded.bind(this),
177 error: this.loadingFailed.bind(this)
182 loadingSucceeded: function(data) {
183 if (this.get('state') != 'loading') {
184 alert('erroneous state:', this.get('state'));
186 this.set('data', data);
187 this.set('state', 'synced');
190 loadingFailed: function() {
191 if (this.get('state') != 'loading') {
192 alert('erroneous state:', this.get('state'));
194 this.set('error', 'Nie udało się załadować panelu');
195 this.set('state', 'error');
198 getXMLPart: function(elem, callback)
200 var path = elem.attr('wl2o:path');
201 if(!this.xmlParts[path])
202 this.loadXMLPart(elem, callback);
204 callback(path, this.xmlParts[path]);
207 loadXMLPart: function(elem, callback)
209 var path = elem.attr('wl2o:path');
214 dataType: 'text; charset=utf-8',
216 revision: this.get('revision'),
219 success: function(data) {
220 self.xmlParts[path] = data;
221 callback(path, data);
223 // TODO: error handling
224 error: function(data) {
225 console.log('Failed to load fragment');
226 callback(undefined, undefined);
231 putXMLPart: function(elem, data) {
234 var path = elem.attr('wl2o:path');
235 this.xmlParts[path] = data;
237 this.set('state', 'unsynced');
239 /* re-render the changed fragment */
243 dataType: 'text; charset=utf-8',
244 data: {fragment: data, part: path},
245 success: function(htmldata) {
246 elem.replaceWith(htmldata);
247 self.set('state', 'dirty');
252 update: function(message) {
253 if (this.get('state') == 'dirty') {
254 this.set('state', 'updating');
257 chunks: $.toJSON(this.xmlParts),
258 revision: this.get('revision')
262 payload.message = message;
272 success: this.updatingSucceeded.bind(this),
273 error: this.updatingFailed.bind(this)
281 updatingSucceeded: function(data) {
282 if (this.get('state') != 'updating') {
283 alert('erroneous state:', this.get('state'));
289 this.set('revision', data.revision);
290 this.set('state', 'updated');
293 updatingFailed: function() {
294 if (this.get('state') != 'updating') {
295 alert('erroneous state:', this.get('state'));
297 messageCenter.addMessage('error', 'Uaktualnienie nie powiodło się', 'Uaktualnienie nie powiodło się');
298 this.set('state', 'dirty');
302 set: function(property, value) {
303 if (property == 'state') {
304 console.log(this.description(), ':', property, '=', value);
306 return this._super(property, value);
311 Editor.ImageGalleryModel = Editor.Model.extend({
312 _className: 'Editor.ImageGalleryModel',
317 init: function(serverURL) {
319 this.set('state', 'empty');
320 this.serverURL = serverURL;
325 load: function(force) {
326 if (force || this.get('state') == 'empty') {
327 this.set('state', 'loading');
331 success: this.loadingSucceeded.bind(this)
336 loadingSucceeded: function(data) {
337 if (this.get('state') != 'loading') {
338 alert('erroneous state:', this.get('state'));
341 console.log('galleries:', data);
343 if (data.length === 0) {
344 this.set('data', []);
347 this.set('data', data[0].pages);
350 this.set('state', 'synced');
353 set: function(property, value) {
354 if (property == 'state') {
355 console.log(this.description(), ':', property, '=', value);
357 return this._super(property, value);
362 Editor.DocumentModel = Editor.Model.extend({
363 _className: 'Editor.DocumentModel',
364 data: null, // name, text_url, user_revision, latest_shared_rev, parts_url, dc_url, size, merge_url
370 this.set('state', 'empty');
375 if (this.get('state') == 'empty') {
376 this.set('state', 'loading');
379 url: documentsUrl + fileId,
381 success: this.successfulLoad.bind(this)
386 successfulLoad: function(data) {
387 this.set('data', data);
388 this.set('state', 'synced');
389 this.contentModels = {
390 'xml': new Editor.XMLModel(data.text_url, data.user_revision),
391 'html': new Editor.HTMLModel(data.html_url, data.user_revision, data.text_url),
392 'gallery': new Editor.ImageGalleryModel(data.gallery_url)
394 for (var key in this.contentModels) {
395 this.contentModels[key].addObserver(this, 'state', this.contentModelStateChanged.bind(this));
399 contentModelStateChanged: function(property, value, contentModel) {
400 if (value == 'dirty') {
401 this.set('state', 'dirty');
402 for (var key in this.contentModels) {
403 if (this.contentModels[key].guid() != contentModel.guid()) {
404 this.contentModels[key].set('state', 'unsynced');
407 } else if (value == 'updated') {
408 this.set('state', 'synced');
409 for (key in this.contentModels) {
410 if (this.contentModels[key].guid() == contentModel.guid()) {
411 this.contentModels[key].set('state', 'synced');
412 this.data.user_revision = this.contentModels[key].get('revision');
413 messageCenter.addMessage('info', 'Uaktualnienie dokumentu do wersji ' + this.data.user_revision,
414 'Uaktualnienie dokumentu do wersji ' + this.data.user_revision);
417 for (key in this.contentModels) {
418 if (this.contentModels[key].guid() != contentModel.guid()) {
419 this.contentModels[key].set('revision', this.data.user_revision);
420 this.contentModels[key].set('state', 'empty');
426 saveDirtyContentModel: function(message) {
427 for (var key in this.contentModels) {
428 if (this.contentModels[key].get('state') == 'dirty') {
429 this.contentModels[key].update(message);
436 this.set('state', 'loading');
438 url: this.data.merge_url,
443 target_revision: this.data.user_revision
445 complete: this.updateCompleted.bind(this),
446 success: function(data) { this.set('updateData', data); }.bind(this)
450 updateCompleted: function(xhr, textStatus) {
451 console.log(xhr.status, textStatus);
452 if (xhr.status == 200) { // Sukces
453 this.data.user_revision = this.get('updateData').revision;
454 messageCenter.addMessage('info', 'Uaktualnienie dokumentu do wersji ' + this.get('updateData').revision,
455 'Uaktualnienie dokumentu do wersji ' + this.get('updateData').revision);
456 for (var key in this.contentModels) {
457 this.contentModels[key].set('revision', this.data.user_revision);
458 this.contentModels[key].set('state', 'empty');
460 } else if (xhr.status == 202) { // Wygenerowano PullRequest (tutaj?)
461 } else if (xhr.status == 204) { // Nic nie zmieniono
462 } else if (xhr.status == 409) { // Konflikt podczas operacji
464 this.set('state', 'synced');
465 this.set('updateData', null);
468 merge: function(message) {
469 this.set('state', 'loading');
471 url: this.data.merge_url,
476 target_revision: this.data.user_revision,
479 complete: this.mergeCompleted.bind(this),
480 success: function(data) { this.set('mergeData', data); }.bind(this)
484 mergeCompleted: function(xhr, textStatus) {
485 console.log(xhr.status, textStatus);
486 if (xhr.status == 200) { // Sukces
487 this.data.user_revision = this.get('mergeData').revision;
488 for (var key in this.contentModels) {
489 this.contentModels[key].set('revision', this.data.user_revision);
490 this.contentModels[key].set('state', 'empty');
492 messageCenter.addMessage('info', 'Uaktualnienie dokumentu do wersji ' + this.get('mergeData').revision,
493 'Uaktualnienie dokumentu do wersji ' + this.get('mergeData').revision);
494 } else if (xhr.status == 202) { // Wygenerowano PullRequest
495 } else if (xhr.status == 204) { // Nic nie zmieniono
496 } else if (xhr.status == 409) { // Konflikt podczas operacji
498 this.set('state', 'synced');
499 this.set('mergeData', null);
503 set: function(property, value) {
504 if (property == 'state') {
505 console.log(this.description(), ':', property, '=', value);
507 return this._super(property, value);
512 var leftPanelView, rightPanelContainer, doc;
516 documentsUrl = $('#api-base-url').text() + '/';
517 toolbarUrl = $('#api-toolbar-url').text();
519 doc = new Editor.DocumentModel();
520 var editor = new EditorView('#body-wrap', doc);
523 var flashView = new FlashView('#flashview', messageCenter);
524 var splitView = new SplitView('#splitview', doc);
526 leftPanelView = new PanelContainerView('#left-panel-container', doc);
527 rightPanelContainer = new PanelContainerView('#right-panel-container', doc);