9542eac50374593f642123ac4ef2bf87c9d0a15e
[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.DocumentModel = Editor.Model.extend({
176   _className: 'Editor.DocumentModel',
177   data: null, // name, text_url, latest_rev, latest_shared_rev, parts_url, dc_url, size
178   contentModels: {},
179   state: 'empty',
180   
181   init: function() {
182     this._super();
183     this.set('state', 'empty');
184     this.load();
185   },
186   
187   load: function() {
188     if (this.get('state') == 'empty') {
189       this.set('state', 'loading');
190       $.ajax({
191         cache: false,
192         url: documentsUrl + fileId,
193         dataType: 'json',
194         success: this.successfulLoad.bind(this)
195       });
196     }
197   },
198   
199   successfulLoad: function(data) {
200     this.set('data', data);
201     this.set('state', 'synced');
202     this.contentModels = {
203       'xml': new Editor.XMLModel(data.text_url),
204       'html': new Editor.HTMLModel(data.html_url)
205     };
206     for (var key in this.contentModels) {
207       this.contentModels[key].addObserver(this, 'state', this.contentModelStateChanged.bind(this));
208     }
209   },
210   
211   contentModelStateChanged: function(property, value, contentModel) {
212     if (value == 'dirty') {
213       for (var key in this.contentModels) {
214         if (this.contentModels[key].guid() != contentModel.guid()) {
215           // console.log(this.contentModels[key].description(), 'frozen');
216           this.contentModels[key].set('state', 'unsynced');
217         }
218       }
219     }
220   },
221   
222   quickSave: function(message) {
223     for (var key in this.contentModels) {
224       if (this.contentModels[key].get('state') == 'dirty') {
225         this.contentModels[key].update(message);
226         break;
227       }
228     }
229   }
230 });
231
232
233 var leftPanelView, rightPanelContainer, doc;
234
235 $(function() {
236   doc = new Editor.DocumentModel();
237   var editor = new EditorView('#body-wrap', doc);
238   editor.freeze();
239   var splitView = new SplitView('#splitview', doc);
240   leftPanelView = new PanelContainerView('#left-panel-container', doc);
241   rightPanelContainer = new PanelContainerView('#right-panel-container', doc);
242 });